diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml index 15fa6547..15a73f23 100644 --- a/.JuliaFormatter.toml +++ b/.JuliaFormatter.toml @@ -1,7 +1,18 @@ -margin = 100 +align_assignment = true +align_matrix = true +align_pair_arrow = true +align_struct_field = true +always_for_in = true +annotate_untyped_fields_with_any = false +conditional_to_if = true +for_in_replacement = "in" +format_docstrings = false +format_markdown = false +import_to_using = true indent = 2 -whitespace_typedefs = true -whitespace_ops_in_indices = true +margin = 100 +normalize_line_endings = "unix" remove_extra_newlines = true -annotate_untyped_fields_with_any = false -normalize_line_endings = "unix" \ No newline at end of file +separate_kwargs_with_semicolon = true +whitespace_ops_in_indices = true +whitespace_typedefs = true diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 00000000..fd2f1513 --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,5 @@ +{ + "projectName": "JSOSuite", + "projectOwner": "JuliaSmoothOptimizers", + "files": ["README.md", "docs/src/index.md"] +} diff --git a/.cirrus.yml b/.cirrus.yml index e8a90ba6..a5763184 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,31 +1,12 @@ +freebsd_instance: + image_family: freebsd-13-3 task: - matrix: - - name: FreeBSD - freebsd_instance: - image_family: freebsd-13-3 - env: - matrix: - - JULIA_VERSION: 1.6 - - JULIA_VERSION: 1 - - name: MacOS M1 - macos_instance: - image: ghcr.io/cirruslabs/macos-ventura-base:latest - env: - - JULIA_VERSION: 1 - install_script: | - URL="https://raw.githubusercontent.com/ararslan/CirrusCI.jl/master/bin/install.sh" - set -x - if [ "$(uname -s)" = "Linux" ] && command -v apt; then - apt update - apt install -y curl - fi - if command -v curl; then - sh -c "$(curl ${URL})" - elif command -v wget; then - sh -c "$(wget ${URL} -q -O-)" - elif command -v fetch; then - sh -c "$(fetch ${URL} -o -)" - fi + name: FreeBSD + env: + matrix: + - JULIA_VERSION: 1 + install_script: + - sh -c "$(fetch https://raw.githubusercontent.com/ararslan/CirrusCI.jl/master/bin/install.sh -o -)" build_script: - cirrusjl build test_script: diff --git a/.copier-answers.yml b/.copier-answers.yml new file mode 100644 index 00000000..56fc44a1 --- /dev/null +++ b/.copier-answers.yml @@ -0,0 +1,22 @@ +# Changes here will be overwritten by Copier +AddAllcontributors: true +AddCodeOfConduct: true +AddCopierCI: false +AddGitHubTemplates: true +AddMacToCI: true +AddPrecommit: true +AddWinToCI: true +AnswerStrategy: ask +AuthorEmail: tangi.migot@gmail.com +AuthorName: Tangi Migot +Indentation: 2 +JuliaMinVersion: '1.6' +License: MPL-2.0 +PackageName: JSOSuite +PackageOwner: JuliaSmoothOptimizers +PackageUUID: ed6ae0be-a024-11e9-2788-05dbf8cd15d9 +RunJuliaNightlyOnCI: false +SimplifiedPRTest: true +UseCirrusCI: true +_commit: v0.7.2 +_src_path: https://github.com/abelsiqueira/BestieTemplate.jl diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..9f5c55fc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +# https://editorconfig.org +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_size = 2 +indent_style = space +trim_trailing_whitespace = true diff --git a/.github/ISSUE_TEMPLATE/10-bug-report.yml b/.github/ISSUE_TEMPLATE/10-bug-report.yml new file mode 100644 index 00000000..3024d2a7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/10-bug-report.yml @@ -0,0 +1,61 @@ +name: Bug Report +description: File a bug report related to running the package +title: "[Bug] " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + + Please, before submitting, make sure that: + + - There is not an [existing issue](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/issues) with the same question + - You have read the [contributing guide](https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/dev/90-contributing/) + - You are following the [code of conduct](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/blob/main/CODE_OF_CONDUCT.md) + + The form below should help you in filling out this issue. + - type: textarea + id: description + attributes: + label: Description + description: Describe the bug + validations: + required: true + - type: input + id: pkg-version + attributes: + label: Package Version + description: What version of the package are you running? + validations: + required: true + - type: input + id: version + attributes: + label: Julia Version + description: What version of Julia are you running? + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Reproduction steps + description: What steps led to the bug happening? Please provide a minimal reproducible example. + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: dropdown + id: os + attributes: + label: "Operating System" + description: What is the impacted environment? + multiple: true + options: + - Windows + - Linux + - Mac diff --git a/.github/ISSUE_TEMPLATE/20-feature-request.yml b/.github/ISSUE_TEMPLATE/20-feature-request.yml new file mode 100644 index 00000000..72b2cf51 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/20-feature-request.yml @@ -0,0 +1,42 @@ +name: "Feature Request" +description: Suggest a new feature for the package +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this feature request! + + Please, before submitting, make sure that: + + - There is not an [existing issue](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/issues) with the same question + - You have read the [contributing guide](https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/dev/90-contributing/) + - You are following the [code of conduct](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/blob/main/CODE_OF_CONDUCT.md) + + The form below should help you in filling out this issue. + - type: textarea + id: description + attributes: + label: Description + description: Describe the requested feature + validations: + required: true + - type: textarea + id: validation + attributes: + label: Validation and testing + description: How could we verify that the new feature works? What kind of tests can be done? + - type: textarea + id: motivation + attributes: + label: Motivation + description: Explain why this feature is relevant + - type: textarea + id: target + attributes: + label: Target audience + description: Tell more about the users of this feature, or where it could be useful + - type: textarea + id: can-help + attributes: + label: Can you help? + description: Can you help developing this feature? diff --git a/.github/ISSUE_TEMPLATE/30-usage.yml b/.github/ISSUE_TEMPLATE/30-usage.yml new file mode 100644 index 00000000..79c1d89c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/30-usage.yml @@ -0,0 +1,24 @@ +name: "Usage question" +description: Questions related to the usage +labels: ["documentation"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this question! + + Please, before submitting, make sure that: + + - You have checked the [documentation](https://JuliaSmoothOptimizers.github.io/JSOSuite.jl) and haven't found enough information + - There is not an [existing issue](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/issues) with the same question + - You have read the [contributing guide](https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/dev/90-contributing/) + - You are following the [code of conduct](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/blob/main/CODE_OF_CONDUCT.md) + + The form below should help you in filling out this issue. + - type: textarea + id: description + attributes: + label: Description + description: Write your question + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/99-general.yml b/.github/ISSUE_TEMPLATE/99-general.yml new file mode 100644 index 00000000..2fab63ca --- /dev/null +++ b/.github/ISSUE_TEMPLATE/99-general.yml @@ -0,0 +1,22 @@ +name: "General issue" +description: In case none of the others templates apply +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this issue! + + Please, before submitting, make sure that: + + - There is not an [existing issue](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/issues) with the same question + - You have read the [contributing guide](https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/dev/90-contributing/) + - You are following the [code of conduct](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/blob/main/CODE_OF_CONDUCT.md) + + The form below should help you in filling out this issue. + - type: textarea + id: description + attributes: + label: Description + description: Describe the issue + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..5f421dbe --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Discussions + url: https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/discussions + about: Create and follow discussions here diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..84d911e7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ + + +## Related issues + + + + +Closes # + + + + +## Checklist + + + +- [ ] I am following the [contributing guidelines](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/blob/main/docs/src/90-contributing.md) +- [ ] Tests are passing +- [ ] Lint workflow is passing +- [ ] Docs were updated and workflow is passing diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..700707ce --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml index 34613bb7..210e56f0 100644 --- a/.github/workflows/CompatHelper.yml +++ b/.github/workflows/CompatHelper.yml @@ -3,7 +3,7 @@ name: CompatHelper on: schedule: - - cron: 0 0 * * * + - cron: 0 0 * * * # Every day at 00:00 UTC workflow_dispatch: permissions: @@ -24,6 +24,8 @@ jobs: version: "1" arch: ${{ runner.arch }} if: steps.julia_in_path.outcome != 'success' + - name: Use Julia cache + uses: julia-actions/cache@v2 - name: "Add the General registry via Git" run: | import Pkg diff --git a/.github/workflows/Docs.yml b/.github/workflows/Docs.yml new file mode 100644 index 00000000..846240cb --- /dev/null +++ b/.github/workflows/Docs.yml @@ -0,0 +1,53 @@ +name: Docs + +on: + push: + branches: + - main + paths: + - "docs/**" + - "src/**" + - "*.toml" + tags: ["*"] + pull_request: + branches: + - main + paths: + - "docs/**" + - "src/**" + - "*.toml" + types: [opened, synchronize, reopened] + +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: "1" + - name: Use Julia cache + uses: julia-actions/cache@v2 + - run: | + julia --project=docs -e ' + using Pkg + Pkg.develop(PackageSpec(path=pwd())) + Pkg.instantiate()' + - run: | + julia --project=docs -e ' + using Documenter: DocMeta, doctest + using JSOSuite + DocMeta.setdocmeta!(JSOSuite, :DocTestSetup, :(using JSOSuite); recursive=true) + doctest(JSOSuite)' + - run: julia --project=docs docs/make.jl + env: + JULIA_PKG_SERVER: "" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml deleted file mode 100644 index be0b8658..00000000 --- a/.github/workflows/Documentation.yml +++ /dev/null @@ -1,23 +0,0 @@ -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 new file mode 100644 index 00000000..d7ba1d15 --- /dev/null +++ b/.github/workflows/Lint.yml @@ -0,0 +1,55 @@ +name: Lint + +on: + push: + branches: + - main + tags: ["*"] + pull_request: + +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + lint: + name: Linting + runs-on: ubuntu-latest + steps: + - name: Clone + uses: actions/checkout@v4 + - name: Setup Julia + uses: julia-actions/setup-julia@v2 + with: + version: "1" + - name: Use Julia cache + uses: julia-actions/cache@v2 + - name: Install JuliaFormatter.jl + run: julia -e 'using Pkg; pkg"add JuliaFormatter"' + - name: Setup Python + uses: actions/setup-python@v5 + with: + cache: "pip" + - name: Cache pre-commit + uses: actions/cache@v4 + with: + path: ~/.cache/pre-commit + key: ${{ runner.os }}-pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }} + - name: Install pre-commit + run: pip install pre-commit + - name: Run pre-commit + run: SKIP=no-commit-to-branch pre-commit run -a + + link-checker: + name: Link checker + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Link Checker + id: lychee + uses: lycheeverse/lychee-action@v1 + with: + fail: true diff --git a/.github/workflows/PreCommitUpdate.yml b/.github/workflows/PreCommitUpdate.yml new file mode 100644 index 00000000..c1bcef19 --- /dev/null +++ b/.github/workflows/PreCommitUpdate.yml @@ -0,0 +1,35 @@ +name: pre-commit Update + +on: + schedule: + - cron: "0 7 1/7 * *" # At 7:00 every 7 days + workflow_dispatch: + +jobs: + pre-commit-update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + cache: pip + - name: Install pre-commit + run: pip install pre-commit + - name: Run pre-commit's autoupdate + run: | + # ignore exit code + pre-commit autoupdate || true + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v6 + with: + commit-message: "chore: :robot: pre-commit update" + title: "[AUTO] pre-commit update" + branch: auto-pre-commit-update + delete-branch: true + labels: chore + - name: Check outputs + run: | + echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" + echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" diff --git a/.github/workflows/ReusableTest.yml b/.github/workflows/ReusableTest.yml new file mode 100644 index 00000000..12431f28 --- /dev/null +++ b/.github/workflows/ReusableTest.yml @@ -0,0 +1,52 @@ +name: Reusable test + +on: + workflow_call: + inputs: + version: + required: false + type: string + default: "1" + os: + required: false + type: string + default: ubuntu-latest + arch: + required: false + type: string + default: x64 + allow_failure: + required: false + type: boolean + default: false + run_codecov: + required: false + type: boolean + default: false + secrets: + codecov_token: + required: true + +jobs: + test: + name: Julia ${{ inputs.version }} - ${{ inputs.os }} - ${{ inputs.arch }} - ${{ github.event_name }} + runs-on: ${{ inputs.os }} + continue-on-error: ${{ inputs.allow_failure }} + + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: ${{ inputs.version }} + arch: ${{ inputs.arch }} + - name: Use Julia cache + uses: julia-actions/cache@v2 + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 + - uses: julia-actions/julia-processcoverage@v1 + if: ${{ inputs.run_codecov }} + - uses: codecov/codecov-action@v4 + if: ${{ inputs.run_codecov }} + with: + file: lcov.info + token: ${{ secrets.codecov_token }} diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml index 083baf95..dab9b0b6 100644 --- a/.github/workflows/TagBot.yml +++ b/.github/workflows/TagBot.yml @@ -1,15 +1,37 @@ -name: TagBot -on: - issue_comment: - types: - - created - workflow_dispatch: -jobs: - TagBot: - if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' - runs-on: ubuntu-latest - steps: - - uses: JuliaRegistries/TagBot@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - ssh: ${{ secrets.DOCUMENTER_KEY }} +name: TagBot + +on: + issue_comment: + types: + - created + workflow_dispatch: + inputs: + lookback: + type: number + default: 3 + +permissions: + actions: read + checks: read + contents: write + deployments: read + issues: read + discussions: read + packages: read + pages: read + pull-requests: read + repository-projects: read + security-events: read + statuses: read + +jobs: + TagBot: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' + runs-on: ubuntu-latest + steps: + - uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + # Edit the following line to reflect the actual name of the GitHub Secret containing your private key + ssh: ${{ secrets.DOCUMENTER_KEY }} + # ssh: ${{ secrets.NAME_OF_MY_SSH_PRIVATE_KEY_SECRET }} diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml new file mode 100644 index 00000000..cc8feed6 --- /dev/null +++ b/.github/workflows/Test.yml @@ -0,0 +1,48 @@ +name: Test + +on: + push: + branches: + - main + tags: ["*"] + + workflow_dispatch: + +jobs: + test: + uses: ./.github/workflows/ReusableTest.yml + with: + os: ${{ matrix.os }} + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + allow_failure: ${{ matrix.allow_failure }} + run_codecov: ${{ matrix.version == '1' && matrix.os == 'ubuntu-latest' }} + secrets: + codecov_token: ${{ secrets.CODECOV_TOKEN }} + strategy: + fail-fast: false + matrix: + version: + - "1.6" + - "1" + os: + - ubuntu-latest + - macOS-latest + - windows-latest + arch: + - x64 + allow_failure: [false] + + include: + - version: "nightly" + os: ubuntu-latest + arch: x64 + allow_failure: true + - version: "nightly" + os: macOS-latest + arch: x64 + allow_failure: true + - version: "nightly" + os: windows-latest + arch: x64 + allow_failure: true diff --git a/.github/workflows/TestOnPRs.yml b/.github/workflows/TestOnPRs.yml new file mode 100644 index 00000000..19a1f5a8 --- /dev/null +++ b/.github/workflows/TestOnPRs.yml @@ -0,0 +1,29 @@ +name: Test on PRs + +on: + pull_request: + branches: + - main + paths: + - "src/**" + - "test/**" + - "*.toml" + types: [opened, synchronize, reopened] + +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + test: + uses: ./.github/workflows/ReusableTest.yml + with: + os: ubuntu-latest + version: "1" + arch: x64 + allow_failure: false + run_codecov: true + secrets: + codecov_token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 409e0d14..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: CI -on: - push: - branches: - - main - pull_request: - types: [opened, synchronize, reopened] -jobs: - test: - name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} - runs-on: ${{ matrix.os }} - continue-on-error: ${{ matrix.allow_failure }} - strategy: - fail-fast: false - matrix: - version: ['1.6', '1'] - os: [ubuntu-latest, macOS-latest, windows-latest] - arch: [x64] - allow_failure: [false] - include: - - version: 'nightly' - os: ubuntu-latest - arch: x64 - allow_failure: true - - version: 'nightly' - os: macOS-latest - arch: x64 - allow_failure: true - - version: 'nightly' - os: windows-latest - arch: x64 - allow_failure: true - steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 - with: - version: ${{ matrix.version }} - arch: ${{ matrix.arch }} - - uses: actions/cache@v1 - 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 - - uses: julia-actions/julia-runtest@v1 - - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v1 - with: - file: lcov.info diff --git a/.github/workflows/format_pr.yml b/.github/workflows/format_pr.yml deleted file mode 100644 index c8f53089..00000000 --- a/.github/workflows/format_pr.yml +++ /dev/null @@ -1,32 +0,0 @@ -# https://github.com/julia-actions/julia-format/blob/master/workflows/format_pr.yml -name: format-pr -on: - push: - branches: - - main - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Install JuliaFormatter and format - run: | - julia -e 'import Pkg; Pkg.add("JuliaFormatter")' - julia -e 'using JuliaFormatter; format(".")' - # https://github.com/marketplace/actions/create-pull-request - # https://github.com/peter-evans/create-pull-request#reference-example - - name: Create Pull Request - id: cpr - uses: peter-evans/create-pull-request@v3 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: ":robot: Format .jl files" - title: '[AUTO] JuliaFormatter.jl run' - branch: auto-juliaformatter-pr - delete-branch: true - labels: formatting, automated pr, no changelog - - name: Check outputs - run: | - echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" - echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" \ No newline at end of file diff --git a/.gitignore b/.gitignore index ba39cc53..c3dfb743 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,7 @@ +*.jl.*.cov +*.jl.cov +*.jl.mem Manifest.toml +docs/build/ +*.rej +node_modules diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 00000000..8bf958ad --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,13 @@ +{ + "MD007": { + "indent": 2, + "start_indented": false + }, + "MD013": { + "line_length": 1000, + "tables": false + }, + "MD033": false, + "MD041": false, + "default": true +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..a36f8066 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,49 @@ +repos: + - repo: local + hooks: + # Prevent committing .rej files + - id: forbidden-files + name: forbidden files + entry: found Copier update rejection files; review them and remove them + language: fail + files: "\\.rej$" + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-json + - id: check-toml + - id: check-yaml + - id: end-of-file-fixer + - id: file-contents-sorter + files: .JuliaFormatter.toml + args: [--unique] + - id: mixed-line-ending + args: [--fix=lf] + - id: no-commit-to-branch + - id: pretty-format-json + args: [--autofix, --indent=2] + - id: trailing-whitespace + - id: check-merge-conflict + args: [--assume-in-merge] + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.41.0 + hooks: + - id: markdownlint-fix + - repo: https://github.com/citation-file-format/cffconvert + rev: 054bda51dbe278b3e86f27c890e3f3ac877d616c + hooks: + - id: validate-cff + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v4.0.0-alpha.8" # Use the sha or tag you want to point at + hooks: + - id: prettier + types_or: [yaml, json] + exclude: ".copier-answers.yml" + - repo: https://github.com/adrienverge/yamllint + rev: v1.35.1 + hooks: + - id: yamllint + - repo: https://github.com/domluna/JuliaFormatter.jl + rev: v1.0.56 + hooks: + - id: julia-formatter diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 00000000..5e16e5fb --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,2 @@ +rules: + indentation: { spaces: 2 } diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..927910c3 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +`tangi.migot@gmail.com`. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/README.md b/README.md index 32fc3d64..eeacc00a 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,34 @@ -# JSOSuite.jl - -[![docs-stable][docs-stable-img]][docs-stable-url] [![docs-dev][docs-dev-img]][docs-dev-url] [![build-ci][build-ci-img]][build-ci-url] [![codecov][codecov-img]][codecov-url] [![release][release-img]][release-url] - -[docs-stable-img]: https://img.shields.io/badge/docs-stable-blue.svg -[docs-stable-url]: https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/stable -[docs-dev-img]: https://img.shields.io/badge/docs-dev-purple.svg -[docs-dev-url]: https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/dev -[build-ci-img]: https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/workflows/CI/badge.svg?branch=main -[build-ci-url]: https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/actions -[codecov-img]: https://codecov.io/gh/JuliaSmoothOptimizers/JSOSuite.jl/branch/main/graph/badge.svg -[codecov-url]: https://codecov.io/gh/JuliaSmoothOptimizers/JSOSuite.jl -[release-img]: https://img.shields.io/github/v/release/JuliaSmoothOptimizers/JSOSuite.jl.svg?style=flat-square -[release-url]: https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/releases - -One stop solutions for all things optimization. +# JSOSuite + +[![Stable Documentation](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/stable) +[![In development documentation](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/dev) +[![Build Status](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/workflows/Test/badge.svg)](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/actions) +[![Test workflow status](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/actions/workflows/Test.yml/badge.svg?branch=main)](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/actions/workflows/Test.yml?query=branch%3Amain) +[![Lint workflow Status](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/actions/workflows/Lint.yml/badge.svg?branch=main)](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/actions/workflows/Lint.yml?query=branch%3Amain) +[![Docs workflow Status](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/actions/workflows/Docs.yml/badge.svg?branch=main)](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/actions/workflows/Docs.yml?query=branch%3Amain) +[![Build Status](https://api.cirrus-ci.com/github/JuliaSmoothOptimizers/JSOSuite.jl.svg)](https://cirrus-ci.com/github/JuliaSmoothOptimizers/JSOSuite.jl) +[![Coverage](https://codecov.io/gh/JuliaSmoothOptimizers/JSOSuite.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/JuliaSmoothOptimizers/JSOSuite.jl) +[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.12588054.svg)](https://doi.org/10.5281/zenodo.12588054) +[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md) +[![All Contributors](https://img.shields.io/github/all-contributors/JuliaSmoothOptimizers/JSOSuite.jl?labelColor=5e1ec7&color=c0ffee&style=flat-square)](#contributors) ## How to Cite -If you use JSOSuite.jl in your work, please cite using the format given in [CITATION.cff](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/blob/main/CITATION.cff). - -## Installation - -``` -] add JSOSuite -``` - -## Examples +If you use JSOSuite.jl in your work, please cite using the reference given in [CITATION.cff](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/blob/main/CITATION.cff). -```julia -using JSOSuite +## Contributing -# Rosenbrock -x0 = [-1.2; 1.0] -f = x -> 100 * (x[2] - x[1]^2)^2 + (x[1] - 1)^2 -stats = minimize(f, x0) +If you want to make contributions of any kind, please first that a look into our [contributing guide directly on GitHub](docs/src/90-contributing.md) or the [contributing page on the website](https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/dev/90-contributing/). -# Unconstrained problem in Float32 -stats = minimize(f, Float32.(x0)) +--- -# Constrained problem -c = x -> [x[1] + x[2] - 1] -stats = minimize(f, x0, c, [0.0], [0.0]) -``` +### Contributors -# Bug reports and discussions + + + -If you think you found a bug, feel free to open an [issue](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/issues). -Focused suggestions and requests can also be opened as issues. Before opening a pull request, start an issue or a discussion on the topic, please. + + -If you want to ask a question not suited for a bug report, feel free to start a discussion [here](https://github.com/JuliaSmoothOptimizers/Organization/discussions). This forum is for general discussion about this repository and the [JuliaSmoothOptimizers](https://github.com/JuliaSmoothOptimizers), so questions about any of our packages are welcome. + diff --git a/docs/Project.toml b/docs/Project.toml index ad403b5e..29d9bbcb 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -7,6 +7,7 @@ GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" JSOSolvers = "10dff2fc-5484-5881-a0e0-c90441020f8a" JSOSuite = "ed6ae0be-a024-11e9-2788-05dbf8cd15d9" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" +LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" NLPModels = "a4795742-8479-5a88-8948-cc11e1c8c1a6" NLPModelsIpopt = "f4238b75-b362-5c4c-b852-0801c9a21d71" diff --git a/docs/make.jl b/docs/make.jl index f2e3c707..10222841 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,28 +1,37 @@ -using Documenter, JSOSuite +using JSOSuite +using Documenter -makedocs( +DocMeta.setdocmeta!(JSOSuite, :DocTestSetup, :(using JSOSuite); recursive = true) + +const page_rename = Dict("developer.md" => "Developer docs") # Without the numbers + +function nice_name(file) + file = replace(file, r"^[0-9]*-" => "") + if haskey(page_rename, file) + return page_rename[file] + end + return splitext(file)[1] |> x -> replace(x, "-" => " ") |> titlecase +end + +makedocs(; modules = [JSOSuite], doctest = true, - linkcheck = false, - format = Documenter.HTML( + linkcheck = false, # Rely on Lint.yml/lychee for the links + authors = "Tangi Migot and contributors", + repo = "https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/blob/{commit}{path}#{line}", + sitename = "JSOSuite.jl", + format = Documenter.HTML(; + prettyurls = true, + canonical = "https://JuliaSmoothOptimizers.github.io/JSOSuite.jl", assets = ["assets/style.css"], - prettyurls = get(ENV, "CI", nothing) == "true", ), - sitename = "JSOSuite.jl", pages = [ - "Home" => "index.md", - "Tutorial" => "tutorial.md", - "Nonlinear Least Squares" => "nls.md", - "Quadratic models with linear constraints" => "qp.md", - "Re-solve and in-place solve" => "resolve.md", - "Benchmarking" => "benchmark.md", - "Speed up Solvers Tips" => "speed-up.md", - "Reference" => "reference.md", + "Home" => "index.md" + [ + nice_name(file) => file for + file in readdir(joinpath(@__DIR__, "src")) if file != "index.md" && splitext(file)[2] == ".md" + ] ], ) -deploydocs( - repo = "github.com/JuliaSmoothOptimizers/JSOSuite.jl.git", - push_preview = true, - devbranch = "main", -) +deploydocs(; repo = "github.com/JuliaSmoothOptimizers/JSOSuite.jl", push_preview = true) diff --git a/docs/src/tutorial.md b/docs/src/10-tutorial.md similarity index 96% rename from docs/src/tutorial.md rename to docs/src/10-tutorial.md index 275fc8ba..23923680 100644 --- a/docs/src/tutorial.md +++ b/docs/src/10-tutorial.md @@ -18,6 +18,7 @@ All these optimizers rely on the `NLPModel API` from [NLPModels.jl](https://gith ``` The function `minimize` accepts as an argument any model `nlp` subtype of `AbstractNLPModel`. + ```julia output = minimize(nlpmodel::AbstractNLPModel; kwargs...) ``` @@ -42,7 +43,7 @@ We refer to [`JuMP tutorial`](https://jump.dev/JuMP.jl/stable/) for more on mode ### NLPModel with Automatic Differentiation -We refer to [`ADNLPModel`](https://jso.dev/ADNLPModels.jl/dev/reference/#ADNLPModels.ADNLPModel-Union{Tuple{S},%20Tuple{Any,%20S}}%20where%20S) for the description of the different constructors. +We refer to [`ADNLPModel`](https://jso.dev/ADNLPModels.jl/dev/reference/) for the description of the different constructors. #### Unconstrained @@ -61,7 +62,7 @@ nlp = ADNLPModel(f, x0) stats = minimize(nlp) ``` -One of the main advantages of this constructor is the possibility to run computations in different arithmetics. +One of the main advantages of this constructor is the possibility to run computations in different arithmetics. ```@example using JSOSuite @@ -139,6 +140,7 @@ JSOSuite.optimizers ``` Required information can be extracted by simple `DataFrame` manipulations. For instance, the list of optimizers handled by this package + ```@example ex1 JSOSuite.optimizers.name ``` @@ -146,6 +148,7 @@ JSOSuite.optimizers.name ### Select optimizers The function [`JSOSuite.select_optimizers`](@ref) returns a list of compatible optimizers. + ```@example using ADNLPModels, JSOSuite f = x -> 100 * (x[2] - x[1]^2)^2 + (x[1] - 1)^2 diff --git a/docs/src/nls.md b/docs/src/20-nls.md similarity index 94% rename from docs/src/nls.md rename to docs/src/20-nls.md index 9dc26990..2e492fa3 100644 --- a/docs/src/nls.md +++ b/docs/src/20-nls.md @@ -16,19 +16,21 @@ Although the problem can be solved using only ``f``, knowing ``F`` independent ## Model and solve NLS In this tutorial, we consider the following equality-constrained problem + ```math \begin{aligned} \min \quad & f(x):=\tfrac{1}{2}(10 * (x[2] - x[1]^2))^2 + \tfrac{1}{2}(x[1] - 1)^2 \\ & 1 \leq x[1] * x[2] \leq 1, \end{aligned} ``` + where ``1 \leq x[1] x[2] \leq 1`` implies that ``x[1] x[2] = 1``. In the rest of this tutorial, we will see two ways to model this problem exploiting the knowledge of the structure of the problem. ### NLS using automatic differentiation -Using the package [ADNLPModels.jl](https://github.com/JuliaSmoothOptimizers/ADNLPModels.jl]), the problem can be model as an `ADNLSModel` which will use automatic-differentiation to compute the derivatives. +Using the package [ADNLPModels.jl](https://github.com/JuliaSmoothOptimizers/ADNLPModels.jl), the problem can be model as an `ADNLSModel` which will use automatic-differentiation to compute the derivatives. ```@example ex1 using ADNLPModels, JSOSuite @@ -39,6 +41,7 @@ c = x -> [x[1] * x[2]] l = [1.] nls = ADNLSModel(F, x0, nres, c, l, l, name="AD-Rosenbrock") ``` + Note that the length of the residual function is given explictly to avoid any superfluous evaluation of this (potentially very large) function. ```@example ex1 @@ -81,7 +84,7 @@ stats = minimize(nls) ## Find a feasible point of an optimization problem or solve a nonlinear system -We show here how to find the feasible point of a given model. +We show here how to find the feasible point of a given model. ```math \begin{aligned} diff --git a/docs/src/qp.md b/docs/src/30-qp.md similarity index 99% rename from docs/src/qp.md rename to docs/src/30-qp.md index 58b61b07..c19e5c0b 100644 --- a/docs/src/qp.md +++ b/docs/src/30-qp.md @@ -10,7 +10,7 @@ The quadratic model with linear constraints is another specific case where the o \end{aligned} ``` -This problem is convex whenever the matrix `Q` is positive semi-definite. A key aspect here is the modeling of the matrices `Q` and `A`. +This problem is convex whenever the matrix `Q` is positive semi-definite. A key aspect here is the modeling of the matrices `Q` and `A`. The main data structure available in Julia are: `LinearAlgebra.Matrix`, `SparseArrays.sparse`, `SparseMatricesCOO.sparse`, `LinearOperators.LinearOperator`. In JuliaSmoothOptimizers, the package [`QuadraticModels.jl`](https://github.com/JuliaSmoothOptimizers/QuadraticModels.jl) can be used to access the `NLPModel API` for such instance. diff --git a/docs/src/resolve.md b/docs/src/40-resolve.md similarity index 98% rename from docs/src/resolve.md rename to docs/src/40-resolve.md index 76ebd6cc..43426758 100644 --- a/docs/src/resolve.md +++ b/docs/src/40-resolve.md @@ -3,22 +3,27 @@ It is very convenient to pre-allocate the memory used during the optimization of a given problem either for improved memory management or re-solving the same or a similar problem. Let us consider the following 2-dimensional unconstrained problem + ```math \begin{aligned} -\min_x \quad & f(x):= x_2^2 \exp(x_1^2) +\min_x \quad & f(x):= x_2^2 \exp(x_1^2) \end{aligned} ``` + Using `JSOSuite`’s `minimize` function, the problem can be solved as follows + ```@example ex1 using JSOSuite f(x) = x[2]^2 * exp(x[1]^2) stats = minimize(f, ones(2)) ; ``` + Using L-BFGS, the problem is locally solved. Note that when passing Julia functions as input to `minimize`, the problem is modeled as an [`ADNLPModel`](https://github.com/JuliaSmoothOptimizers/ADNLPModels.jl). So, the following would be equivalent: + ```@example ex2 using ADNLPModels, JSOSuite f(x) = x[2]^2 * exp(x[1]^2) @@ -27,6 +32,7 @@ stats = minimize(nlp) ``` The procedure is similar with `JuMP` models. + ```@example 3 using JuMP, JSOSuite model = Model() @@ -38,6 +44,7 @@ stats = minimize(model) ## In-place solve If we want to solve the same problem several times, for instance, for several initial guesses, it is recommended to use an in-place solve. + ```@example ex1 using ADNLPModels, JSOSolvers, SolverCore f(x) = x[2]^2 * exp(x[1]^2) @@ -46,14 +53,18 @@ solver = JSOSolvers.LBFGSSolver(nlp) stats = SolverCore.GenericExecutionStats(nlp) solve!(solver, nlp, stats, x = ones(2)) ``` + This deserves more explanations. The name of the solver structure and the corresponding package can be accessed via the DataFrame `JSOSuite.optimizers`. + ```@example ex1 JSOSuite.optimizers[!, [:name_solver, :name_pkg]] ``` + In our example, the solver L-BFGS is implemented in [`JSOSolvers.jl`](https://github.com/JuliaSmoothOptimizers/JSOSolvers.jl) and the solver structure is `LBFGSSolver`. Now, it is possible to reuse the memory allocated for the first solve for another round: + ```@example ex1 # NLPModels.reset!(nlp) # would also reset the evaluation counters of the model SolverCore.reset!(solver) @@ -64,6 +75,7 @@ solve!(solver, nlp, stats, x = new_x0) # new solve with existing solver object ## In-place solve of a different problem It is also possible to reuse the allocated memory to solve another problem with the same number of variables and constraints: + ```@example ex1 f2(x) = x[2]^2 + exp(x[1]^2) nlp = ADNLPModel(f2, ones(2)) # or use JuMP @@ -74,6 +86,7 @@ solve!(solver, nlp, stats) ## Allocation-free solvers In order to measure, the amount of memory allocated by the solvers, the package [`NLPModelsTest.jl`](https://github.com/JuliaSmoothOptimizers/NLPModelsTest.jl) defines a set of test problems that are allocation free. + ```@example ex1 using NLPModelsTest, SolverCore, JSOSolvers nlp = BROWNDEN(Float64) @@ -82,4 +95,5 @@ stats = GenericExecutionStats(nlp) solve!(solver, nlp, stats) @allocated solve!(solver, nlp, stats) ``` + Several of the pure Julia solvers available in JSOSuite have this property. diff --git a/docs/src/benchmark.md b/docs/src/50-benchmark.md similarity index 96% rename from docs/src/benchmark.md rename to docs/src/50-benchmark.md index 579dc0e3..1d4ffbb7 100644 --- a/docs/src/benchmark.md +++ b/docs/src/50-benchmark.md @@ -5,6 +5,7 @@ Benchmarking is very important when researching new algorithms or selecting the The package [`SolverBenchmark`](https://github.com/JuliaSmoothOptimizers/SolverBenchmark.jl) exports the function [`bmark_solvers`](https://github.com/JuliaSmoothOptimizers/SolverBenchmark.jl/blob/main/src/bmark_solvers.jl) that runs a set of optimizers on a set of problems. `JSOSuite.jl` specialize this function, see `bmark_solvers`. The [JuliaSmoothOptimizers organization](https://jso.dev) contains several packages of test problems ready to use for benchmarking. The main ones are + - [`OptimizationProblems.jl`](https://github.com/JuliaSmoothOptimizers/OptimizationProblems.jl): This package provides a collection of optimization problems in JuMP and ADNLPModels syntax; - [`CUTEst.jl`](https://github.com/JuliaSmoothOptimizers/CUTEst.jl); - [`NLSProblems.jl`](https://github.com/JuliaSmoothOptimizers/NLSProblems.jl). @@ -27,7 +28,7 @@ selected_meta = selected_meta[.!selected_meta.has_bounds .&& (selected_meta.ncon list = selected_meta[!, :name] ``` -Then, we generate the list of problems using [`ADNLPModel`](https://jso.dev/ADNLPModels.jl/dev/reference/#ADNLPModels.ADNLPModel-Union{Tuple{S},%20Tuple{Any,%20S}}%20where%20S). +Then, we generate the list of problems using [`ADNLPModel`](https://jso.dev/ADNLPModels.jl/dev/reference/). ```@example op ad_problems = [ @@ -47,11 +48,12 @@ selected_optimizers[selected_optimizers.is_available, :] # optimizers available ``` For the purpose of this example, we will consider 3 optimizers. + ```@example op select = ["IPOPT", "TRUNK", "LBFGS"] ``` -Once the problems and optimizers are chosen, the function `bmark_solvers` runs the benchmark. +Once the problems and optimizers are chosen, the function `bmark_solvers` runs the benchmark. ```@example op using SolverBenchmark diff --git a/docs/src/speed-up.md b/docs/src/60-speed-up.md similarity index 91% rename from docs/src/speed-up.md rename to docs/src/60-speed-up.md index 2935db1d..eb119d21 100644 --- a/docs/src/speed-up.md +++ b/docs/src/60-speed-up.md @@ -5,6 +5,7 @@ The following contains a list of tips to speed up the solver selection and usage ## Derivatives The optimizers available in `JSOSuite.jl` are all using first and sometines second-order derivatives. There are mainly three categories: + - 1st order methods use only gradient information; - 1st order quasi-Newton methods require only gradient information, and uses it to build an approximation of the Hessian; - 2nd order methods: Those are using gradients and Hessian information. @@ -24,10 +25,10 @@ This classification is straightforwardly extended to handling constraints with t ## Find a better initial guess -The majority of derivative-based optimizers are local methods whose performance are dependent of the initial guess. +The majority of derivative-based optimizers are local methods whose performance are dependent of the initial guess. This usually relies on specific knowledge of the problem. -The function [`feasible_point`](@ref) computes a point satisfying the constraints of the problem that can be used as an initial guess. +The function [`feasible_point`](@ref) computes a point satisfying the constraints of the problem that can be used as an initial guess. An alternative is to solve a simpler version of the problem and reuse the solution as an initial guess for the more complex one. ## Use the structure of the problem @@ -45,20 +46,20 @@ Note that all optimizers presented here have been carefully optimized. All have ### Unconstrained -##### LBFGS (1st order) +#### LBFGS (1st order) - `mem::Int = 5`: memory parameter of the `lbfgs` algorithm; - `τ₁::T = T(0.9999)`: slope factor in the Wolfe condition when performing the line search; - `bk_max:: Int = 25`: maximum number of backtracks when performing the line search. -##### R2 (1st order) +#### R2 (1st order) - `η1 = eps(T)^(1/4)`, `η2 = T(0.95)`: step acceptance parameters; - `γ1 = T(1/2)`, `γ2 = 1/γ1`: regularization update parameters; - `σmin = eps(T)`: step parameter for R2 algorithm; - `β = T(0) ∈ [0,1]` is the constant in the momentum term. If `β == 0`, R2 does not use momentum. -##### TRUNK (matrix-free) +#### TRUNK (matrix-free) - `bk_max::Int = 10`: algorithm parameter; - `monotone::Bool = true`: algorithm parameter; @@ -66,7 +67,7 @@ Note that all optimizers presented here have been carefully optimized. All have ### Bound-constrained (matrix-free) -##### TRON +#### TRON - `μ₀::T = T(1e-2)`: algorithm parameter in (0, 0.5); - `μ₁::T = one(T)`: algorithm parameter in (0, +∞); @@ -76,27 +77,27 @@ Note that all optimizers presented here have been carefully optimized. All have ### Constrained -##### RipQP (quadratic with linear constraints) +#### RipQP (quadratic with linear constraints) See [RipQP.jl tutorial](https://jso.dev/tutorials/introduction-to-ripqp/) and [RipQP.jl API](https://jso.dev/RipQP.jl/stable/API/). -##### CaNNOLeS (NLS with nonlinear equality constraints) +#### CaNNOLeS (NLS with nonlinear equality constraints) - `linsolve::Symbol = :ma57`: solver to compute LDLt factorization. Available methods are: `:ma57`, `:ldlfactorizations`; - `method::Symbol = :Newton`: available methods `:Newton, :LM, :Newton_noFHess`, and `:Newton_vanishing`; See [CaNNOLeS.jl tutorial](https://jso.dev/CaNNOLeS.jl/dev/tutorial/). -##### DCISolver (nonlinear equality constraints) +#### DCISolver (nonlinear equality constraints) - `linear_solver = :ldlfact`: Solver for the factorization. options: `:ma57` if `HSL.jl` available. See the [`fine-tuneDCI tutorial`](https://jso.dev/DCISolver.jl/dev/fine-tuneDCI/). -##### FletcherPenaltySolver (nonlinear equality constraints) +#### FletcherPenaltySolver (nonlinear equality constraints) See the [`fine-tuneFPS tutorial`](https://jso.dev/FletcherPenaltySolver.jl/dev/fine-tuneFPS/). -##### Percival +#### Percival - `μ::Real = T(10.0)`: Starting value of the penalty parameter. diff --git a/docs/src/90-contributing.md b/docs/src/90-contributing.md new file mode 100644 index 00000000..0e22597a --- /dev/null +++ b/docs/src/90-contributing.md @@ -0,0 +1,25 @@ +# [Contributing guidelines](@id contributing) + +First of all, thanks for the interest! + +We welcome all kinds of contribution, including, but not limited to code, documentation, examples, configuration, issue creating, etc. + +Be polite and respectful, and follow the code of conduct. + +## Bug reports and discussions + +If you think you found a bug, feel free to open an [issue](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/issues). +Focused suggestions and requests can also be opened as issues. +Before opening a pull request, start an issue or a discussion on the topic, please. + +## Working on an issue + +If you found an issue that interests you, comment on that issue what your plans are. +If the solution to the issue is clear, you can immediately create a pull request (see below). +Otherwise, say what your proposed solution is and wait for a discussion around it. + +!!! tip + Feel free to ping us after a few days if there are no responses. + +If your solution involves code (or something that requires running the package locally), check the [developer documentation](91-developer.md). +Otherwise, you can use the GitHub interface directly to create your pull request. diff --git a/docs/src/91-developer.md b/docs/src/91-developer.md new file mode 100644 index 00000000..47b05b07 --- /dev/null +++ b/docs/src/91-developer.md @@ -0,0 +1,163 @@ +# [Developer documentation](@id dev_docs) + +!!! note "Contributing guidelines" + If you haven't, please read the [Contributing guidelines](90-contributing.md) first. + +If you want to make contributions to this package that involves code, then this guide is for you. + +## First time clone + +!!! tip "If you have writing rights" + If you have writing rights, you don't have to fork. Instead, simply clone and skip ahead. Whenever **upstream** is mentioned, use **origin** instead. + +If this is the first time you work with this repository, follow the instructions below to clone the repository. + +1. Fork this repo +2. Clone your repo (this will create a `git remote` called `origin`) +3. Add this repo as a remote: + + ```bash + git remote add upstream https://github.com/JuliaSmoothOptimizers/JSOSuite.jl + ``` + +This will ensure that you have two remotes in your git: `origin` and `upstream`. +You will create branches and push to `origin`, and you will fetch and update your local `main` branch from `upstream`. + +## Linting and formatting + +Install a plugin on your editor to use [EditorConfig](https://editorconfig.org). +This will ensure that your editor is configured with important formatting settings. + +We use [https://pre-commit.com](https://pre-commit.com) to run the linters and formatters. +In particular, the Julia code is formatted using [JuliaFormatter.jl](https://github.com/domluna/JuliaFormatter.jl), so please install it globally first: + +```julia-repl +julia> # Press ] +pkg> activate +pkg> add JuliaFormatter +``` + +To install `pre-commit`, we recommend using [pipx](https://pipx.pypa.io) as follows: + +```bash +# Install pipx following the link +pipx install pre-commit +``` + +With `pre-commit` installed, activate it as a pre-commit hook: + +```bash +pre-commit install +``` + +To run the linting and formatting manually, enter the command below: + +```bash +pre-commit run -a +``` + +**Now, you can only commit if all the pre-commit tests pass**. + +## Testing + +As with most Julia packages, you can just open Julia in the repository folder, activate the environment, and run `test`: + +```julia-repl +julia> # press ] +pkg> activate . +pkg> test +``` + +## Working on a new issue + +We try to keep a linear history in this repo, so it is important to keep your branches up-to-date. + +1. Fetch from the remote and fast-forward your local main + + ```bash + git fetch upstream + git switch main + git merge --ff-only upstream/main + ``` + +2. Branch from `main` to address the issue (see below for naming) + + ```bash + git switch -c 42-add-answer-universe + ``` + +3. Push the new local branch to your personal remote repository + + ```bash + git push -u origin 42-add-answer-universe + ``` + +4. Create a pull request to merge your remote branch into the org main. + +### Branch naming + +- If there is an associated issue, add the issue number. +- If there is no associated issue, **and the changes are small**, add a prefix such as "typo", "hotfix", "small-refactor", according to the type of update. +- If the changes are not small and there is no associated issue, then create the issue first, so we can properly discuss the changes. +- Use dash separated imperative wording related to the issue (e.g., `14-add-tests`, `15-fix-model`, `16-remove-obsolete-files`). + +### Commit message + +- Use imperative or present tense, for instance: *Add feature* or *Fix bug*. +- Have informative titles. +- When necessary, add a body with details. +- If there are breaking changes, add the information to the commit message. + +### Before creating a pull request + +!!! tip "Atomic git commits" + Try to create "atomic git commits" (recommended reading: [The Utopic Git History](https://blog.esciencecenter.nl/the-utopic-git-history-d44b81c09593)). + +- Make sure the tests pass. +- Make sure the pre-commit tests pass. +- Fetch any `main` updates from upstream and rebase your branch, if necessary: + + ```bash + git fetch upstream + git rebase upstream/main BRANCH_NAME + ``` + +- Then you can open a pull request and work with the reviewer to address any issues. + +## Building and viewing the documentation locally + +Following the latest suggestions, we recommend using `LiveServer` to build the documentation. +Here is how you do it: + +1. Run `julia --project=docs` to open Julia in the environment of the docs. +1. If this is the first time building the docs + 1. Press `]` to enter `pkg` mode + 1. Run `pkg> dev .` to use the development version of your package + 1. Press backspace to leave `pkg` mode +1. Run `julia> using LiveServer` +1. Run `julia> servedocs()` + +## Making a new release + +To create a new release, you can follow these simple steps: + +- Create a branch `release-x.y.z` +- Update `version` in `Project.toml` +- Update the `CHANGELOG.md`: + - Rename the section "Unreleased" to "[x.y.z] - yyyy-mm-dd" (i.e., version under brackets, dash, and date in ISO format) + - Add a new section on top of it named "Unreleased" + - Add a new link in the bottom for version "x.y.z" + - Change the "[unreleased]" link to use the latest version - end of line, `vx.y.z ... HEAD`. +- Create a commit "Release vx.y.z", push, create a PR, wait for it to pass, merge the PR. +- Go back to main screen and click on the latest commit (link: ) +- At the bottom, write `@JuliaRegistrator register` + +After that, you only need to wait and verify: + +- Wait for the bot to comment (should take < 1m) with a link to a RP to the registry +- Follow the link and wait for a comment on the auto-merge +- The comment should said all is well and auto-merge should occur shortly +- After the merge happens, TagBot will trigger and create a new GitHub tag. Check on +- After the release is create, a "docs" GitHub action will start for the tag. +- After it passes, a deploy action will run. +- After that runs, the [stable docs](https://JuliaSmoothOptimizers.github.io/JSOSuite.jl/stable) should be updated. Check them and look for the version number. diff --git a/docs/src/95-reference.md b/docs/src/95-reference.md new file mode 100644 index 00000000..b1069f28 --- /dev/null +++ b/docs/src/95-reference.md @@ -0,0 +1,17 @@ +# [Reference](@id reference) + +## Contents + +```@contents +Pages = ["95-reference.md"] +``` + +## Index + +```@index +Pages = ["95-reference.md"] +``` + +```@autodocs +Modules = [JSOSuite] +``` diff --git a/docs/src/assets/style.css b/docs/src/assets/style.css index 7f1fab0d..f2cf50df 100644 --- a/docs/src/assets/style.css +++ b/docs/src/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/src/index.md b/docs/src/index.md index f1fc2e72..c275c463 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,4 +1,8 @@ -# JSOSuite.jl +```@meta +CurrentModule = JSOSuite +``` + +# JSOSuite `JSOSuite` is a unique solution to access all the solvers available in the [JuliaSmoothOptimizers](https://github.com/JuliaSmoothOptimizers) organization. @@ -13,14 +17,26 @@ All these solvers rely on the `NLPModel API` from [NLPModels.jl](https://github. \end{aligned} ``` -The package `JSOSuite` exports a function [`minimize`](@ref): +## Installation + +```julia-repl +julia> # Press ] +pkg> add JSOSuite ``` + +## Usage + +The package `JSOSuite` exports a function [`minimize`](@ref): + +```julia output = minimize(args...; kwargs...) ``` + where the arguments define the problem, see [Tutorial](@ref tutorial-section). It is also possible to define an `NLPModel` or a `JuMP` model representing the problem, and then call `minimize`: -``` + +```julia output = minimize(nlpmodel; kwargs...) output = minimize(jump; kwargs...) ``` @@ -32,6 +48,7 @@ The `NLPModel API` is a general API for solvers to interact with models by provi JuliaSmoothOptimizers' compliant solvers accept any model compatible with the `NLPModel API`. See the [Tutorial](@ref tutorial-section) section for examples. Depending on the origin of the problem several modeling tools are available. The following generic modeling tools are accepted: + - `JuMP` models are internally made compatible with NLPModel via [NLPModelsJuMP.jl](https://github.com/JuliaSmoothOptimizers/NLPModelsJuMP.jl); - `Ampl` models stored in a `.nl` file can be instantiated with `AmplModel("name_of_file.nl")` using [AmplNLReader.jl](https://github.com/JuliaSmoothOptimizers/AmplNLReader.jl); - [QPSReader.jl](https://github.com/JuliaSmoothOptimizers/QPSReader.jl) reads linear problems in MPS format and quadratic problems in QPS format; @@ -39,6 +56,7 @@ Depending on the origin of the problem several modeling tools are available. The - Models with manually input derivatives can be defined using [ManualNLPModels.jl](https://github.com/JuliaSmoothOptimizers/ManualNLPModels.jl). It is also possible to define your `NLPModel` variant. Several examples are available within JuliaSmoothOptimizers' umbrella: + - [KnetNLPModels.jl](https://github.com/JuliaSmoothOptimizers/KnetNLPModels.jl): An NLPModels Interface to Knet. - [PDENLPModels.jl](https://github.com/JuliaSmoothOptimizers/PDENLPModels.jl): A NLPModel API for optimization problems with PDE-constraints. @@ -51,6 +69,7 @@ See the [Nonlinear Least Squares](@ref nls-section) for more on the special trea The value returned is a [`GenericExecutionStats`](https://jso.dev/SolverCore.jl/dev/reference/#SolverCore.GenericExecutionStats), which is a structure containing the available information at the end of the execution, such as a solver status, the objective function value, the norm of the residuals, the elapsed time, etc. It contains the following fields: + - `status`: Indicates the output of the solver. Use `show_statuses()` for the full list; - `solution`: The final approximation returned by the solver (default: an uninitialized vector like `nlp.meta.x0`); - `objective`: The objective value at `solution` (default: `Inf`); @@ -64,6 +83,7 @@ It contains the following fields: - `solver_specific::Dict{Symbol,Any}`: A solver specific dictionary. The list of statuses is available via the function `SolverCore.show_statuses`: + ```@example using SolverCore show_statuses() @@ -94,20 +114,15 @@ The following are specific to nonlinear least squares: Further possible options are documented in each solver's documentation. -## Installation +## Contributors -``` -] add JSOSuite -``` +```@raw html + + + -## Table of Contents + + -```@contents + ``` - -# Bug reports and discussions - -If you think you found a bug, feel free to open an [issue](https://github.com/JuliaSmoothOptimizers/JSOSuite.jl/issues). -Focused suggestions and requests can also be opened as issues. Before opening a pull request, start an issue or a discussion on the topic, please. - -If you want to ask a question not suited for a bug report, feel free to start a discussion [here](https://github.com/JuliaSmoothOptimizers/Organization/discussions). This forum is for general discussion about this repository and the [JuliaSmoothOptimizers](https://github.com/JuliaSmoothOptimizers), so questions about any of our packages are welcome. diff --git a/docs/src/reference.md b/docs/src/reference.md deleted file mode 100644 index 00cca182..00000000 --- a/docs/src/reference.md +++ /dev/null @@ -1,17 +0,0 @@ -# Reference -​ -## Contents -​ -```@contents -Pages = ["reference.md"] -``` -​ -## Index -​ -```@index -Pages = ["reference.md"] -``` -​ -```@autodocs -Modules = [JSOSuite] -``` \ No newline at end of file diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 00000000..9f2a9ee2 --- /dev/null +++ b/lychee.toml @@ -0,0 +1,7 @@ +exclude = [ + "@ref" +] + +exclude_path = [ + "docs/build" +] diff --git a/src/multi-start.jl b/src/multi-start.jl index 91bd9319..037d7f8b 100644 --- a/src/multi-start.jl +++ b/src/multi-start.jl @@ -38,7 +38,7 @@ function multi_start( best_x = get_x0(nlp) dom = Vector{RealInterval{Float64}}(undef, get_nvar(nlp)) new_x0, best_x = S(undef, get_nvar(nlp)), S(undef, get_nvar(nlp)) - for i = 1:get_nvar(nlp) + for i in 1:get_nvar(nlp) dom[i] = RealInterval(nlp.meta.lvar[i], nlp.meta.uvar[i]) end new_x0 .= get_x0(nlp) @@ -81,7 +81,7 @@ function multi_start( kwargs..., ) - for i = 1:N + for i in 1:N get_next_x0!(Val(strategy), new_x0, i, dom, best_x) el_time = time() - start_time best_obj = run_solver!( @@ -111,7 +111,7 @@ function run_solver!( kwargs..., ) for solver_name in solvers - stats = minimize(solver_name, nlp, x = new_x0, verbose = solver_verbose; kwargs...) + stats = minimize(solver_name, nlp; x = new_x0, verbose = solver_verbose, kwargs...) if (stats.status == :first_order) && (stats.objective < best_obj) best_obj = stats.objective best_x .= stats.solution @@ -132,7 +132,7 @@ function run_solver!( max_time; kwargs..., ) - stats = minimize(solver_name, nlp, x = new_x0, verbose = solver_verbose; kwargs...) + stats = minimize(solver_name, nlp; x = new_x0, verbose = solver_verbose, kwargs...) if (stats.status == :first_order) && (stats.objective < best_obj) best_obj = stats.objective best_x .= stats.solution @@ -147,7 +147,7 @@ function Random.rand!( dom::Vector{RealInterval{T}}, ) where {T} # check that length(next_x0) == length(dom) - for i = 1:length(next_x0) + for i in 1:length(next_x0) next_x0[i] = rand(rng, dom[i]) end return next_x0 diff --git a/src/optimizers.jl b/src/optimizers.jl index cb1042cb..bd730a75 100644 --- a/src/optimizers.jl +++ b/src/optimizers.jl @@ -19,7 +19,7 @@ For each solver, the following are available: - `double_precision_only::Bool`: `true` if the solver only handles double precision (`Float64`); - `highest_derivative::Int`: order of the highest derivative used by the algorithm. """ -optimizers = DataFrame( +optimizers = DataFrame(; name = String[], name_solver = Symbol[], name_pkg = String[], diff --git a/src/solve-model.jl b/src/solve-model.jl index c707e0bb..dd73fa28 100644 --- a/src/solve-model.jl +++ b/src/solve-model.jl @@ -182,7 +182,7 @@ function QuadraticModel( x0 = fill!(S(undef, length(c)), zero(T)), name::String = "Generic", ) where {T, S <: AbstractVector{T}} - return QuadraticModel(c, H, lvar = lvar, uvar = uvar, c0 = c0, x0 = x0, name = name) + return QuadraticModel(c, H; lvar = lvar, uvar = uvar, c0 = c0, x0 = x0, name = name) end function QuadraticModel( @@ -195,7 +195,7 @@ function QuadraticModel( x0 = fill!(S(undef, length(c)), zero(T)), name::String = "Generic", ) where {T, S <: AbstractVector{T}} - return QuadraticModel(c, H, A = A, lcon = lcon, ucon = ucon, c0 = c0, x0 = x0, name = name) + return QuadraticModel(c, H; A = A, lcon = lcon, ucon = ucon, c0 = c0, x0 = x0, name = name) end function QuadraticModel( @@ -212,7 +212,7 @@ function QuadraticModel( ) where {T, S <: AbstractVector{T}} return QuadraticModel( c, - H, + H; A = A, lcon = lcon, ucon = ucon, diff --git a/src/solvers/ripqp_solve.jl b/src/solvers/ripqp_solve.jl index b9c41059..18cf917d 100644 --- a/src/solvers/ripqp_solve.jl +++ b/src/solvers/ripqp_solve.jl @@ -16,7 +16,7 @@ function minimize( delete!(keywords, :atol) delete!(keywords, :rtol) RipQP.InputTol( - T0, + T0; ϵ_pdd = ϵ_pdd, ϵ_rb = ϵ_rb, ϵ_rc = ϵ_rc, @@ -28,7 +28,7 @@ function minimize( ϵ_rb = ϵ_rc = T0(keywords[:atol]) delete!(keywords, :atol) RipQP.InputTol( - T0, + T0; ϵ_pdd = ϵ_pdd, ϵ_rb = ϵ_rb, ϵ_rc = ϵ_rc, @@ -40,7 +40,7 @@ function minimize( ϵ_rb = ϵ_rc = T0(keywords[:atol]) delete!(keywords, :rtol) RipQP.InputTol( - T0, + T0; ϵ_pdd = ϵ_pdd, ϵ_rb = ϵ_rb, ϵ_rc = ϵ_rc, diff --git a/test/multi-start-test.jl b/test/multi-start-test.jl index c1fe9f77..d56f6b1f 100644 --- a/test/multi-start-test.jl +++ b/test/multi-start-test.jl @@ -2,25 +2,25 @@ using ADNLPModels, NLPModels, NLPModelsTest, JSOSuite, LinearAlgebra @info "Test 1" nlp = BROWNDEN() -JSOSuite.multi_start(nlp, verbose = 1) +JSOSuite.multi_start(nlp; verbose = 1) # Test 2 d = 5 function f(x; d = d) - return sum(x[i]^2 / 4000 - prod(cos(x[i] / sqrt(i)) for i = 1:d) + 1 for i = 1:d) + return sum(x[i]^2 / 4000 - prod(cos(x[i] / sqrt(i)) for i in 1:d) + 1 for i in 1:d) end T = Float64 @info "Test 2" nlp = ADNLPModel(f, 300 * ones(T, d), -600 * ones(T, d), 600 * ones(T, d)) -ultimate_x = JSOSuite.multi_start(nlp, N = 50, verbose = 10) +ultimate_x = JSOSuite.multi_start(nlp; N = 50, verbose = 10) norm(grad(nlp, ultimate_x)), obj(nlp, ultimate_x) @info "Test 3" nlp = ADNLPModel(f, 300 * ones(T, d)) ultimate_x = JSOSuite.multi_start( - nlp, + nlp; N = 10, verbose = 1, solver_verbose = 0, diff --git a/test/qp_tests.jl b/test/qp_tests.jl index bcb861e0..40a1f1e9 100644 --- a/test/qp_tests.jl +++ b/test/qp_tests.jl @@ -7,12 +7,12 @@ H = sparse(Hrows, Hcols, Hvals) c0 = 1.0 x0 = [-1.2; 1.0] - qp_model = QuadraticModel(c, H, c0 = c0, x0 = x0, name = "uncqp_QP") + qp_model = QuadraticModel(c, H; c0 = c0, x0 = x0, name = "uncqp_QP") stats = minimize(qp_model) @test true - minimize(c, H, c0 = c0, x0 = x0, name = "uncqp_QP") + minimize(c, H; c0 = c0, x0 = x0, name = "uncqp_QP") @test true - minimize("RipQP", c, H, c0 = c0, x0 = x0, name = "uncqp_QP") + minimize("RipQP", c, H; c0 = c0, x0 = x0, name = "uncqp_QP") @test true end @@ -22,12 +22,12 @@ uvar = [1.0; 1.0] lvar = [0.0; 0.0] x0 = [0.5; 0.5] - qp_model = QuadraticModel(c, H, lvar, uvar, x0 = x0, name = "bndqp_QP") + qp_model = QuadraticModel(c, H, lvar, uvar; x0 = x0, name = "bndqp_QP") stats = minimize(qp_model) @test true - minimize(c, H, lvar, uvar, x0 = x0, name = "bndqp_QP") + minimize(c, H, lvar, uvar; x0 = x0, name = "bndqp_QP") @test true - minimize("RipQP", c, H, lvar, uvar, x0 = x0, name = "bndqp_QP") + minimize("RipQP", c, H, lvar, uvar; x0 = x0, name = "bndqp_QP") @test true end @@ -39,12 +39,12 @@ A = ones(1, n) lcon = [1.0] ucon = [1.0] - qp_model = QuadraticModel(c, H, A, lcon, ucon, name = "eqconqp_QP") + qp_model = QuadraticModel(c, H, A, lcon, ucon; name = "eqconqp_QP") stats = minimize(qp_model) @test true - minimize(c, H, A, lcon, ucon, name = "eqconqp_QP") + minimize(c, H, A, lcon, ucon; name = "eqconqp_QP") @test true - minimize("RipQP", c, H, A, lcon, ucon, name = "eqconqp_QP") + minimize("RipQP", c, H, A, lcon, ucon; name = "eqconqp_QP") @test true end @@ -62,12 +62,12 @@ lcon = [0.0; -Inf; -1.0] ucon = [Inf; 0.0; 1.0] x0 = ones(2) - qp_model = QuadraticModel(c, H, A, lcon, ucon, c0 = c0, x0 = x0, name = "ineqconqp_QP") + qp_model = QuadraticModel(c, H, A, lcon, ucon; c0 = c0, x0 = x0, name = "ineqconqp_QP") stats = minimize(qp_model) @test true - minimize(c, H, A, lcon, ucon, c0 = c0, x0 = x0, name = "ineqconqp_QP") + minimize(c, H, A, lcon, ucon; c0 = c0, x0 = x0, name = "ineqconqp_QP") @test true - minimize("RipQP", c, H, A, lcon, ucon, c0 = c0, x0 = x0, name = "ineqconqp_QP") + minimize("RipQP", c, H, A, lcon, ucon; c0 = c0, x0 = x0, name = "ineqconqp_QP") @test true end end diff --git a/test/runtests.jl b/test/runtests.jl index c5926b4e..401bc024 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -73,7 +73,7 @@ end test_in_place_solve(nlp, solver_name) test_in_place_solve(model, solver_name) elseif is_available[1] && spec_nls[1] # NLS - nls = OptimizationProblems.ADNLPProblems.arglina(use_nls = true) + nls = OptimizationProblems.ADNLPProblems.arglina(; use_nls = true) test_in_place_solve(nls, solver_name) elseif is_available[1] # RipQP nlp_qm = QuadraticModel(nlp, nlp.meta.x0) @@ -85,15 +85,15 @@ end include("qp_tests.jl") @testset "Test `Float32`" begin - nlp = OptimizationProblems.ADNLPProblems.genrose(type = Float32) + nlp = OptimizationProblems.ADNLPProblems.genrose(; type = Float32) atol, rtol = √eps(Float32), √eps(Float32) for solver in eachrow(JSOSuite.select_optimizers(nlp)) if solver.nonlinear_obj - minimize(solver.name, nlp, verbose = 0, atol = atol, rtol = rtol) + minimize(solver.name, nlp; verbose = 0, atol = atol, rtol = rtol) @test true else nlp_qm = QuadraticModel(nlp, nlp.meta.x0) - minimize(solver.name, nlp_qm, verbose = 0, atol = atol, rtol = rtol) + minimize(solver.name, nlp_qm; verbose = 0, atol = atol, rtol = rtol) @test true end end @@ -104,47 +104,47 @@ end jum = MathOptNLPModel(model) @test JSOSuite.select_optimizers(model) == JSOSuite.select_optimizers(jum) for solver in eachrow(JSOSuite.select_optimizers(model)) - minimize(solver.name, model, verbose = 0) + minimize(solver.name, model; verbose = 0) @test true end end @testset "Benchmark on unconstrained problems" begin ad_problems = [ - OptimizationProblems.ADNLPProblems.eval(Meta.parse(problem))() for problem ∈ + OptimizationProblems.ADNLPProblems.eval(Meta.parse(problem))() for problem in first(meta[(5 .<= meta.nvar .<= 10) .& (meta.ncon .== 0) .& (.!meta.has_bounds), :name], 5) ] select = JSOSuite.optimizers[ JSOSuite.optimizers.can_solve_nlp .& JSOSuite.optimizers.is_available, :name, ] - stats = bmark_solvers(ad_problems, select, atol = 1e-3, max_time = 10.0, verbose = 0) + stats = bmark_solvers(ad_problems, select; atol = 1e-3, max_time = 10.0, verbose = 0) @test true # just test that it runs end @testset "Basic solve tests" begin f = x -> 100 * (x[2] - x[1]^2)^2 + (x[1] - 1)^2 - stats = minimize(f, [-1.2; 1.0], verbose = 0) + stats = minimize(f, [-1.2; 1.0]; verbose = 0) @test stats.status_reliable && (stats.status == :first_order) - stats = minimize("DCISolver", f, [-1.2; 1.0], verbose = 0) + stats = minimize("DCISolver", f, [-1.2; 1.0]; verbose = 0) @test stats.status_reliable && (stats.status == :first_order) F = x -> [10 * (x[2] - x[1]^2); x[1] - 1] - stats = minimize(F, [-1.2; 1.0], 2, verbose = 0) + stats = minimize(F, [-1.2; 1.0], 2; verbose = 0) @test stats.status_reliable && (stats.status == :first_order) - stats = minimize("DCISolver", F, [-1.2; 1.0], 2, verbose = 0) + stats = minimize("DCISolver", F, [-1.2; 1.0], 2; verbose = 0) @test stats.status_reliable && (stats.status == :first_order) end @testset "Test solve OptimizationProblems: $name" for name in first(meta[meta.nvar .< 10, :name], 5) name in ["bennett5", "channel", "hs253", "hs73", "misra1c"] && continue nlp = OptimizationProblems.ADNLPProblems.eval(Meta.parse(name))() - minimize(nlp, verbose = 0) + minimize(nlp; verbose = 0) @test true model = OptimizationProblems.PureJuMP.eval(Meta.parse(name))() - minimize(model, verbose = 0) + minimize(model; verbose = 0) @test true end @@ -164,7 +164,7 @@ for solver in eachrow(JSOSuite.optimizers) if solver.nonlinear_obj minimize( solver.name, - nlp, + nlp; atol = 1e-5, rtol = 1e-5, max_time = 12.0, @@ -176,7 +176,7 @@ for solver in eachrow(JSOSuite.optimizers) nlp_qm = QuadraticModel(nlp, nlp.meta.x0) minimize( solver.name, - nlp_qm, + nlp_qm; atol = 1e-5, rtol = 1e-5, max_time = 12.0, @@ -191,7 +191,7 @@ end @testset "Test kwargs in optimizers on $model" for model in (:arglina, :hs6) nlp = OptimizationProblems.ADNLPProblems.eval(model)() - nls = OptimizationProblems.ADNLPProblems.eval(model)(use_nls = true) + nls = OptimizationProblems.ADNLPProblems.eval(model)(; use_nls = true) callback = (args...) -> nothing for solver in eachrow(JSOSuite.optimizers) @testset "Test options in $(solver.name)" begin @@ -201,7 +201,7 @@ end if solver.can_solve_nlp minimize( solver.name, - nlp, + nlp; atol = 1e-5, rtol = 1e-5, max_time = 12.0, @@ -214,7 +214,7 @@ end elseif solver.specialized_nls minimize( solver.name, - nls, + nls; atol = 1e-5, rtol = 1e-5, Fatol = 1e-5, @@ -230,7 +230,7 @@ end nlp_qm = QuadraticModel(nlp, nlp.meta.x0) minimize( solver.name, - nlp_qm, + nlp_qm; atol = 1e-5, rtol = 1e-5, max_time = 12.0,