Loading DESCRIPTION +4 −4 Original line number Diff line number Diff line Package: CLA Version: 0.95-0 Date: 2019-02-04 Date: 2019-03-13 Title: Critical Line Algorithm in Pure R Author: Yanhao Shi <syhelena@163.com>, Martin Maechler <maechler@stat.math.ethz.ch> Loading @@ -8,9 +8,9 @@ Maintainer: Martin Maechler <maechler@stat.math.ethz.ch> Depends: R (>= 3.2.0) Imports: stats, grDevices, graphics Suggests: fGarch, FRAPO, Matrix Description: Implements 'Markovitz' Critical Line Algorithm ('CLA') for classical mean-variance portfolio optimization. Care has been taken for correctness in light of previous buggy implementations. Description: Implements 'Markovitz' Critical Line Algorithm ('CLA') for classical mean-variance portfolio optimization, see Markovitz (1952) <doi:10.2307/2975974>. Care has been taken for correctness in light of previous buggy implementations. License: GPL (>= 3) | file LICENSE Encoding: UTF-8 URL: https://gitlab.math.ethz.ch/maechler/CLA/ TODO +8 −2 Original line number Diff line number Diff line ##-*- org -*--> Emacs .. [Tab] key + [Org] menu; C-c C-o to follow links * ASAP (no longer "Before release of package") * *Before* next CRAN release ** DONE OpenBLAS, ATLAS, etc: must fix file:tests/SP500-ex.R at least: use R=/usr/bin/R R-pkg-check CLA # Fedora's R pkg using OpenBLAS R=R-3.5.1_MS R-pkg-check CLA # (RMO using MKL) R=R-ATLAS R-pkg-check CLA # using ATLAS see files ./CLA_ATLAS.out ./CLA_MKL.out ./CLA_OpenBLAS.out * ASAP (but possibly later than CRAN release) ** TODO check arguments e.g., lB <= uB, sum upper Bounds >= 1 ** TODO References --> (mostly done) ** TODO References --> (mostly done): Make Master thesis web-available (from SfS ETHZ) ? *** DONE 1) References from the thesis, including the "buried" python-paper with *WRONG* algo *** TODO 2) Master thesis: I'd like the thesis to be on our web page ** TODO Improve plot() method, using hyperbolic interpolation see R/CLA.R man/plot.CLA.Rd Loading inst/NEWS.Rd +5 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ \title{News for \R Package \pkg{CLA}}% MM: look into ../svn-log-from.all \newcommand{\CRANpkg}{\href{https://CRAN.R-project.org/package=#1}{\pkg{#1}}} \section{Changes in version 0.95-0 (2019-02-04)}{ \section{Changes in version 0.95-0 (2019-03-13)}{ \subsection{New Features}{ \itemize{ \item \emph{Not} back-compatible \emph{changed} result: The very Loading @@ -13,6 +13,7 @@ with the litterature and other implementations. \item Added data set \code{muS.10ex} orginally from Markowitz and Todd. \item Added \file{NEWS} file. } } Loading @@ -28,6 +29,9 @@ \item adapt \file{man/findSig.Rd} example to R 3.6.0's new default \code{sample()} kind. \item Run the \file{tests/*.R} with R versions that use one OpenBLAS, ATLAS, or MKL (and skip some tests on these). } } } Loading man/CLA.Rd +5 −1 Original line number Diff line number Diff line Loading @@ -77,7 +77,7 @@ CLA(mu, covar, lB, uB, tol.lambda = 1e-07, %% \doi{10.1007/BF02282055}. Niedermayer, A. and Niedermayer, D. (2010) Applying markowitz’s critical line algorithm, in J. B. Guerard (ed.), Applying Markowitz’s Critical Line Algorithm, in J. B. Guerard (ed.), Handbook of Portfolio Construction, Springer; chapter 12, 383--400; \doi{10.1007/978-0-387-77439-8_12}. Loading @@ -85,6 +85,10 @@ CLA(mu, covar, lB, uB, tol.lambda = 1e-07, An open-source implementation of the critical-line algorithm for portfolio optimization, \emph{Algorithms} \bold{6}(1), 169--196; \doi{10.3390/a6010169}, Yanhao Shi (2017) Implementation and applications of critical line algorithm for portfolio optimization; unpublished Master's thesis, ETH Zurich. } %% \note{ %% } Loading tests/SP500-ex.R +58 −18 Original line number Diff line number Diff line Loading @@ -10,9 +10,41 @@ b64nLD <- (arch == "x86_64" && .M$sizeof.longdouble != 16) if(b64nLD) arch <- paste0(arch, "--no-long-double") arch ## I'd want ## strict <- we_are_using_Rs_own_BLAS_and_Lapack() # but simply for now (strict <- Sys.info()[["user"]] == "maechler")# actually ## <---> sync with ~/R/Pkgs/robustbase/tests/mc-strict.R ## ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ sInfo <- sessionInfo() if(!exists("osVersion")) osVersion <- sInfo$running cat("osVersion:", osVersion, "\n") if(!is.null(osVersion)) "Fedora" # last resort BLAS.is.LAPACK <- sInfo$BLAS == sInfo$LAPACK cat("osVersion:", osVersion, "| ", 'BLAS "is" Lapack:', BLAS.is.LAPACK, "\n") ## Find out if we are running Micrsoft R Open is.MS.Ropen <- { file.exists(Rpr <- file.path(R.home("etc"), "Rprofile.site")) && length(lnsRpr <- readLines(Rpr)) && ## length(grep("[Mm]icrosoft", lnsRpr)) > 3 # MRO 3.5.1 has '20' times "[Mm]icrosoft" length(grep("Microsoft R Open", lnsRpr, fixed=TRUE, value=TRUE)) > 0 ## MRO 3.5.1 has it twice } if(is.MS.Ropen) cat("We are running 'Microsoft R Open'\n") ## I'd really want ## ## strict <- we_are_using_Rs_own_BLAS_and_Lapack() [ ==> BLAS != Lapack ] ## ## Actually the following is currently (2019-03) equivalent to ## strict <- !(using ATLAS || OpenBLAS || MKL ) if(TRUE) { strict <- !BLAS.is.LAPACK && !is.MS.Ropen } else { ## workaround: strict <- print(Sys.info()[["user"]]) == "maechler"# actually ## but not when testing with /usr/bin/R [OpenBLAS!] (as "maechler"): if(strict && substr(osVersion, 1,6) == "Fedora" && R.home() == "/usr/lib64/R") strict <- FALSE } cat("strict:", strict, "\n") data(muS.sp500) Loading @@ -27,7 +59,7 @@ system.time(# ~ 9 sec (64-bit); 13.8 sec (32-b florence); seen 27.44 sec on Winb ) CLs5c.0.120 # -> print() method un.call <- function(x) { x$call <- NULL ; x } uncall <- function(x) `$<-`(x, call, NULL) doExtras <- TRUE # for experiments, not normally doExtras <- FALSE Loading @@ -40,14 +72,14 @@ if(doExtras) system.time({ }) # 78.101 elapsed [nb-mm4] ; 46.108 [lynne 2018-10] if(doExtras) { identical(un.call(CLs5c.ls[["10^-7"]]), un.call(CLs5c.0.120)) identical(uncall(CLs5c.ls[["10^-7"]]), uncall(CLs5c.0.120)) for(i in seq_along(tols)[-1]) { cat("--=--=--=--=--\n", (n1 <- names(tols[i-1])), " vs. ", (n2 <- names(tols[i])), ": ") ae <- all.equal(un.call(CLs5c.ls[[i-1]]), un.call(CLs5c.ls[[ i ]])) ae <- all.equal(uncall(CLs5c.ls[[i-1]]), uncall(CLs5c.ls[[ i ]])) if(isTRUE(ae)) cat(" are all.equal()\n") else { CLA.i. <- un.call(CLs5c.ls[[i-1]]) ; wgt <- CLA.i.$weights_set CLA.i. <- uncall(CLs5c.ls[[i-1]]) ; wgt <- CLA.i.$weights_set cat("are different [all.equal()]: dim(..[[",n1,"]]$weights_set) =", dim(wgt)[1],"x", dim(wgt)[2],"\n") } Loading Loading @@ -82,23 +114,26 @@ if(require(Matrix)) withAutoprint(local = FALSE, { } options(op) stopifnot(nrow(wts.non0) == 79) if(FALSE) # once, manually (into tests/ directory saveRDS(wts.non0, "wtsn0.rds") file.info("wtsn0.rds")$size # 2702049 wtsn0.ref <- readRDS("wtsn0.rds") ## see on all platforms what we get ## see on all platforms what we get -- on OpenBLAS, the dim() differs ! all.equal(target = wtsn0.ref, current = wts.non0, tol=0) # expect TRUE only on 64bit (Lnx, R's BLAS) # 3.10416e-15 and 1.366427e-15 on other BLAS differWts <- ncol(wtsn0.ref) != ncol(wts.non0) if(differWts) { cat("Got",ncol(wts.non0), "weights from CLA() -- different than ref with", ncol(wtsn0.ref), "\n") strict <- FALSE # ! } else { stopifnot(all.equal(target = wtsn0.ref, current = wts.non0, tol = 1e-13)) } non.0.assets <- Filter(function(.) . > 0, apply(wts.non0, 1, function(c) sum(c > 0))) b64.n0 <- c(AAPL = 135L, ADSK = 66L, AET = 147L, AMGN = 3L, ATI = 75L, AYE = 56L, AZO = 26L, BAX = 95L, BCR = 35L, BDX = 36L, BIIB = 118L, Loading Loading @@ -177,18 +212,19 @@ if(all(non.0.assets == non.0.TARG)) { ## show differences: } ## They have the same names and only differ by +/- 1: stopifnot( stopifnot(exprs = { identical(names(b64.n0), names(b32.n0)) , if(b64) !strict || identical(non.0.assets, non.0.TARG) # fails on ATLAS, MKL, OpenBLAS if(b64) !strict || identical(non.0.assets, non.0.TARG) # identical(*) fails on ATLAS, MKL, OpenBLAS else if(nonWindows) identical(non.0.assets, b32.n0) else ## 32-bit Windows TRUE ## for now , identical(head(CLs5c.0.120$free_indices, 12), differWts || identical(head(CLs5c.0.120$free_indices, 12), list(c(295L, 453L), 453L, c(453L, 472L), c(19L, 453L, 472L), c(19L, 453L), 453L, c(15L, 453L), 15L, c(15L, 320L), c(15L, 105L, 320L), c(105L, 320L), c(105L, 320L, 472L))) ) }) ## Check some of the 'Env<n>' versions: --------- Loading Loading @@ -219,12 +255,16 @@ if(is.environment(e8 <- nsCLA$Env8)) local(withAutoprint({ system.time(r8 <- e8$cla.solve(muS.sp500$mu, muS.sp500$covar, lB = rep(0,n), uB= rep(1/20, n))) ## lynne (2017): 9.6--9.8 sec; 2018: 6.1 sec if(ncol(claDrop1st(r8)$weights_set) == ncol(rCLA$weights_set)) stopifnot(all.equal(claDrop1st(r8), rCLA, tol = 1e-14)) # they are the same! else cat("#{columns} differ in r8\n") })) if(is.environment(e9 <- nsCLA$Env9)) local(withAutoprint({ system.time(r9 <- e9$cla.solve(muS.sp500$mu, muS.sp500$covar, lB = rep(0,n), uB= rep(1/20, n))) ## lynne(2017): 10.0 sec; 2018: 6.6 sec if(ncol(claDrop1st(r9)$weights_set) == ncol(rCLA$weights_set)) stopifnot(all.equal(claDrop1st(r9), rCLA, tol = 1e-14)) # they are the same! else cat("#{columns} differ in r9\n") })) Loading
DESCRIPTION +4 −4 Original line number Diff line number Diff line Package: CLA Version: 0.95-0 Date: 2019-02-04 Date: 2019-03-13 Title: Critical Line Algorithm in Pure R Author: Yanhao Shi <syhelena@163.com>, Martin Maechler <maechler@stat.math.ethz.ch> Loading @@ -8,9 +8,9 @@ Maintainer: Martin Maechler <maechler@stat.math.ethz.ch> Depends: R (>= 3.2.0) Imports: stats, grDevices, graphics Suggests: fGarch, FRAPO, Matrix Description: Implements 'Markovitz' Critical Line Algorithm ('CLA') for classical mean-variance portfolio optimization. Care has been taken for correctness in light of previous buggy implementations. Description: Implements 'Markovitz' Critical Line Algorithm ('CLA') for classical mean-variance portfolio optimization, see Markovitz (1952) <doi:10.2307/2975974>. Care has been taken for correctness in light of previous buggy implementations. License: GPL (>= 3) | file LICENSE Encoding: UTF-8 URL: https://gitlab.math.ethz.ch/maechler/CLA/
TODO +8 −2 Original line number Diff line number Diff line ##-*- org -*--> Emacs .. [Tab] key + [Org] menu; C-c C-o to follow links * ASAP (no longer "Before release of package") * *Before* next CRAN release ** DONE OpenBLAS, ATLAS, etc: must fix file:tests/SP500-ex.R at least: use R=/usr/bin/R R-pkg-check CLA # Fedora's R pkg using OpenBLAS R=R-3.5.1_MS R-pkg-check CLA # (RMO using MKL) R=R-ATLAS R-pkg-check CLA # using ATLAS see files ./CLA_ATLAS.out ./CLA_MKL.out ./CLA_OpenBLAS.out * ASAP (but possibly later than CRAN release) ** TODO check arguments e.g., lB <= uB, sum upper Bounds >= 1 ** TODO References --> (mostly done) ** TODO References --> (mostly done): Make Master thesis web-available (from SfS ETHZ) ? *** DONE 1) References from the thesis, including the "buried" python-paper with *WRONG* algo *** TODO 2) Master thesis: I'd like the thesis to be on our web page ** TODO Improve plot() method, using hyperbolic interpolation see R/CLA.R man/plot.CLA.Rd Loading
inst/NEWS.Rd +5 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ \title{News for \R Package \pkg{CLA}}% MM: look into ../svn-log-from.all \newcommand{\CRANpkg}{\href{https://CRAN.R-project.org/package=#1}{\pkg{#1}}} \section{Changes in version 0.95-0 (2019-02-04)}{ \section{Changes in version 0.95-0 (2019-03-13)}{ \subsection{New Features}{ \itemize{ \item \emph{Not} back-compatible \emph{changed} result: The very Loading @@ -13,6 +13,7 @@ with the litterature and other implementations. \item Added data set \code{muS.10ex} orginally from Markowitz and Todd. \item Added \file{NEWS} file. } } Loading @@ -28,6 +29,9 @@ \item adapt \file{man/findSig.Rd} example to R 3.6.0's new default \code{sample()} kind. \item Run the \file{tests/*.R} with R versions that use one OpenBLAS, ATLAS, or MKL (and skip some tests on these). } } } Loading
man/CLA.Rd +5 −1 Original line number Diff line number Diff line Loading @@ -77,7 +77,7 @@ CLA(mu, covar, lB, uB, tol.lambda = 1e-07, %% \doi{10.1007/BF02282055}. Niedermayer, A. and Niedermayer, D. (2010) Applying markowitz’s critical line algorithm, in J. B. Guerard (ed.), Applying Markowitz’s Critical Line Algorithm, in J. B. Guerard (ed.), Handbook of Portfolio Construction, Springer; chapter 12, 383--400; \doi{10.1007/978-0-387-77439-8_12}. Loading @@ -85,6 +85,10 @@ CLA(mu, covar, lB, uB, tol.lambda = 1e-07, An open-source implementation of the critical-line algorithm for portfolio optimization, \emph{Algorithms} \bold{6}(1), 169--196; \doi{10.3390/a6010169}, Yanhao Shi (2017) Implementation and applications of critical line algorithm for portfolio optimization; unpublished Master's thesis, ETH Zurich. } %% \note{ %% } Loading
tests/SP500-ex.R +58 −18 Original line number Diff line number Diff line Loading @@ -10,9 +10,41 @@ b64nLD <- (arch == "x86_64" && .M$sizeof.longdouble != 16) if(b64nLD) arch <- paste0(arch, "--no-long-double") arch ## I'd want ## strict <- we_are_using_Rs_own_BLAS_and_Lapack() # but simply for now (strict <- Sys.info()[["user"]] == "maechler")# actually ## <---> sync with ~/R/Pkgs/robustbase/tests/mc-strict.R ## ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ sInfo <- sessionInfo() if(!exists("osVersion")) osVersion <- sInfo$running cat("osVersion:", osVersion, "\n") if(!is.null(osVersion)) "Fedora" # last resort BLAS.is.LAPACK <- sInfo$BLAS == sInfo$LAPACK cat("osVersion:", osVersion, "| ", 'BLAS "is" Lapack:', BLAS.is.LAPACK, "\n") ## Find out if we are running Micrsoft R Open is.MS.Ropen <- { file.exists(Rpr <- file.path(R.home("etc"), "Rprofile.site")) && length(lnsRpr <- readLines(Rpr)) && ## length(grep("[Mm]icrosoft", lnsRpr)) > 3 # MRO 3.5.1 has '20' times "[Mm]icrosoft" length(grep("Microsoft R Open", lnsRpr, fixed=TRUE, value=TRUE)) > 0 ## MRO 3.5.1 has it twice } if(is.MS.Ropen) cat("We are running 'Microsoft R Open'\n") ## I'd really want ## ## strict <- we_are_using_Rs_own_BLAS_and_Lapack() [ ==> BLAS != Lapack ] ## ## Actually the following is currently (2019-03) equivalent to ## strict <- !(using ATLAS || OpenBLAS || MKL ) if(TRUE) { strict <- !BLAS.is.LAPACK && !is.MS.Ropen } else { ## workaround: strict <- print(Sys.info()[["user"]]) == "maechler"# actually ## but not when testing with /usr/bin/R [OpenBLAS!] (as "maechler"): if(strict && substr(osVersion, 1,6) == "Fedora" && R.home() == "/usr/lib64/R") strict <- FALSE } cat("strict:", strict, "\n") data(muS.sp500) Loading @@ -27,7 +59,7 @@ system.time(# ~ 9 sec (64-bit); 13.8 sec (32-b florence); seen 27.44 sec on Winb ) CLs5c.0.120 # -> print() method un.call <- function(x) { x$call <- NULL ; x } uncall <- function(x) `$<-`(x, call, NULL) doExtras <- TRUE # for experiments, not normally doExtras <- FALSE Loading @@ -40,14 +72,14 @@ if(doExtras) system.time({ }) # 78.101 elapsed [nb-mm4] ; 46.108 [lynne 2018-10] if(doExtras) { identical(un.call(CLs5c.ls[["10^-7"]]), un.call(CLs5c.0.120)) identical(uncall(CLs5c.ls[["10^-7"]]), uncall(CLs5c.0.120)) for(i in seq_along(tols)[-1]) { cat("--=--=--=--=--\n", (n1 <- names(tols[i-1])), " vs. ", (n2 <- names(tols[i])), ": ") ae <- all.equal(un.call(CLs5c.ls[[i-1]]), un.call(CLs5c.ls[[ i ]])) ae <- all.equal(uncall(CLs5c.ls[[i-1]]), uncall(CLs5c.ls[[ i ]])) if(isTRUE(ae)) cat(" are all.equal()\n") else { CLA.i. <- un.call(CLs5c.ls[[i-1]]) ; wgt <- CLA.i.$weights_set CLA.i. <- uncall(CLs5c.ls[[i-1]]) ; wgt <- CLA.i.$weights_set cat("are different [all.equal()]: dim(..[[",n1,"]]$weights_set) =", dim(wgt)[1],"x", dim(wgt)[2],"\n") } Loading Loading @@ -82,23 +114,26 @@ if(require(Matrix)) withAutoprint(local = FALSE, { } options(op) stopifnot(nrow(wts.non0) == 79) if(FALSE) # once, manually (into tests/ directory saveRDS(wts.non0, "wtsn0.rds") file.info("wtsn0.rds")$size # 2702049 wtsn0.ref <- readRDS("wtsn0.rds") ## see on all platforms what we get ## see on all platforms what we get -- on OpenBLAS, the dim() differs ! all.equal(target = wtsn0.ref, current = wts.non0, tol=0) # expect TRUE only on 64bit (Lnx, R's BLAS) # 3.10416e-15 and 1.366427e-15 on other BLAS differWts <- ncol(wtsn0.ref) != ncol(wts.non0) if(differWts) { cat("Got",ncol(wts.non0), "weights from CLA() -- different than ref with", ncol(wtsn0.ref), "\n") strict <- FALSE # ! } else { stopifnot(all.equal(target = wtsn0.ref, current = wts.non0, tol = 1e-13)) } non.0.assets <- Filter(function(.) . > 0, apply(wts.non0, 1, function(c) sum(c > 0))) b64.n0 <- c(AAPL = 135L, ADSK = 66L, AET = 147L, AMGN = 3L, ATI = 75L, AYE = 56L, AZO = 26L, BAX = 95L, BCR = 35L, BDX = 36L, BIIB = 118L, Loading Loading @@ -177,18 +212,19 @@ if(all(non.0.assets == non.0.TARG)) { ## show differences: } ## They have the same names and only differ by +/- 1: stopifnot( stopifnot(exprs = { identical(names(b64.n0), names(b32.n0)) , if(b64) !strict || identical(non.0.assets, non.0.TARG) # fails on ATLAS, MKL, OpenBLAS if(b64) !strict || identical(non.0.assets, non.0.TARG) # identical(*) fails on ATLAS, MKL, OpenBLAS else if(nonWindows) identical(non.0.assets, b32.n0) else ## 32-bit Windows TRUE ## for now , identical(head(CLs5c.0.120$free_indices, 12), differWts || identical(head(CLs5c.0.120$free_indices, 12), list(c(295L, 453L), 453L, c(453L, 472L), c(19L, 453L, 472L), c(19L, 453L), 453L, c(15L, 453L), 15L, c(15L, 320L), c(15L, 105L, 320L), c(105L, 320L), c(105L, 320L, 472L))) ) }) ## Check some of the 'Env<n>' versions: --------- Loading Loading @@ -219,12 +255,16 @@ if(is.environment(e8 <- nsCLA$Env8)) local(withAutoprint({ system.time(r8 <- e8$cla.solve(muS.sp500$mu, muS.sp500$covar, lB = rep(0,n), uB= rep(1/20, n))) ## lynne (2017): 9.6--9.8 sec; 2018: 6.1 sec if(ncol(claDrop1st(r8)$weights_set) == ncol(rCLA$weights_set)) stopifnot(all.equal(claDrop1st(r8), rCLA, tol = 1e-14)) # they are the same! else cat("#{columns} differ in r8\n") })) if(is.environment(e9 <- nsCLA$Env9)) local(withAutoprint({ system.time(r9 <- e9$cla.solve(muS.sp500$mu, muS.sp500$covar, lB = rep(0,n), uB= rep(1/20, n))) ## lynne(2017): 10.0 sec; 2018: 6.6 sec if(ncol(claDrop1st(r9)$weights_set) == ncol(rCLA$weights_set)) stopifnot(all.equal(claDrop1st(r9), rCLA, tol = 1e-14)) # they are the same! else cat("#{columns} differ in r9\n") }))