diff --git a/.breakage/Project.toml b/.breakage/Project.toml index a65fa1c..7f17b55 100644 --- a/.breakage/Project.toml +++ b/.breakage/Project.toml @@ -1,3 +1,3 @@ -[deps] -GitHub = "bc5e4493-9b4d-5f90-b8aa-2b2bcaad7a26" -PkgDeps = "839e9fc8-855b-5b3c-a3b7-2833d3dd1f59" +[deps] +GitHub = "bc5e4493-9b4d-5f90-b8aa-2b2bcaad7a26" +PkgDeps = "839e9fc8-855b-5b3c-a3b7-2833d3dd1f59" diff --git a/.github/workflows/Breakage.yml b/.github/workflows/Breakage.yml index 5a9d623..484ff19 100644 --- a/.github/workflows/Breakage.yml +++ b/.github/workflows/Breakage.yml @@ -1,165 +1,165 @@ -# Ref: https://securitylab.github.com/research/github-actions-preventing-pwn-requests -name: Breakage - -# read-only repo token -# no access to secrets -on: - pull_request: - -jobs: - # Build dynamically the matrix on which the "break" job will run. - # The matrix contains the packages that depend on ${{ env.pkg }}. - # Job "setup_matrix" outputs variable "matrix", which is in turn - # the output of the "getmatrix" step. - # The contents of "matrix" is a JSON description of a matrix used - # in the next step. It has the form - # { - # "pkg": [ - # "PROPACK", - # "LLSModels", - # "FletcherPenaltySolver" - # ] - # } - setup_matrix: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.getmatrix.outputs.matrix }} - env: - pkg: ${{ github.event.repository.name }} - steps: - - uses: actions/checkout@v4 - - uses: julia-actions/setup-julia@v2 - with: - version: 1 - arch: x64 - - id: getmatrix - run: | - julia -e 'using Pkg; Pkg.Registry.add(RegistrySpec(url = "https://github.com/JuliaRegistries/General.git"))' - julia --project=.breakage -e 'using Pkg; Pkg.update(); Pkg.instantiate()' - pkgs=$(julia --project=.breakage .breakage/get_jso_users.jl ${{ env.pkg }}) - vs='["latest", "stable"]' - # Check if pkgs is empty, and set it to a JSON array if necessary - if [[ -z "$pkgs" || "$pkgs" == "String[]" ]]; then - echo "No packages found; exiting successfully." - exit 0 - fi - vs='["latest", "stable"]' - matrix=$(jq -cn --argjson deps "$pkgs" --argjson vers "$vs" '{pkg: $deps, pkgversion: $vers}') # don't escape quotes like many posts suggest - echo "matrix=$matrix" >> "$GITHUB_OUTPUT" - - break: - needs: setup_matrix - if: needs.setup_matrix.result == 'success' && needs.setup_matrix.outputs.matrix != '' - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.setup_matrix.outputs.matrix) }} - - steps: - - uses: actions/checkout@v4 - - # Install Julia - - uses: julia-actions/setup-julia@v2 - with: - version: 1 - arch: x64 - - uses: actions/cache@v4 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- - - uses: julia-actions/julia-buildpkg@v1 - - # Breakage test - - name: 'Breakage of ${{ matrix.pkg }}, ${{ matrix.pkgversion }} version' - env: - PKG: ${{ matrix.pkg }} - VERSION: ${{ matrix.pkgversion }} - run: | - set -v - mkdir -p ./breakage - git clone https://github.com/JuliaSmoothOptimizers/$PKG.jl.git - cd $PKG.jl - if [ $VERSION == "stable" ]; then - TAG=$(git tag -l "v*" --sort=-creatordate | head -n1) - if [ -z "$TAG" ]; then - TAG="no_tag" - else - git checkout $TAG - fi - else - TAG=$VERSION - fi - export TAG - julia -e 'using Pkg; - PKG, TAG, VERSION = ENV["PKG"], ENV["TAG"], ENV["VERSION"] - joburl = joinpath(ENV["GITHUB_SERVER_URL"], ENV["GITHUB_REPOSITORY"], "actions/runs", ENV["GITHUB_RUN_ID"]) - open("../breakage/breakage-$PKG-$VERSION", "w") do io - try - TAG == "no_tag" && error("No tag for $VERSION") - pkg"activate ."; - pkg"instantiate"; - pkg"dev ../"; - if TAG == "latest" - global TAG = chomp(read(`git rev-parse --short HEAD`, String)) - end - pkg"build"; - pkg"test"; - - print(io, "[![](https://img.shields.io/badge/$TAG-Pass-green)]($joburl)"); - catch e - @error e; - print(io, "[![](https://img.shields.io/badge/$TAG-Fail-red)]($joburl)"); - end; - end' - - - uses: actions/upload-artifact@v4 - with: - name: breakage-${{ matrix.pkg }}-${{ matrix.pkgversion }} - path: breakage/breakage-* - - upload: - needs: break - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/download-artifact@v4 - with: - path: breakage - pattern: breakage-* - merge-multiple: true - - - run: ls -R - - run: | - cd breakage - echo "| Package name | latest | stable |" > summary.md - echo "|--|--|--|" >> summary.md - count=0 - for file in breakage-* - do - if [ $count == "0" ]; then - name=$(echo $file | cut -f2 -d-) - echo -n "| $name | " - else - echo -n "| " - fi - cat $file - if [ $count == "0" ]; then - echo -n " " - count=1 - else - echo " |" - count=0 - fi - done >> summary.md - - - name: PR comment with file - uses: thollander/actions-comment-pull-request@v2 - with: - filePath: breakage/summary.md +# Ref: https://securitylab.github.com/research/github-actions-preventing-pwn-requests +name: Breakage + +# read-only repo token +# no access to secrets +on: + pull_request: + +jobs: + # Build dynamically the matrix on which the "break" job will run. + # The matrix contains the packages that depend on ${{ env.pkg }}. + # Job "setup_matrix" outputs variable "matrix", which is in turn + # the output of the "getmatrix" step. + # The contents of "matrix" is a JSON description of a matrix used + # in the next step. It has the form + # { + # "pkg": [ + # "PROPACK", + # "LLSModels", + # "FletcherPenaltySolver" + # ] + # } + setup_matrix: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.getmatrix.outputs.matrix }} + env: + pkg: ${{ github.event.repository.name }} + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: 1 + arch: x64 + - id: getmatrix + run: | + julia -e 'using Pkg; Pkg.Registry.add(RegistrySpec(url = "https://github.com/JuliaRegistries/General.git"))' + julia --project=.breakage -e 'using Pkg; Pkg.update(); Pkg.instantiate()' + pkgs=$(julia --project=.breakage .breakage/get_jso_users.jl ${{ env.pkg }}) + vs='["latest", "stable"]' + # Check if pkgs is empty, and set it to a JSON array if necessary + if [[ -z "$pkgs" || "$pkgs" == "String[]" ]]; then + echo "No packages found; exiting successfully." + exit 0 + fi + vs='["latest", "stable"]' + matrix=$(jq -cn --argjson deps "$pkgs" --argjson vers "$vs" '{pkg: $deps, pkgversion: $vers}') # don't escape quotes like many posts suggest + echo "matrix=$matrix" >> "$GITHUB_OUTPUT" + + break: + needs: setup_matrix + if: needs.setup_matrix.result == 'success' && needs.setup_matrix.outputs.matrix != '' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.setup_matrix.outputs.matrix) }} + + steps: + - uses: actions/checkout@v4 + + # Install Julia + - uses: julia-actions/setup-julia@v2 + with: + version: 1 + arch: x64 + - uses: actions/cache@v4 + env: + cache-name: cache-artifacts + with: + path: ~/.julia/artifacts + key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} + restore-keys: | + ${{ runner.os }}-test-${{ env.cache-name }}- + ${{ runner.os }}-test- + ${{ runner.os }}- + - uses: julia-actions/julia-buildpkg@v1 + + # Breakage test + - name: 'Breakage of ${{ matrix.pkg }}, ${{ matrix.pkgversion }} version' + env: + PKG: ${{ matrix.pkg }} + VERSION: ${{ matrix.pkgversion }} + run: | + set -v + mkdir -p ./breakage + git clone https://github.com/JuliaSmoothOptimizers/$PKG.jl.git + cd $PKG.jl + if [ $VERSION == "stable" ]; then + TAG=$(git tag -l "v*" --sort=-creatordate | head -n1) + if [ -z "$TAG" ]; then + TAG="no_tag" + else + git checkout $TAG + fi + else + TAG=$VERSION + fi + export TAG + julia -e 'using Pkg; + PKG, TAG, VERSION = ENV["PKG"], ENV["TAG"], ENV["VERSION"] + joburl = joinpath(ENV["GITHUB_SERVER_URL"], ENV["GITHUB_REPOSITORY"], "actions/runs", ENV["GITHUB_RUN_ID"]) + open("../breakage/breakage-$PKG-$VERSION", "w") do io + try + TAG == "no_tag" && error("No tag for $VERSION") + pkg"activate ."; + pkg"instantiate"; + pkg"dev ../"; + if TAG == "latest" + global TAG = chomp(read(`git rev-parse --short HEAD`, String)) + end + pkg"build"; + pkg"test"; + + print(io, "[![](https://img.shields.io/badge/$TAG-Pass-green)]($joburl)"); + catch e + @error e; + print(io, "[![](https://img.shields.io/badge/$TAG-Fail-red)]($joburl)"); + end; + end' + + - uses: actions/upload-artifact@v4 + with: + name: breakage-${{ matrix.pkg }}-${{ matrix.pkgversion }} + path: breakage/breakage-* + + upload: + needs: break + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + path: breakage + pattern: breakage-* + merge-multiple: true + + - run: ls -R + - run: | + cd breakage + echo "| Package name | latest | stable |" > summary.md + echo "|--|--|--|" >> summary.md + count=0 + for file in breakage-* + do + if [ $count == "0" ]; then + name=$(echo $file | cut -f2 -d-) + echo -n "| $name | " + else + echo -n "| " + fi + cat $file + if [ $count == "0" ]; then + echo -n " " + count=1 + else + echo " |" + count=0 + fi + done >> summary.md + + - name: PR comment with file + uses: thollander/actions-comment-pull-request@v2 + with: + filePath: breakage/summary.md diff --git a/.github/workflows/Copier.yml b/.github/workflows/Copier.yml index f7919af..574bc9c 100644 --- a/.github/workflows/Copier.yml +++ b/.github/workflows/Copier.yml @@ -2,7 +2,7 @@ name: Copier Update on: schedule: - - cron: 0 7 1/7 * * # Every 7 days at 7:00 UTC + - cron: 0 7 1/7 * * # Every 7 days at 7:00 UTC workflow_dispatch: jobs: diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml index be0b865..5575279 100644 --- a/.github/workflows/Documentation.yml +++ b/.github/workflows/Documentation.yml @@ -1,23 +1,23 @@ -name: Documentation -on: - push: - branches: - - main - tags: '*' - pull_request: - types: [opened, synchronize, reopened] -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@latest - with: - version: '1' - - name: Install dependencies - run: julia --project=docs -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - - name: Build and deploy - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} - run: julia --project=docs --color=yes docs/make.jl +name: Documentation +on: + push: + branches: + - main + tags: '*' + pull_request: + types: [opened, synchronize, reopened] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@latest + with: + version: '1' + - name: Install dependencies + run: julia --project=docs -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + - name: Build and deploy + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} + run: julia --project=docs --color=yes docs/make.jl diff --git a/.github/workflows/Lint.yml b/.github/workflows/Lint.yml index f68ec22..dab91cf 100644 --- a/.github/workflows/Lint.yml +++ b/.github/workflows/Lint.yml @@ -14,7 +14,7 @@ concurrency: cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} jobs: - + lint: name: Linting runs-on: ubuntu-latest @@ -61,4 +61,3 @@ jobs: with: fail: true args: --config '.lychee.toml' . - diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml index c8dc2de..d87d62a 100644 --- a/.github/workflows/Test.yml +++ b/.github/workflows/Test.yml @@ -27,9 +27,9 @@ jobs: os: - ubuntu-latest - macOS-latest - + - windows-latest - + arch: - x64 allow_failure: [false] diff --git a/CITATION.cff b/CITATION.cff index 12f40ea..d31da02 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -8,4 +8,3 @@ type: software authors: - given-names: Dominique Orban email: dominique.orban@gmail.com - diff --git a/Project.toml b/Project.toml index 2633646..2bd2729 100644 --- a/Project.toml +++ b/Project.toml @@ -32,12 +32,15 @@ SVMExt = "MLDatasets" ADNLPModels = "0.7, 0.8" DifferentialEquations = "7.16" Distributions = "0.25" +LinearAlgebra = "1.10, 1.11" ManualNLPModels = "0.2" MLDatasets = "0.7" NLPModels = "0.16, 0.17, 0.18, 0.19, 0.20, 0.21" Noise = "0.2" ProximalOperators = "0.15, 0.16" +Random = "1.10, 1.11" QuadraticModels = "0.9" SciMLSensitivity = "7.89" ShiftedProximalOperators = "0.2" +SparseArrays = "1.10, 1.11" julia = "1.10" diff --git a/docs/assets/style.css b/docs/assets/style.css index 7f1fab0..f2cf50d 100644 --- a/docs/assets/style.css +++ b/docs/assets/style.css @@ -2,7 +2,7 @@ html.theme--documenter-dark #documenter .docs-sidebar { border-right: 4px solid #640000; background-color: #8c1515; - color: #fff; + color: #fff; } .mi, .mo, .mn { @@ -24,4 +24,4 @@ a:hover { nav.toc .logo { max-width: 256px; max-height: 256px; -} \ No newline at end of file +} diff --git a/docs/make.jl b/docs/make.jl index d0e88f2..0322103 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,21 +1,28 @@ using RegularizedProblems using Documenter -DocMeta.setdocmeta!(RegularizedProblems, :DocTestSetup, :(using RegularizedProblems); recursive = true) +DocMeta.setdocmeta!( + RegularizedProblems, + :DocTestSetup, + :(using RegularizedProblems); + recursive = true, +) const page_rename = Dict("developer.md" => "Developer docs") # Without the numbers const numbered_pages = [ - file for file in readdir(joinpath(@__DIR__, "src")) if - file != "index.md" && splitext(file)[2] == ".md" + file for file in readdir(joinpath(@__DIR__, "src")) if + file != "index.md" && splitext(file)[2] == ".md" ] makedocs(; - modules = [RegularizedProblems], - authors = "Dominique Orban , Robert Baraldi bounds ? "BPDNpos" : "BPDN") - nlsmodel_kwargs = Dict{Symbol, Any}(:name => bounds ? "BPDN-LS_pos" : "BPDN-LS") + nlpmodel_kwargs = Dict{Symbol,Any}(:name => bounds ? "BPDNpos" : "BPDN") + nlsmodel_kwargs = Dict{Symbol,Any}(:name => bounds ? "BPDN-LS_pos" : "BPDN-LS") if bounds nlpmodel_kwargs[:lvar] = zero(x0) nlpmodel_kwargs[:uvar] = fill!(similar(x0), Inf) @@ -92,6 +92,13 @@ function bpdn_model(args...; bounds::Bool = false) end FirstOrderModel(obj, grad!, zero(x0); nlpmodel_kwargs...), - FirstOrderNLSModel(resid!, jprod_resid!, jtprod_resid!, size(A, 1), zero(x0); nlsmodel_kwargs...), + FirstOrderNLSModel( + resid!, + jprod_resid!, + jtprod_resid!, + size(A, 1), + zero(x0); + nlsmodel_kwargs..., + ), x0 end diff --git a/src/group_lasso_model.jl b/src/group_lasso_model.jl index 9b74419..ab9a8b8 100644 --- a/src/group_lasso_model.jl +++ b/src/group_lasso_model.jl @@ -9,8 +9,10 @@ function group_lasso_data(; compound::Int = 1, ) m ≤ n || error("number of rows ($m) should be ≤ number of columns ($n)") - mod(n, g) == 0 || error("number of groups ($g) must divide evenly into number of rows ($n)") - ag ≤ g || error("number of active groups ($ag) must be smaller than the number of groups ($g)") + mod(n, g) == 0 || + error("number of groups ($g) must divide evenly into number of rows ($n)") + ag ≤ g || + error("number of active groups ($ag) must be smaller than the number of groups ($g)") compound > 0 || error("compound factor must be positive") m = compound * m diff --git a/src/nnmf.jl b/src/nnmf.jl index eea2ee0..a3ece86 100644 --- a/src/nnmf.jl +++ b/src/nnmf.jl @@ -45,11 +45,11 @@ function nnmf_model(m::Int = 100, n::Int = 50, k::Int = 10, T::DataType = Float6 WH = similar(A) gw = similar(A, (m, k)) gh = similar(A, (k, n)) - selected = (m * k + 1):((m + n) * k) + selected = (m*k+1):((m+n)*k) function resid!(r, x) - W = reshape_array(view(x, 1:(m * k)), (m, k)) - H = reshape_array(view(x, (m * k + 1):((m + n) * k)), (k, n)) + W = reshape_array(view(x, 1:(m*k)), (m, k)) + H = reshape_array(view(x, (m*k+1):((m+n)*k)), (k, n)) mul!(WH, W, H) for i ∈ eachindex(r) r[i] = A[i] - WH[i] @@ -66,24 +66,24 @@ function nnmf_model(m::Int = 100, n::Int = 50, k::Int = 10, T::DataType = Float6 resid!(r, x) minusR = reshape_array(r, (m, n)) minusR .*= -1 - W_T = reshape_array(view(x, 1:(m * k)), (m, k))' - H_T = reshape_array(view(x, (m * k + 1):((m + n) * k)), (k, n))' + W_T = reshape_array(view(x, 1:(m*k)), (m, k))' + H_T = reshape_array(view(x, (m*k+1):((m+n)*k)), (k, n))' mul!(gw, minusR, H_T) mul!(gh, W_T, minusR) for i ∈ eachindex(gw) g[i] = gw[i] end for i ∈ eachindex(gh) - g[i + m * k] = gh[i] + g[i+m*k] = gh[i] end return g end function jacv!(Jv, x, v) - W = reshape_array(view(x, 1:(m * k)), (m, k)) - H = reshape_array(view(x, (m * k + 1):((m + n) * k)), (k, n)) - W_v = reshape_array(view(v, 1:(m * k)), (m, k)) - H_v = reshape_array(view(v, (m * k + 1):((m + n) * k)), (k, n)) + W = reshape_array(view(x, 1:(m*k)), (m, k)) + H = reshape_array(view(x, (m*k+1):((m+n)*k)), (k, n)) + W_v = reshape_array(view(v, 1:(m*k)), (m, k)) + H_v = reshape_array(view(v, (m*k+1):((m+n)*k)), (k, n)) mul!(WH, W_v, H) for i ∈ eachindex(WH) Jv[i] = -WH[i] @@ -96,8 +96,8 @@ function nnmf_model(m::Int = 100, n::Int = 50, k::Int = 10, T::DataType = Float6 end function jactv!(Jtv, x, w) - W_T = reshape_array(view(x, 1:(m * k)), (m, k))' - H_T = reshape_array(view(x, (m * k + 1):((m + n) * k)), (k, n))' + W_T = reshape_array(view(x, 1:(m*k)), (m, k))' + H_T = reshape_array(view(x, (m*k+1):((m+n)*k)), (k, n))' X_v = reshape_array(w, (m, n)) mul!(gw, X_v, H_T) mul!(gh, W_T, X_v) @@ -105,7 +105,7 @@ function nnmf_model(m::Int = 100, n::Int = 50, k::Int = 10, T::DataType = Float6 Jtv[i] = -gw[i] end for i ∈ eachindex(gh) - Jtv[i + m * k] = -gh[i] + Jtv[i+m*k] = -gh[i] end return Jtv end diff --git a/src/testset_bpdn.jl b/src/testset_bpdn.jl index 9a7b125..08d7a90 100644 --- a/src/testset_bpdn.jl +++ b/src/testset_bpdn.jl @@ -3,14 +3,18 @@ export setup_bpdn_l0, setup_bpdn_l1, setup_bpdn_B0 function setup_bpdn_l0(args...; kwargs...) model, nls_model, _ = bpdn_model(args...; kwargs...) - λ = norm(grad(model, zeros(model.meta.nvar)), Inf) / 10 + y = similar(model.meta.x0) + grad!(model, y, zeros(model.meta.nvar)) + λ = norm(y) / 10 h = ProximalOperators.NormL0(λ) return RegularizedNLPModel(model, h), RegularizedNLSModel(nls_model, h) end function setup_bpdn_l1(args...; kwargs...) model, nls_model, _ = bpdn_model(args...; kwargs...) - λ = norm(grad(model, zeros(model.meta.nvar)), Inf) / 10 + y = similar(model.meta.x0) + grad!(model, y, zeros(model.meta.nvar)) + λ = norm(y) / 10 h = ProximalOperators.NormL1(λ) return RegularizedNLPModel(model, h), RegularizedNLSModel(nls_model, h) end diff --git a/src/testset_nnmf.jl b/src/testset_nnmf.jl index c52781f..3f6844a 100644 --- a/src/testset_nnmf.jl +++ b/src/testset_nnmf.jl @@ -5,12 +5,14 @@ function setup_nnmf_l0(args...; kwargs...) model, nls_model, _, selected = nnmf_model(args...) λ = norm(grad(model, rand(model.meta.nvar)), Inf) / 200 h = ProximalOperators.NormL0(λ) - return RegularizedNLPModel(model, h, selected), RegularizedNLSModel(nls_model, h, selected) + return RegularizedNLPModel(model, h, selected), + RegularizedNLSModel(nls_model, h, selected) end function setup_nnmf_l1(args...; kwargs...) model, nls_model, _, selected = nnmf_model(args...) λ = norm(grad(model, rand(model.meta.nvar)), Inf) / 100_000 h = ProximalOperators.NormL1(λ) - return RegularizedNLPModel(model, h, selected), RegularizedNLSModel(nls_model, h, selected) + return RegularizedNLPModel(model, h, selected), + RegularizedNLSModel(nls_model, h, selected) end diff --git a/src/types.jl b/src/types.jl index 2f8b4ef..e76cbe5 100644 --- a/src/types.jl +++ b/src/types.jl @@ -6,7 +6,7 @@ export AbstractRegularizedNLPModel, RegularizedNLPModel, RegularizedNLSModel @deprecate FirstOrderNLSModel(r!, jv!, jtv!, nequ, x; kwargs...) NLSModel(x, r!, nequ; jprod = jv!, jtprod = jtv!, kwargs...) #! format: on -abstract type AbstractRegularizedNLPModel{T, S} <: AbstractNLPModel{T, S} end +abstract type AbstractRegularizedNLPModel{T,S} <: AbstractNLPModel{T,S} end """ rmodel = RegularizedNLPModel(model, regularizer) @@ -30,28 +30,28 @@ This aggregate type can be used to call solvers with a single object representin model, but is especially useful for use with SolverBenchmark.jl, which expects problems to be defined by a single object. """ -mutable struct RegularizedNLPModel{T, S, M <: AbstractNLPModel{T, S}, H, I} <: - AbstractRegularizedNLPModel{T, S} +mutable struct RegularizedNLPModel{T,S,M<:AbstractNLPModel{T,S},H,I} <: + AbstractRegularizedNLPModel{T,S} model::M # smooth model h::H # regularizer selected::I # set of variables to which the regularizer should be applied end -function RegularizedNLPModel(model::AbstractNLPModel{T, S}, h::H) where {T, S, H} +function RegularizedNLPModel(model::AbstractNLPModel{T,S}, h::H) where {T,S,H} selected = 1:get_nvar(model) - RegularizedNLPModel{T, S, typeof(model), typeof(h), typeof(selected)}(model, h, selected) + RegularizedNLPModel{T,S,typeof(model),typeof(h),typeof(selected)}(model, h, selected) end -mutable struct RegularizedNLSModel{T, S, M <: AbstractNLSModel{T, S}, H, I} <: - AbstractRegularizedNLPModel{T, S} +mutable struct RegularizedNLSModel{T,S,M<:AbstractNLSModel{T,S},H,I} <: + AbstractRegularizedNLPModel{T,S} model::M # smooth model h::H # regularizer selected::I # set of variables to which the regularizer should be applied end -function RegularizedNLSModel(model::AbstractNLSModel{T, S}, h::H) where {T, S, H} +function RegularizedNLSModel(model::AbstractNLSModel{T,S}, h::H) where {T,S,H} selected = 1:get_nvar(model) - RegularizedNLSModel{T, S, typeof(model), typeof(h), typeof(selected)}(model, h, selected) + RegularizedNLSModel{T,S,typeof(model),typeof(h),typeof(selected)}(model, h, selected) end function NLPModels.obj(rnlp::AbstractRegularizedNLPModel, x::AbstractVector) diff --git a/src/utils.jl b/src/utils.jl index 8b31b25..9068cc7 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,3 +1,3 @@ # non-allocating reshape # see https://github.com/JuliaLang/julia/issues/36313 -reshape_array(a, dims) = invoke(Base._reshape, Tuple{AbstractArray, typeof(dims)}, a, dims) +reshape_array(a, dims) = invoke(Base._reshape, Tuple{AbstractArray,typeof(dims)}, a, dims) diff --git a/test/Project.toml b/test/Project.toml index c051902..c868fff 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,6 @@ [deps] ADNLPModels = "54578032-b7ea-4c30-94aa-7cbd1cce6c9a" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" ManualNLPModels = "30dfa513-9b2f-4fb3-9796-781eabac1617" @@ -13,6 +14,7 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] ADNLPModels = "0.7, 0.8" +Aqua = "0.8" DifferentialEquations = "7.16" ManualNLPModels = "0.2" MLDatasets = "0.7" diff --git a/test/runtests.jl b/test/runtests.jl index ff7444a..0fc924c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,12 +1,19 @@ using LinearAlgebra, Test +using Aqua using ADNLPModels, DifferentialEquations, ManualNLPModels, MLDatasets, NLPModels, ProximalOperators, - QuadraticModels, - SciMLSensitivity + QuadraticModels + +# This package is skipped on FreeBSD due to issues with SciMLSensitivity and Enzyme packages + +if !Sys.isfreebsd() + using SciMLSensitivity +end + using RegularizedProblems function test_well_defined(model, nls_model, sol) @@ -37,6 +44,11 @@ Don't add your tests to runtests.jl. Instead, create files named The file will be automatically included inside a `@testset` with title "Title For My Test". =# + +@testset "Aqua" begin + Aqua.test_all(RegularizedProblems; ambiguities = false) +end + for (root, dirs, files) in walkdir(@__DIR__) for file in files if isnothing(match(r"^test-.*\.jl$", file)) diff --git a/test/test-fh.jl b/test/test-fh.jl index b870ff5..5fade92 100644 --- a/test/test-fh.jl +++ b/test/test-fh.jl @@ -1,11 +1,15 @@ -model, nls_model, sol = fh_model() -test_objectives(model, nls_model) -@test typeof(model) <: ADNLPModel -@test typeof(sol) == typeof(model.meta.x0) -@test model.meta.nvar == 5 -@test all(model.meta.x0 .== 1) -@test length(findall(x -> x .!= 0, sol)) == 2 -@test typeof(nls_model) <: ADNLSModel -@test nls_model.meta.nvar == 5 -@test nls_model.nls_meta.nequ == 202 -@test all(nls_model.meta.x0 .== 1) +# This test is skipped on FreeBSD due to issues with SciMLSensitivity and Enzyme packages + +if !Sys.isfreebsd() + model, nls_model, sol = fh_model() + test_objectives(model, nls_model) + @test typeof(model) <: ADNLPModel + @test typeof(sol) == typeof(model.meta.x0) + @test model.meta.nvar == 5 + @test all(model.meta.x0 .== 1) + @test length(findall(x -> x .!= 0, sol)) == 2 + @test typeof(nls_model) <: ADNLSModel + @test nls_model.meta.nvar == 5 + @test nls_model.nls_meta.nequ == 202 + @test all(nls_model.meta.x0 .== 1) +end