Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions .github/workflows/Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
Manifest.toml
docs/build
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "ProximalCore"
uuid = "dc4f5ac2-75d1-4f31-931e-60435d74994b"
authors = ["Lorenzo Stella <lorenzostella@gmail.com>"]
version = "0.1.2"
version = "0.2.0"

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand Down
3 changes: 3 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
ProximalCore = "dc4f5ac2-75d1-4f31-931e-60435d74994b"
17 changes: 17 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -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"
)=#
25 changes: 25 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
@@ -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"]
```
20 changes: 20 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -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"]
```
138 changes: 3 additions & 135 deletions src/ProximalCore.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
95 changes: 95 additions & 0 deletions src/base_functions.jl
Original file line number Diff line number Diff line change
@@ -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 {<x, y> - 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()
Loading
Loading