Skip to content

Commit

Permalink
Merge pull request #35 from osqp/release_0.6.3
Browse files Browse the repository at this point in the history
Release 0.6.3
  • Loading branch information
bnaras authored Oct 3, 2023
2 parents 0936ebc + 18b0dbe commit b5fdc02
Show file tree
Hide file tree
Showing 18 changed files with 195 additions and 130 deletions.
7 changes: 7 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,10 @@ libosqp.a
^cran-comments\.md$
^CRAN-RELEASE$
^\.github$
.github
src/osqp_sources/CITATION.cff
src/osqp_sources/docs
src/osqp_sources/site
src/osqp_sources/tests
src/osqp_sources/lin_sys/direct/qdldl/qdldl_sources/tests

46 changes: 0 additions & 46 deletions .travis.yml

This file was deleted.

12 changes: 7 additions & 5 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: osqp
Title: Quadratic Programming Solver using the 'OSQP' Library
Version: 0.6.0.8
Date: 2023-01-30
Version: 0.6.3
Date: 2023-10-02
Authors@R: c(
person("Bartolomeo", "Stellato", role = c("aut", "ctb", "cph"),
email = "[email protected]"),
Expand All @@ -16,11 +16,13 @@ Copyright: file COPYRIGHT
Description: Provides bindings to the 'OSQP' solver. The 'OSQP' solver is a numerical optimization package or solving convex quadratic programs written in 'C' and based on the alternating direction method of multipliers. See <arXiv:1711.08013> for details.
License: Apache License 2.0 | file LICENSE
SystemRequirements: C++17
Imports: Rcpp (>= 0.12.14), methods, Matrix, R6
Imports: Rcpp (>= 0.12.14), methods, Matrix (>= 1.6.1), R6
LinkingTo: Rcpp
RoxygenNote: 7.2.1
Collate: 'RcppExports.R' 'osqp-package.R' 'solve.R' 'osqp.R' 'params.R'
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
Collate: 'RcppExports.R' 'osqp-package.R' 'sparse.R' 'solve.R' 'osqp.R' 'params.R'
NeedsCompilation: yes
Suggests: testthat
Encoding: UTF-8
BugReports: https://github.com/osqp/osqp-r/issues
URL: https://osqp.org
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Version 0.6.3

* Sync up to version [0.6.3 of OSQP release](https://github.com/osqp/osqp/releases/tag/v0.6.3)
* Fix `params.R` ([issue #18](https://github.com/osqp/osqp-r/issues/18))
* Added `time-limit` settings parameter per [PG's code](https://github.com/osqp/osqp-r/pull/24)
* Added check for lower bounds not exceeding upper bounds ([issue 29](https://github.com/osqp/osqp-r/issues/29))

# Version 0.6.0.8

* Fix prototype of `main` in `qdldl_sources/examplaes/example.c`
Expand Down
28 changes: 16 additions & 12 deletions R/osqp.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#' @importFrom Matrix triu
#' @importFrom methods as
#' @importFrom R6 R6Class
#' @param P,A sparse matrices of class dgCMatrix or coercible into such, with P positive semidefinite.
#' @param P,A sparse matrices of class dgCMatrix or coercible into such, with P positive semidefinite. (In the interest of efficiency, only the upper triangular part of P is used)
#' @param q,l,u Numeric vectors, with possibly infinite elements in l and u
#' @param pars list with optimization parameters, conveniently set with the function
#' \code{\link{osqpSettings}}. For \code{osqpObject$UpdateSettings(newPars)} only a subset of the settings
Expand Down Expand Up @@ -64,7 +64,7 @@
#' # Update model and solve again
#' model$Update(q = q_new)
#' res <- model$Solve()
#'
#' @importFrom Matrix sparseMatrix
#' @export
osqp = function(P=NULL, q=NULL, A=NULL, l=NULL, u=NULL, pars = osqpSettings()) {

Expand All @@ -73,14 +73,17 @@ osqp = function(P=NULL, q=NULL, A=NULL, l=NULL, u=NULL, pars = osqpSettings()) {

if (is.null(P))
n = length(q)
else
n = dim(P)[1]

else {
dimP <- dim(P)
n = dim(P)[1L]
if (dimP[2L] != n) stop("P must be symmetric!")
}

if (is.null(P)){
P = sparseMatrix(integer(), integer(), x = numeric(), dims = c(n, n))
P = Matrix::sparseMatrix(integer(), integer(), x = numeric(), dims = c(n, n))
} else {
P = triu(as(P, "dgCMatrix"))
## P = triu(as(P, "dgCMatrix"))
P <- ensure_dtc_matrix(P)
}

if (is.null(q))
Expand All @@ -91,11 +94,12 @@ osqp = function(P=NULL, q=NULL, A=NULL, l=NULL, u=NULL, pars = osqpSettings()) {

if (is.null(A)) {
m = 0
A = sparseMatrix(integer(), integer(), x = numeric(), dims = c(m, n))
A = Matrix::sparseMatrix(integer(), integer(), x = numeric(), dims = c(m, n))
u = l = numeric()
} else {
A = as(A, "dgCMatrix")
m = nrow(A)
## A = as(A, "dgCMatrix")
A <- ensure_dgc_matrix(A)
if (is.null(u))
u = rep_len(Inf, m)
else
Expand All @@ -107,11 +111,11 @@ osqp = function(P=NULL, q=NULL, A=NULL, l=NULL, u=NULL, pars = osqpSettings()) {
l = as.numeric(l)
}

stopifnot(dim(P) == c(n, n),
length(q) == n,
stopifnot(length(q) == n,
dim(A) == c(m, n),
length(l) == m,
length(u) == m)
length(u) == m,
l <= u)

R6Class("osqp_model",
public =
Expand Down
42 changes: 15 additions & 27 deletions R/params.R
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,27 @@
#' @param adaptive_rho_interval Number of iterations between rho adaptations rho. If 0, it is automatic
#' @param adaptive_rho_tolerance Tolerance X for adapting rho. The new rho has to be X times larger or 1/X times smaller than the current one to trigger a new factorization
#' @param adaptive_rho_fraction Interval for adapting rho (fraction of the setup time)
#' @param time_limit run time limit with 0 indicating no limit
#' @export
osqpSettings = function(rho = 0.1, sigma = 1e-06, max_iter = 4000L, eps_abs = 0.001,
eps_rel = 0.001, eps_prim_inf = 1e-04, eps_dual_inf = 1e-04,
alpha = 1.6, linsys_solver = c(QDLDL_SOLVER=0L),
delta = 1e-06, polish = FALSE, polish_refine_iter = 3L, verbose = TRUE,
scaled_termination = FALSE, check_termination = 25L, warm_start = TRUE,
scaling = 10L, adaptive_rho = 1L, adaptive_rho_interval = 0L,
adaptive_rho_tolerance = 5, adaptive_rho_fraction = 0.4) {
inpars = as.list(match.call())[-1]
pars = sapply(simplify = FALSE, USE.NAMES = TRUE, names(inpars), function(nm) {
checkpar(inpars[[nm]], defaultOsqpSettings[[nm]])
})
pars
}



defaultOsqpSettings = list(rho = 0.1, sigma = 1e-06, max_iter = 4000L, eps_abs = 0.001,
eps_rel = 0.001, eps_prim_inf = 1e-04, eps_dual_inf = 1e-04,
alpha = 1.6, linsys_solver = c(QDLDL_SOLVER=0L),
delta = 1e-06, polish = FALSE, polish_refine_iter = 3L, verbose = TRUE,
scaled_termination = FALSE, check_termination = 25L, warm_start = TRUE,
scaling = 10L, adaptive_rho = 1L, adaptive_rho_interval = 0L,
adaptive_rho_tolerance = 5, adaptive_rho_fraction = 0.4)


checkpar = function(l, r) {
adaptive_rho_tolerance = 5, adaptive_rho_fraction = 0.4, time_limit = 0.0) {
given_args <- as.list(environment()) ## all params with current values
call_arg_names <- names(match.call()[-1]) ## lose the function name at index 1
default_args <- formals() ## this is the default list of arg values
given_args <- given_args[call_arg_names] ## restrict to specified args

l = switch(typeof(r),
integer=as.integer(l),
double=as.numeric(l),
logical=as.logical(l))
if(length(l) != 1 || is.na(l))
return (r)
l
for (name in call_arg_names) {
given <- given_args[[name]]
if (length(given) != 1 || is.na(given)) {
given_args[[name]] <- default_args[[name]] ## force default
} else {
storage.mode(given_args[[name]]) <- storage.mode(eval(default_args[[name]])) #eval default arg
}
}
given_args
}
57 changes: 57 additions & 0 deletions R/sparse.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## Created by @naras to address coercion considerations with Matrix package
##
## Inspired by Rsymphony package from
## Kurt Hornik and Stefan Theussl and Reinhard Harter
##

#' Ensure that a matrix is column-sparse format (class `dgCMatrix`)
#' @param m a C sparse matrix or coercible object such as a matrix or simple triplet matrix
#' @return a sparse matrix of class `dgCMatrix`
#' @importFrom Matrix sparseMatrix
#' @importFrom methods as
#' @noRd
ensure_dgc_matrix <- function(m) {
if (inherits(m, "dgCMatrix")) {
m
} else if (inherits(m, "matrix")) {
Matrix::.m2sparse(m, "dgCMatrix")
} else if(inherits(m, "simple_triplet_matrix")) { ## e.g. from package slam
## The matrix method assumes that indices for non-zero entries are
## in row-major order, but the simple_triplet_matrix() constructor
## currently does not canonicalize accordingly ...
ind <- order(m$j, m$i)
Matrix::sparseMatrix(p = c(0L, cumsum(tabulate(m$j[ind], m$ncol))),
i = m$i[ind] - 1L,
values = m$v[ind], dims = dim(m), index1 = FALSE)
} else {
## Resort to brute force
as(as(as(m, "CsparseMatrix"), "generalMatrix"), "dMatrix")
}
}

#' Ensure that a matrix is column-sparse format upper triangular (class `dtCMatrix`)
#' @param m a C sparse upper triangular matrix or coercible object such as a matrix or simple triplet matrix
#' @return a sparse matrix of class `dgCMatrix`
#' @importFrom Matrix sparseMatrix triu
#' @importFrom methods as
#' @noRd
ensure_dtc_matrix <- function(m) {
if (inherits(m, "dgCMatrix")) {
m
} else if (inherits(m, "matrix")) {
Matrix::.m2sparse(m, "dtCMatrix")
} else if(inherits(m, "simple_triplet_matrix")) { ## e.g. from package slam
ind <- which(m$i <= m$j)
x <- list(i = m$i[ind] + 1L, j = m$j[ind] + 1L) ##make it 1-based
values <- m$v[ind]
ind <- order(x$j, x$i) ## may not be needed
Matrix::sparseMatrix(p = c(0L, cumsum(tabulate(x$j[ind], m$ncol))),
i = x$i[ind] - 1L,
values = values,
dims = dim(x), index1 = FALSE,
triangular = TRUE)
} else {
## Resort to brute force
Matrix::triu(as(as(as(m, "CsparseMatrix"), "generalMatrix"), "dMatrix"))
}
}
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# R interface for OSQP

<!-- [![image](https://travis-ci.org/oxfordcontrol/osqp-r.svg?branch=master)](https://travis-ci.org/oxfordcontrol/osqp-r) -->

<!-- [![image](https://ci.appveyor.com/api/projects/status/bx1navxa474nhlpd/branch/master?svg=true)](https://ci.appveyor.com/project/goulart-paul/osqp-r/branch/master) -->

<!-- badges: start -->
[![R-CMD-check](https://github.com/osqp/osqp-r/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/osqp/osqp-r/actions/workflows/R-CMD-check.yaml)
[![CRAN\_Status\_Badge](https://www.r-pkg.org/badges/version/osqp)](https://cran.r-project.org/package=osqp)
[![](https://cranlogs.r-pkg.org/badges/osqp)](https://CRAN.R-project.org/package=osqp)
<!-- badges: end -->

Provides R-bindings to [OSQP](https://osqp.org/): the Operator
Expand Down
2 changes: 1 addition & 1 deletion configure
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ LDFLAGS=`"${R_HOME}/bin/R" CMD config LDFLAGS`

if [ -x "$(command -v cmake)" ]; then
echo "Making fixes to osqp_sources for CRAN"
(cd src && ${R_HOME}/bin/Rscript ../inst/26ce409b_fixes/make_fixes.R)
(cd src && ${R_HOME}/bin/Rscript ../inst/58f00bd_fixes/make_fixes.R)
echo "-- Trying to build libosqp.a via cmake ..."
cd src/osqp_sources
mkdir -p build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#' @param path relative file path of source
#' @param line_no line numbers to be replaced (integer vector)
#' @param replacement the corresponding replacements (character vector)
#' @param comment_prefix the comment prefix, default C/C++
#' @param comment_prefix the comment prefix, default C/C++
replace_lines <- function(path, line_no, replacement, comment_prefix = "//") {
stopifnot(length(line_no) == length(replacement))
FIXED_FLAG <- paste(comment_prefix, "CRAN FIXES DONE")
Expand All @@ -20,24 +20,24 @@ replace_lines <- function(path, line_no, replacement, comment_prefix = "//") {
}
invisible(TRUE)
}

# Fix pardiso_interface.c
replace_lines(path = "osqp_sources/lin_sys/direct/pardiso/pardiso_interface.c",
line_no = 35,
replacement = "c_int mkl_get_max_threads(void);")

# Fix pardiso_loader.h
replace_lines(path = "osqp_sources/lin_sys/direct/pardiso/pardiso_loader.h",
line_no = 22,
replacement = "c_int lh_unload_pardiso(void);")

# Fix pardiso_loader.c
replace_lines(path = "osqp_sources/lin_sys/direct/pardiso/pardiso_loader.c",
line_no = c(25, 58, 90),
replacement = c("typedef int (*mkl_get_mt_t)(void);",
"c_int mkl_get_max_threads(void) {",
"c_int lh_unload_pardiso(void) {"))


## # Fix pardiso_interface.c
## replace_lines(path = "osqp_sources/lin_sys/direct/pardiso/pardiso_interface.c",
## line_no = 35,
## replacement = "c_int mkl_get_max_threads(void);")

## # Fix pardiso_loader.h
## replace_lines(path = "osqp_sources/lin_sys/direct/pardiso/pardiso_loader.h",
## line_no = 22,
## replacement = "c_int lh_unload_pardiso(void);")

## # Fix pardiso_loader.c
## replace_lines(path = "osqp_sources/lin_sys/direct/pardiso/pardiso_loader.c",
## line_no = c(25, 58, 90),
## replacement = c("typedef int (*mkl_get_mt_t)(void);",
## "c_int mkl_get_max_threads(void) {",
## "c_int lh_unload_pardiso(void) {"))
# Fix example.c
replace_lines(path = "osqp_sources/lin_sys/direct/qdldl/qdldl_sources/examples/example.c",
line_no = 17,
Expand All @@ -47,7 +47,13 @@ replace_lines(path = "osqp_sources/lin_sys/direct/qdldl/qdldl_sources/examples/e
file.rename(from = "osqp_sources/include/proj.h", to = "osqp_sources/include/osqp_proj.h")

## Fix CMakeLists.txt
replace_lines("osqp_sources/include/CMakeLists.txt", 11, ' "${CMAKE_CURRENT_SOURCE_DIR}/osqp_proj.h"',
replace_lines("osqp_sources/CMakeLists.txt", 2, 'cmake_minimum_required (VERSION 3.5)',
comment_prefix = "#")

replace_lines("osqp_sources/include/CMakeLists.txt", 12, ' "${CMAKE_CURRENT_SOURCE_DIR}/osqp_proj.h"',
comment_prefix = "#")

replace_lines("osqp_sources/lin_sys/direct/qdldl/qdldl_sources/CMakeLists.txt", 2, 'cmake_minimum_required (VERSION 3.5)',
comment_prefix = "#")

## Fix auxil.c
Expand Down
7 changes: 3 additions & 4 deletions man/osqp.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit b5fdc02

Please sign in to comment.