In our recent paper, we presented a new approach for generating a guaranteed affine underestimator for a black-box convex function on a box domain, by tractable derivative-free sampling. Felix Bonhoff's master's thesis (RWTH Aachen, 2023) presented a variant of this approach that requires fewer samples.
This repository provides a Julia implementation of our new sampling approach, tested in Julia v1.9. If you make use of this implementation in your own work, please cite the accompanying article:
Yingkai Song, Huiyi Cao, C. Mehta, and Kamil A. Khan, Bounding convex relaxations of process models from below by tractable black-box sampling, Computers & Chemical Engineering, 153:107413 (2021). doi:10.1016/j.compchemeng.2021.107413
In the Julia REPL, enter the following command:
import Pkg; Pkg.add(url="https://github.com/kamilkhanlab/ConvexSampling.jl")
Now the package's module can be invoked with using ConvexSampling
.
Consider the following convex quadratic function f
:
using LinearAlgebra
A = [65.0 56.0; 56.0 65.0]
b = [6.0, 2.0]
c = 23.0
f(x) = dot(x, A, x) + dot(b, x) + c
xL = [-5.0, -3.0]
xU = [5.0, 3.0]
on the box domain: all(xL .<= x .<= xU)
. Suppose we wish to construct affine underestimators and/or lower bounds of f
on its box domain.
-
Once the package is installed, we can load its module:
using ConvexSampling
-
Now,
f
can be sampled at either 5 domain points using the approach of Song et al.:data = sample_convex_function(f, xL, xU; stencil=:compass)
or at 4 domain points using the approach of Bonhoff:
data = sample_convex_function(f, xL, xU; stencil=:simplex)
In general, for a function of
n
variables,stencil=:compass
will sample this function2n+1
times, whilestencil=:simplex
will sample itn+2
times, but may ultimately yield a looser relaxation.Our approach handles univariate and multivariate functions differently, so our implementation has Julia dispatch over
typeof(xL)
:- If
xL
is aFloat64
, thenf
must have the signaturef(x::Float64) -> Float64
, and our univariate formulas will be applied. Any univariate function must be entered this way. - If
xL
is aVector{Float64}
with$\geq 2$ components, thenf
must have the signaturef(x::Vector{Float64}) -> Float64
, and our multivariate formulas will be applied.
Either way,
xU
must have the same type and number of components asxL
. - If
-
Using the sampled information, we can construct a guaranteed affine underestimator of
f
on its box domain:fAffine = construct_underestimator(data)
The constructed function
fAffine
underestimatesf
on its box domain, sofAffine(x) <= f(x)
wheneverall(xL .<= x .<= xU)
. We can instead obtain this underestimator as its constant coefficients:w0, b, c = evaluate_underestimator_coeffs(data)
in which case
fAffine(x) == c + dot(b, x - w0)
for allx
.We can also evaluate a guaranteed lower bound of
f
on its box domain:fL = evaluate_lower_bound(data)
Then, we will have
f(x) >= fL
for eachx
in the domain. -
The function
f
may be plotted with its sampling-based underestimatorfAffine
and lower boundfL
:graph = plot_underestimator(data, f) @show graph
Note that if the
plot_sampling_underestimator
function is entered directly in the REPL, the@show
command is not required.
Suppose we have a convex function
As in our paper, this implementation also allows for absolute error in evaluating
A newer procedure is implemented in Bonhoff's master's thesis (RWTH Aachen, 2023), requiring
- Yingkai Song, Huiyi Cao, C. Mehta, and Kamil A. Khan, Bounding convex relaxations of process models from below by tractable black-box sampling, Computers & Chemical Engineering, 153:107413, 2021, DOI: 10.1016/j.compchemeng.2021.107413
- Felix Bonhoff, master's thesis, RWTH Aachen, 2023