From 49f444d9116acf0462f8f084c0a9aa1f840d5ad5 Mon Sep 17 00:00:00 2001 From: Tamas Hakkel Date: Tue, 18 Mar 2025 16:26:44 +0100 Subject: [PATCH 01/10] property functions from ProximalOperators.jl moved here --- Project.toml | 2 +- src/ProximalCore.jl | 138 +-------------------------------------- src/base_functions.jl | 95 +++++++++++++++++++++++++++ src/gradient_and_prox.jl | 70 ++++++++++++++++++++ src/properties.jl | 130 ++++++++++++++++++++++++++++++++++++ 5 files changed, 299 insertions(+), 136 deletions(-) create mode 100644 src/base_functions.jl create mode 100644 src/gradient_and_prox.jl create mode 100644 src/properties.jl diff --git a/Project.toml b/Project.toml index 6c7f1d1..a6c625f 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ProximalCore" uuid = "dc4f5ac2-75d1-4f31-931e-60435d74994b" authors = ["Lorenzo Stella "] -version = "0.1.2" +version = "0.2.0" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/src/ProximalCore.jl b/src/ProximalCore.jl index 0bc6855..ad20bb3 100644 --- a/src/ProximalCore.jl +++ b/src/ProximalCore.jl @@ -2,140 +2,8 @@ module ProximalCore using LinearAlgebra -is_convex(::Type) = false -is_convex(::T) where T = is_convex(T) - -is_generalized_quadratic(::Type) = false -is_generalized_quadratic(::T) where T = is_generalized_quadratic(T) - -""" - gradient!(y, f, x) - -In-place gradient (and value) of `f` at `x`. - -The gradient is written to the (pre-allocated) array `y`, which should have the same shape/size as `x`. - -Returns the value `f` at `x`. - -See also: [`gradient`](@ref). -""" -gradient! - -""" - gradient(f, x) - -Gradient (and value) of `f` at `x`. - -Return a tuple `(y, fx)` consisting of -- `y`: the gradient of `f` at `x` -- `fx`: the value of `f` at `x` - -See also: [`gradient!`](@ref). -""" -function gradient(f, x) - y = similar(x) - fx = gradient!(y, f, x) - return y, fx -end - -""" - prox!(y, f, x, gamma=1) - -In-place proximal mapping for `f`, evaluated at `x`, with stepsize `gamma`. - -The proximal mapping is defined as -```math -\\mathrm{prox}_{\\gamma f}(x) = \\arg\\min_z \\left\\{ f(z) + \\tfrac{1}{2\\gamma}\\|z-x\\|^2 \\right\\}. -``` -The result is written to the (pre-allocated) array `y`, which should have the same shape/size as `x`. - -Returns the value of `f` at `y`. - -See also: [`prox`](@ref). -""" -prox! - -prox!(y, f, x) = prox!(y, f, x, 1) - -""" - prox(f, x, gamma=1) - -Proximal mapping for `f`, evaluated at `x`, with stepsize `gamma`. - -The proximal mapping is defined as -```math -\\mathrm{prox}_{\\gamma f}(x) = \\arg\\min_z \\left\\{ f(z) + \\tfrac{1}{2\\gamma}\\|z-x\\|^2 \\right\\}. -``` - -Returns a tuple `(y, fy)` consisting of -- `y`: the output of the proximal mapping of `f` at `x` with stepsize `gamma` -- `fy`: the value of `f` at `y` - -See also: [`prox!`](@ref). -""" -function prox(f, x, gamma=1) - y = similar(x) - fy = prox!(y, f, x, gamma) - return y, fy -end - -struct Zero end - -(::Zero)(x) = real(eltype(x))(0) - -function gradient!(y, f::Zero, x) - y .= eltype(x)(0) - return f(x) -end - -function prox!(y, ::Zero, x, gamma) - y .= x - return real(eltype(y))(0) -end - -is_convex(::Type{Zero}) = true -is_generalized_quadratic(::Type{Zero}) = true - -struct IndZero end - -function (::IndZero)(x) - R = real(eltype(x)) - if iszero(x) - return R(0) - end - return R(Inf) -end - -is_convex(::Type{IndZero}) = true -is_generalized_quadratic(::Type{IndZero}) = true - -function prox!(y, ::IndZero, x, gamma) - R = real(eltype(x)) - y .= R(0) - return R(0) -end - -struct ConvexConjugate{T} - f::T -end - -is_convex(::Type{<:ConvexConjugate}) = true -is_generalized_quadratic(::Type{ConvexConjugate{T}}) where T = is_generalized_quadratic(T) - -function prox_conjugate!(y, u, f, x, gamma) - u .= x ./ gamma - v = prox!(y, f, u, 1 / gamma) - v = real(dot(x, y)) - gamma * real(dot(y, y)) - v - y .= x .- gamma .* y - return v -end - -prox_conjugate!(y, f, x, gamma) = prox_conjugate!(y, similar(x), f, x, gamma) - -prox!(y, g::ConvexConjugate, x, gamma) = prox_conjugate!(y, g.f, x, gamma) - -convex_conjugate(f) = ConvexConjugate(f) -convex_conjugate(::Zero) = IndZero() -convex_conjugate(::IndZero) = Zero() +include("properties.jl") +include("gradient_and_prox.jl") +include("base_functions.jl") end # module diff --git a/src/base_functions.jl b/src/base_functions.jl new file mode 100644 index 0000000..498e546 --- /dev/null +++ b/src/base_functions.jl @@ -0,0 +1,95 @@ +""" + Zero() + +Constructs the zero function, i.e., the function that is zero everywhere. + +# Example +```jldoctest +julia> f = Zero() +Zero() + +julia> f(rand(3)) +0.0 +``` +""" +struct Zero end + +(::Zero)(x) = real(eltype(x))(0) + +function gradient!(y, f::Zero, x) + y .= eltype(x)(0) + return f(x) +end + +function prox!(y, ::Zero, x, gamma) + y .= x + return real(eltype(y))(0) +end + +is_convex(::Type{Zero}) = true +is_generalized_quadratic(::Type{Zero}) = true + +""" + IndZero() + +Constructs the indicator function of the zero set, i.e., the function that is zero if the input is zero and infinity otherwise. + +# Example +```jldoctest +julia> f = IndZero() +IndZero() + +julia> f([1, 2, 3]) +Inf + +julia> f([0, 0, 0]) +0.0 +``` +""" +struct IndZero end + +function (::IndZero)(x) + R = real(eltype(x)) + if iszero(x) + return R(0) + end + return R(Inf) +end + +is_convex(::Type{IndZero}) = true +is_generalized_quadratic(::Type{IndZero}) = true + +function prox!(y, ::IndZero, x, gamma) + R = real(eltype(x)) + y .= R(0) + return R(0) +end + +""" + ConvexConjugate(f) + +Constructs the convex conjugate of the function `f`. The convex conjugate of a function `f` is defined as + `f*(y) = sup_x { - f(x)}`. +""" +struct ConvexConjugate{T} + f::T +end + +is_convex(::Type{<:ConvexConjugate}) = true +is_generalized_quadratic(::Type{ConvexConjugate{T}}) where T = is_generalized_quadratic(T) + +function prox_conjugate!(y, u, f, x, gamma) + u .= x ./ gamma + v = prox!(y, f, u, 1 / gamma) + v = real(dot(x, y)) - gamma * real(dot(y, y)) - v + y .= x .- gamma .* y + return v +end + +prox_conjugate!(y, f, x, gamma) = prox_conjugate!(y, similar(x), f, x, gamma) + +prox!(y, g::ConvexConjugate, x, gamma) = prox_conjugate!(y, g.f, x, gamma) + +convex_conjugate(f) = ConvexConjugate(f) +convex_conjugate(::Zero) = IndZero() +convex_conjugate(::IndZero) = Zero() diff --git a/src/gradient_and_prox.jl b/src/gradient_and_prox.jl new file mode 100644 index 0000000..ea06076 --- /dev/null +++ b/src/gradient_and_prox.jl @@ -0,0 +1,70 @@ +""" + gradient!(y, f, x) + +In-place gradient (and value) of `f` at `x`. + +The gradient is written to the (pre-allocated) array `y`, which should have the same shape/size as `x`. + +Returns the value `f` at `x`. + +See also: [`gradient`](@ref). +""" +gradient! + +""" + gradient(f, x) + +Gradient (and value) of `f` at `x`. + +Return a tuple `(y, fx)` consisting of +- `y`: the gradient of `f` at `x` +- `fx`: the value of `f` at `x` + +See also: [`gradient!`](@ref). +""" +function gradient(f, x) + y = similar(x) + fx = gradient!(y, f, x) + return y, fx +end + +""" + prox!(y, f, x, gamma=1) + +In-place proximal mapping for `f`, evaluated at `x`, with stepsize `gamma`. + +The proximal mapping is defined as +```math +\\mathrm{prox}_{\\gamma f}(x) = \\arg\\min_z \\left\\{ f(z) + \\tfrac{1}{2\\gamma}\\|z-x\\|^2 \\right\\}. +``` +The result is written to the (pre-allocated) array `y`, which should have the same shape/size as `x`. + +Returns the value of `f` at `y`. + +See also: [`prox`](@ref). +""" +prox! + +prox!(y, f, x) = prox!(y, f, x, 1) + +""" + prox(f, x, gamma=1) + +Proximal mapping for `f`, evaluated at `x`, with stepsize `gamma`. + +The proximal mapping is defined as +```math +\\mathrm{prox}_{\\gamma f}(x) = \\arg\\min_z \\left\\{ f(z) + \\tfrac{1}{2\\gamma}\\|z-x\\|^2 \\right\\}. +``` + +Returns a tuple `(y, fy)` consisting of +- `y`: the output of the proximal mapping of `f` at `x` with stepsize `gamma` +- `fy`: the value of `f` at `y` + +See also: [`prox!`](@ref). +""" +function prox(f, x, gamma=1) + y = similar(x) + fy = prox!(y, f, x, gamma) + return y, fy +end diff --git a/src/properties.jl b/src/properties.jl new file mode 100644 index 0000000..73d9ea2 --- /dev/null +++ b/src/properties.jl @@ -0,0 +1,130 @@ +""" + is_convex(T::Type) + +Returns `true` if the type `T` represents a convex function. +A function f(x) is convex if its domain is a convex set and for all x, y in the domain and for all λ in [0, 1], we have f(λx + (1-λ)y) ≤ λf(x) + (1-λ)f(y). +""" +is_convex(::Type) = false +is_convex(::T) where T = is_convex(T) + +""" + is_generalized_quadratic(T::Type) + +Returns `true` if the type `T` represents a generalized quadratic function. +The general form of a quadratic function is f(x)=ax2+bx+c where a, b, and c are real numbers and a≠0. +""" +is_generalized_quadratic(::Type) = false +is_generalized_quadratic(::T) where T = is_generalized_quadratic(T) + +""" + is_prox_accurate(T::Type) + +Returns `true` if the type `T` has a proximal operator that can be expressed in a closed formula. + (i.e. `prox!` function is defined for the type `T`). +""" +is_prox_accurate(::Type) = true +is_prox_accurate(::T) where T = is_prox_accurate(T) + +""" + is_separable(T::Type) + +Returns `true` if the type `T` represents a separable function. +A function f(x) is separable if it can applied to each element of x independently. +""" +is_separable(::Type) = false +is_separable(::T) where T = is_separable(T) + +""" + is_singleton_indicator(T::Type) + +Returns `true` if the type `T` represents a singleton indicator function. +An indicator function f(x) is a singleton if it is 0 for a single value and ∞ otherwise. +""" +is_singleton_indicator(::Type) = false +is_singleton_indicator(::T) where T = is_singleton_indicator(T) + +""" + is_cone_indicator(T::Type) + +Returns `true` if the type `T` represents a conic indicator function. +A function f(x) is a cone if it is convex, positively homogeneous, and it returns 0 if and only if x is in a cone. +In other words, if f(x) = 0, then f(λx) = 0 for all λ ≥ 0. +""" +is_cone_indicator(::Type) = false +is_cone_indicator(::T) where T = is_cone_indicator(T) + +""" + is_affine_indicator(T::Type) + +Returns `true` if the type `T` represents an affine indicator function. +A function f(x) is affine if it is convex and it returns 0 if and only if x is in an affine set. +An affine set is a set that can be represented as the solution set of a system of linear equations. +In other words, f(x) = 0 if and only if Ax = b, where A is a matrix and b is a vector or A is a vector and b is a scalar. +""" +is_affine_indicator(T::Type) = is_singleton_indicator(T) +is_affine_indicator(::T) where T = is_affine_indicator(T) + +""" + is_set_indicator(T::Type) + +Returns `true` if the type `T` represents an indicator function of a set. +A function f(x) is a set if it is convex and it returns 0 if and only if x is in a set. +""" +is_set_indicator(T::Type) = is_cone_indicator(T) || is_affine_indicator(T) +is_set_indicator(::T) where T = is_set_indicator(T) + +""" + is_positively_homogeneous(T::Type) + +Returns `true` if the type `T` represents a positively homogeneous function. +A function f(x) is positively homogeneous if f(λx) = λf(x) for all λ ≥ 0. +""" +is_positively_homogeneous(T::Type) = is_cone_indicator(T) +is_positively_homogeneous(::T) where T = is_positively_homogeneous(T) + +""" + is_support(T::Type) + +Returns `true` if the type `T` represents a support function over a set. +A function f(x) is a support function over a set C if f(x) = sup{⟨x, c⟩ : c ∈ C}. +""" +is_support(T::Type) = is_convex(T) && is_positively_homogeneous(T) +is_support(::T) where T = is_support(T) + +""" + is_locally_smooth(T::Type) + +Returns `true` if the type `T` represents a locally smooth function. +A function f(x) is locally smooth if it is continuously differentiable on a subset of its domain. +If f is locally smooth, then `gradient!(y, f, x)` is expected to be defined, and it should return the value of f at x and store the gradient in y. +""" +is_locally_smooth(T::Type) = is_smooth(T) +is_locally_smooth(::T) where T = is_locally_smooth(T) + +""" + is_smooth(T::Type) + +Returns `true` if the type `T` represents a smooth function. +A function f(x) is smooth if it is continuously differentiable. +If f is smooth, then `gradient!(y, f, x)` is expected to be defined, and it should return the value of f at x and store the gradient in y. +""" +is_smooth(::Type) = false +is_smooth(::T) where T = is_smooth(T) + +""" + is_quadratic(T::Type) + +Returns `true` if the type `T` represents a quadratic function. +A function f(x) is quadratic if it is smooth and its Hessian is constant. +""" +is_quadratic(T::Type) = is_generalized_quadratic(T) && is_smooth(T) +is_quadratic(::T) where T = is_quadratic(T) + +""" + is_strongly_convex(T::Type) + +Returns `true` if the type `T` represents a strongly convex function. +A function f(x) is strongly convex if it is convex and there exists a positive constant μ such that f(x) - μ/2 * ||x||^2 is convex. +""" +is_strongly_convex(::Type) = false +is_strongly_convex(::T) where T = is_strongly_convex(T) From b37395b7dcf6deb6d4412dfc7672d214d6daf74f Mon Sep 17 00:00:00 2001 From: Tamas Hakkel Date: Tue, 18 Mar 2025 16:26:54 +0100 Subject: [PATCH 02/10] add docs --- .gitignore | 1 + docs/Project.toml | 3 +++ docs/make.jl | 17 +++++++++++++++++ docs/src/api.md | 25 +++++++++++++++++++++++++ docs/src/index.md | 20 ++++++++++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 docs/Project.toml create mode 100644 docs/make.jl create mode 100644 docs/src/api.md create mode 100644 docs/src/index.md diff --git a/.gitignore b/.gitignore index ba39cc5..1209b4f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ Manifest.toml +docs/build diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..827172f --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,3 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +ProximalCore = "dc4f5ac2-75d1-4f31-931e-60435d74994b" diff --git a/docs/make.jl b/docs/make.jl new file mode 100644 index 0000000..cbf9b0b --- /dev/null +++ b/docs/make.jl @@ -0,0 +1,17 @@ +using Documenter +using ProximalCore + +makedocs( + sitename = "ProximalCore.jl", + format = Documenter.HTML(), + modules = [ProximalCore], + pages = [ + "Home" => "index.md", + "API Reference" => "api.md" + ] +) + +#=deploydocs( + repo = "github.com/JuliaFirstOrder/ProximalCore.jl", + devbranch = "main" +)=# diff --git a/docs/src/api.md b/docs/src/api.md new file mode 100644 index 0000000..a50b7a1 --- /dev/null +++ b/docs/src/api.md @@ -0,0 +1,25 @@ +# API Reference + +```@meta +CurrentModule = ProximalCore +``` + +## Interface Meta-Functions +The main goal of this function to provide a universal interface to smooth functions +and proximable functions to be used by proximal gradient algorithms. +```@autodocs +Modules = [ProximalCore] +Pages = ["gradient_and_prox.jl"] +``` + +## Properties +```@autodocs +Modules = [ProximalCore] +Pages = ["properties.jl"] +``` + +## Basic Functions +```@autodocs +Modules = [ProximalCore] +Pages = ["base_functions.jl"] +``` diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..5e007ca --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,20 @@ +# ProximalCore.jl + +Core definitions for the ProximalOperators and ProximalAlgorithms ecosystem. + +## Installation + +```julia +using Pkg +Pkg.add("ProximalCore") +``` + +## Overview + +ProximalCore.jl provides the fundamental types and definitions used by the broader proximal optimization ecosystem in Julia, specifically [ProximalOperators.jl](https://github.com/JuliaFirstOrder/ProximalOperators.jl) and [ProximalAlgorithms.jl](https://github.com/JuliaFirstOrder/ProximalAlgorithms.jl). + +## Contents + +```@contents +Pages = ["api.md"] +``` From 54a7a8041877a5281f3718cdef76fd2b4e8da505 Mon Sep 17 00:00:00 2001 From: Tamas Hakkel Date: Mon, 14 Apr 2025 13:28:55 +0200 Subject: [PATCH 03/10] rename is_prox_accurate to is_proximable --- src/properties.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/properties.jl b/src/properties.jl index 73d9ea2..5a8de4c 100644 --- a/src/properties.jl +++ b/src/properties.jl @@ -17,13 +17,13 @@ is_generalized_quadratic(::Type) = false is_generalized_quadratic(::T) where T = is_generalized_quadratic(T) """ - is_prox_accurate(T::Type) + is_proximable(T::Type) Returns `true` if the type `T` has a proximal operator that can be expressed in a closed formula. (i.e. `prox!` function is defined for the type `T`). """ -is_prox_accurate(::Type) = true -is_prox_accurate(::T) where T = is_prox_accurate(T) +is_proximable(::Type) = true +is_proximable(::T) where T = is_proximable(T) """ is_separable(T::Type) From 1925ea8f4183faaec53ed9eeb33795425e17e691 Mon Sep 17 00:00:00 2001 From: Tamas Hakkel Date: Tue, 11 Nov 2025 19:34:26 +0100 Subject: [PATCH 04/10] Modernize Test.yaml --- .github/workflows/Test.yml | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml index ffbb080..5c34e82 100644 --- a/.github/workflows/Test.yml +++ b/.github/workflows/Test.yml @@ -6,31 +6,37 @@ on: - master pull_request: workflow_dispatch: + jobs: build: - name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} + name: Julia ${{ matrix.julia-version }} - ${{ matrix.os }} - ${{ matrix.julia-arch }} runs-on: ${{ matrix.os }} + strategy: fail-fast: false matrix: - version: - - '1' - - '1.2' - - '1.6' - os: - - ubuntu-latest - - macOS-latest - - windows-latest - arch: - - x64 + julia-version: ['1.2', 'lts', '1'] + julia-arch: [x64] + os: [ubuntu-latest, windows-latest, macOS-latest] + + # needed to allow julia-actions/cache to delete old caches that it has created + permissions: + actions: write + contents: read + steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 - uses: julia-actions/setup-julia@latest with: - version: ${{ matrix.version }} - arch: ${{ matrix.arch }} + version: ${{ matrix.julia-version }} + arch: ${{ matrix.julia-arch }} + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@latest - uses: julia-actions/julia-runtest@latest - - uses: julia-actions/julia-uploadcodecov@latest + - uses: codecov/codecov-action@v5 + # Upload coverage only from one job (Linux, Julia latest version) + if: matrix.os == 'ubuntu-latest' && matrix.julia-version == '1' + with: + files: lcov.info env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 40504ef2e6256c74b4fab4d73082ae35c3aeda5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Hakkel?= Date: Thu, 13 Nov 2025 10:31:04 +0100 Subject: [PATCH 05/10] fix docstring for is_locally_smooth Co-authored-by: Lorenzo Stella --- src/properties.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/properties.jl b/src/properties.jl index 5a8de4c..f3cb6a5 100644 --- a/src/properties.jl +++ b/src/properties.jl @@ -95,7 +95,7 @@ is_support(::T) where T = is_support(T) is_locally_smooth(T::Type) Returns `true` if the type `T` represents a locally smooth function. -A function f(x) is locally smooth if it is continuously differentiable on a subset of its domain. +A function f(x) is locally smooth if it is smooth on every open set within its domain. If f is locally smooth, then `gradient!(y, f, x)` is expected to be defined, and it should return the value of f at x and store the gradient in y. """ is_locally_smooth(T::Type) = is_smooth(T) From 4d43b12d0a0c583540a121bdb521579263f3f7eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Hakkel?= Date: Thu, 13 Nov 2025 10:31:20 +0100 Subject: [PATCH 06/10] fix docstring for is_smooth Co-authored-by: Lorenzo Stella --- src/properties.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/properties.jl b/src/properties.jl index f3cb6a5..6225098 100644 --- a/src/properties.jl +++ b/src/properties.jl @@ -105,7 +105,7 @@ is_locally_smooth(::T) where T = is_locally_smooth(T) is_smooth(T::Type) Returns `true` if the type `T` represents a smooth function. -A function f(x) is smooth if it is continuously differentiable. +A function f(x) is smooth if it is continuously differentiable and its gradient is Lipschitz. If f is smooth, then `gradient!(y, f, x)` is expected to be defined, and it should return the value of f at x and store the gradient in y. """ is_smooth(::Type) = false From 15c76bdf233048da7d4715c979cbe1f0e843b94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Hakkel?= Date: Wed, 19 Nov 2025 09:24:20 +0100 Subject: [PATCH 07/10] Fix docstrings of property functions Apply suggestions from code review Co-authored-by: Lorenzo Stella --- src/properties.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/properties.jl b/src/properties.jl index 6225098..ad9bbcb 100644 --- a/src/properties.jl +++ b/src/properties.jl @@ -10,8 +10,8 @@ is_convex(::T) where T = is_convex(T) """ is_generalized_quadratic(T::Type) -Returns `true` if the type `T` represents a generalized quadratic function. -The general form of a quadratic function is f(x)=ax2+bx+c where a, b, and c are real numbers and a≠0. +Returns `true` if the type `T` represents a generalized quadratic function, i.e. a quadratic function over a subspace and +∞ outside of it. +A quadratic function has the form f(x)=(1/2)* + + c where A is a symmetric matrix, b is a vector, and c a real number. """ is_generalized_quadratic(::Type) = false is_generalized_quadratic(::T) where T = is_generalized_quadratic(T) @@ -46,7 +46,7 @@ is_singleton_indicator(::T) where T = is_singleton_indicator(T) """ is_cone_indicator(T::Type) -Returns `true` if the type `T` represents a conic indicator function. +Returns `true` if the type `T` represents the indicator function of a cone. A function f(x) is a cone if it is convex, positively homogeneous, and it returns 0 if and only if x is in a cone. In other words, if f(x) = 0, then f(λx) = 0 for all λ ≥ 0. """ @@ -56,10 +56,10 @@ is_cone_indicator(::T) where T = is_cone_indicator(T) """ is_affine_indicator(T::Type) -Returns `true` if the type `T` represents an affine indicator function. +Returns `true` if the type `T` represents the indicator of an affine set. A function f(x) is affine if it is convex and it returns 0 if and only if x is in an affine set. An affine set is a set that can be represented as the solution set of a system of linear equations. -In other words, f(x) = 0 if and only if Ax = b, where A is a matrix and b is a vector or A is a vector and b is a scalar. +In other words, f(x) = 0 if Ax = b, for a given matrix A and vector b, and ∞ otherwise. """ is_affine_indicator(T::Type) = is_singleton_indicator(T) is_affine_indicator(::T) where T = is_affine_indicator(T) @@ -68,7 +68,7 @@ is_affine_indicator(::T) where T = is_affine_indicator(T) is_set_indicator(T::Type) Returns `true` if the type `T` represents an indicator function of a set. -A function f(x) is a set if it is convex and it returns 0 if and only if x is in a set. +The indicator of a set S is a function associating 0 to points in S, and ∞ otherwise. """ is_set_indicator(T::Type) = is_cone_indicator(T) || is_affine_indicator(T) is_set_indicator(::T) where T = is_set_indicator(T) @@ -85,8 +85,8 @@ is_positively_homogeneous(::T) where T = is_positively_homogeneous(T) """ is_support(T::Type) -Returns `true` if the type `T` represents a support function over a set. -A function f(x) is a support function over a set C if f(x) = sup{⟨x, c⟩ : c ∈ C}. +Returns `true` if the type `T` represents a support function of a set. +A function f(x) is a support function of a set C if f(x) = sup{⟨x, c⟩ : c ∈ C}. """ is_support(T::Type) = is_convex(T) && is_positively_homogeneous(T) is_support(::T) where T = is_support(T) From f2bbdd5bdc8e76b841a178d7b8474efb3999aec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Hakkel?= Date: Wed, 19 Nov 2025 11:47:04 +0100 Subject: [PATCH 08/10] Fix docstrings of property functions Co-authored-by: Lorenzo Stella --- src/properties.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/properties.jl b/src/properties.jl index ad9bbcb..77b373b 100644 --- a/src/properties.jl +++ b/src/properties.jl @@ -47,7 +47,8 @@ is_singleton_indicator(::T) where T = is_singleton_indicator(T) is_cone_indicator(T::Type) Returns `true` if the type `T` represents the indicator function of a cone. -A function f(x) is a cone if it is convex, positively homogeneous, and it returns 0 if and only if x is in a cone. +A cone is a set C such that if x ∈ C, then λx ∈ C for any λ ≥ 0. In other words, is a set that is closed under non-negative scaling. +`` In other words, if f(x) = 0, then f(λx) = 0 for all λ ≥ 0. """ is_cone_indicator(::Type) = false From 745ee6d041a571708c4274dae6a6b2d86aba4c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Hakkel?= Date: Wed, 19 Nov 2025 11:47:15 +0100 Subject: [PATCH 09/10] Fix docstrings of property functions Co-authored-by: Lorenzo Stella --- src/properties.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/properties.jl b/src/properties.jl index 77b373b..8b3ddb0 100644 --- a/src/properties.jl +++ b/src/properties.jl @@ -49,7 +49,6 @@ is_singleton_indicator(::T) where T = is_singleton_indicator(T) Returns `true` if the type `T` represents the indicator function of a cone. A cone is a set C such that if x ∈ C, then λx ∈ C for any λ ≥ 0. In other words, is a set that is closed under non-negative scaling. `` -In other words, if f(x) = 0, then f(λx) = 0 for all λ ≥ 0. """ is_cone_indicator(::Type) = false is_cone_indicator(::T) where T = is_cone_indicator(T) From ada9da211676abe8741e404a848227b48a81a5bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Hakkel?= Date: Wed, 19 Nov 2025 11:47:23 +0100 Subject: [PATCH 10/10] Fix docstrings of property functions Co-authored-by: Lorenzo Stella --- src/properties.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/properties.jl b/src/properties.jl index 8b3ddb0..0ce598a 100644 --- a/src/properties.jl +++ b/src/properties.jl @@ -57,7 +57,6 @@ is_cone_indicator(::T) where T = is_cone_indicator(T) is_affine_indicator(T::Type) Returns `true` if the type `T` represents the indicator of an affine set. -A function f(x) is affine if it is convex and it returns 0 if and only if x is in an affine set. An affine set is a set that can be represented as the solution set of a system of linear equations. In other words, f(x) = 0 if Ax = b, for a given matrix A and vector b, and ∞ otherwise. """