├── .github ├── setup.md └── workflows │ └── build.yml ├── .gitignore ├── .gitmodules ├── .python-version ├── CMakeLists.txt ├── LICENSE ├── MANIFEST.in ├── Pipfile ├── Pipfile.lock ├── README.md ├── extensions.py ├── setup.cfg ├── setup.py └── test_scripts └── sample_test_script.py /.github/setup.md: -------------------------------------------------------------------------------- 1 | How to Update 2 | ============= 3 | 4 | 1. Update nlopt submodule 5 | ```shell 6 | git submodule update --remote 7 | # if there are changes 8 | git add extern/ 9 | git commit -m "Update nlopt submodule" 10 | ``` 11 | 2. `[Optional]` If there is a need, update the `ci/nlopt_manylinux2014_x64_64.Dockerfile` image. This is used to build 12 | the linux images 13 | * This should be done in `image/*` branch as the github action `manylinux-image.yml` will automatically update the 14 | image in dockerhub on push. 15 | * Whenever there is a upgrade to Python's minor version, it is likely that the manylinux image will not have that 16 | version. Go to https://quay.io/repository/pypa/manylinux2014_x86_64?tab=tags and change the image version 17 | accordingly. 18 | 3. Update `.github/workflows/build.yaml` if necessary 19 | * Search for lines: `python-version`, `CIBW_BUILD` 20 | 4. There are already tests in the github workflows to test that `pip install nlopt` works. But none to test the module specifically 21 | 1. Spin up a docker image and run the sample code 22 | 2. ```shell 23 | docker container run -it --rm --entrypoint bash python:3.10-slim-buster 24 | pip install nlopt 25 | apt-get update 26 | apt-get install curl -y 27 | curl https://raw.githubusercontent.com/DanielBok/nlopt-python/master/test_scripts/sample_test_script.py --output test.py 28 | python test.py 29 | ``` 30 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | branch: 7 | description: 'Branch to build' 8 | required: true 9 | type: choice 10 | options: 11 | - master 12 | - refs/remotes/** 13 | push: 14 | branches: 15 | - develop/* 16 | pull_request: 17 | branches: 18 | - master 19 | release: 20 | types: [ published ] 21 | 22 | defaults: 23 | run: 24 | shell: bash 25 | 26 | jobs: 27 | build_wheels_windows: 28 | name: Build wheels on Windows 29 | runs-on: windows-latest 30 | strategy: 31 | fail-fast: False 32 | matrix: 33 | python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13' ] 34 | steps: 35 | - name: Checkout repository 36 | uses: actions/checkout@v4 37 | with: 38 | submodules: true 39 | 40 | - name: Setup Python ${{ matrix.python-version }} 41 | uses: actions/setup-python@v4 42 | with: 43 | python-version: ${{ matrix.python-version }} 44 | 45 | - name: Build wheels 46 | run: | 47 | python -m pip install -U pip numpy swig wheel setuptools 48 | python setup.py bdist_wheel -d dist 49 | ls -al ./dist 50 | 51 | - name: Place wheels in artifacts folder 52 | uses: actions/upload-artifact@v4 53 | with: 54 | name: windows-${{ matrix.python-version }} 55 | path: ./dist/*.whl 56 | 57 | build_wheels_unix: 58 | name: Build wheels on ${{ matrix.os }} 59 | runs-on: ${{ matrix.os }} 60 | strategy: 61 | fail-fast: False 62 | matrix: 63 | os: [ ubuntu-latest, macos-latest, macos-13 ] 64 | steps: 65 | - name: Checkout repository 66 | uses: actions/checkout@v4 67 | with: 68 | submodules: true 69 | 70 | - name: Setup Python ${{ matrix.python-version }} 71 | uses: actions/setup-python@v4 72 | with: 73 | python-version: '3.11' 74 | 75 | - name: Build wheels 76 | env: 77 | # only build CPython-3.9+ and skip 32-bit builds 78 | CIBW_BUILD: cp39-* cp310-* cp311-* cp312-* cp313-* 79 | CIBW_SKIP: "*-manylinux_i686 *-musllinux*" 80 | # use latest build 81 | CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64 82 | CIBW_BEFORE_ALL_MACOS: brew install swig 83 | CIBW_BEFORE_BUILD: pip install numpy swig 84 | run: | 85 | python -m pip install -U pip cibuildwheel 86 | python -m cibuildwheel --output-dir dist 87 | ls -R dist 88 | 89 | - name: Place wheels in artifacts folder 90 | uses: actions/upload-artifact@v4 91 | with: 92 | name: ${{ matrix.os }} 93 | path: ./dist/*.whl 94 | 95 | test-wheels: 96 | name: Test wheels 97 | needs: [ build_wheels_windows, build_wheels_unix ] 98 | runs-on: ${{ matrix.os }} 99 | strategy: 100 | matrix: 101 | os: [ windows-latest, ubuntu-latest, macos-latest, macos-13 ] 102 | python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13' ] 103 | 104 | steps: 105 | - name: Checkout repository 106 | uses: actions/checkout@v4 107 | with: 108 | submodules: true 109 | - name: Setup Python ${{ matrix.python-version }} 110 | uses: actions/setup-python@v4 111 | with: 112 | python-version: ${{ matrix.python-version }} 113 | 114 | - name: Retrieve packages 115 | uses: actions/download-artifact@v4 116 | with: 117 | path: dist 118 | 119 | - name: List items 120 | run: | 121 | ls -alR dist 122 | 123 | - name: Test Package Installation 124 | run: | 125 | python -m pip install --upgrade pip 126 | 127 | # list all files in the dist folder 128 | ls -R dist 129 | 130 | # finds path to the right wheel or source file to install later 131 | os=$(echo ${{ runner.os }} | awk '{print tolower($0)}' | head -c3) 132 | 133 | # version refers to the python version. So 3.8 -> 38 134 | version=$(echo ${{ matrix.python-version }} | sed 's/\.//g') 135 | 136 | if [[ "${{ matrix.os }}" == "windows-latest" ]]; then 137 | chunk="windows-*" 138 | else 139 | chunk="${{matrix.os}}" 140 | fi 141 | 142 | # this finds files like 143 | # nlopt-2.6.2-cp36-cp36m-win_amd64.whl 144 | # nlopt-2.6.2-cp36-cp36m-manylinux10_amd64.whl 145 | # nlopt-2.7.1-cp310-cp310-win_amd64.whl 146 | file=$(find dist/${chunk} -name "nlopt-*${version}*${os}*.whl" -type f); 147 | 148 | echo "Installing file: ${file}" 149 | 150 | pip install ${file} 151 | python extern/nlopt/test/t_python.py 152 | 153 | deploy: 154 | name: Deploy packages 155 | runs-on: ubuntu-latest 156 | needs: test-wheels 157 | permissions: 158 | id-token: write 159 | contents: read 160 | 161 | steps: 162 | - name: Setup Python ${{ matrix.python-version }} 163 | uses: actions/setup-python@v4 164 | with: 165 | python-version: ${{ matrix.python-version }} 166 | 167 | - name: Retrieve packages 168 | uses: actions/download-artifact@v4 169 | with: 170 | path: dist 171 | 172 | - name: Install twine 173 | run: | 174 | pip install twine 175 | pip install -U packaging 176 | 177 | - name: Move files to top level directory 178 | run: | 179 | ls -ltR dist 180 | python - << EOF 181 | from pathlib import Path 182 | import shutil 183 | 184 | d = Path('dist') 185 | for f in d.rglob('*.whl'): 186 | shutil.move(f, d / f.name) 187 | 188 | for f in d.iterdir(): 189 | if f.is_dir(): 190 | shutil.rmtree(f) 191 | 192 | EOF 193 | 194 | - name: Upload packages to testpypi 195 | if: ${{ !startsWith(github.ref, 'refs/tags/') }} 196 | run: python -m twine upload --skip-existing --repository testpypi dist/* --verbose 197 | 198 | - name: Upload packages to pypi 199 | if: startsWith(github.ref, 'refs/tags/') 200 | run: python -m twine upload --skip-existing dist/* --verbose 201 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.egg-info/ 3 | dist/ 4 | build/ 5 | wheelhouse/ 6 | __pycache__/ 7 | 8 | CMakeFiles 9 | 10 | py? 11 | py?? 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "extern/nlopt"] 2 | path = extern/nlopt 3 | url = https://github.com/stevengj/nlopt.git 4 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.12.2 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1.0..3.14) 2 | 3 | project(nlopt-python) 4 | 5 | set (CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}) 6 | set (CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/nlopt) 7 | set (INSTALL_PYTHON_DIR ${CMAKE_INSTALL_PREFIX}) 8 | 9 | option (BUILD_SHARED_LIBS OFF) 10 | 11 | if (NOT WIN32) 12 | find_package (PythonInterp) 13 | 14 | execute_process( 15 | COMMAND 16 | ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())" 17 | OUTPUT_VARIABLE 18 | PYTHON_INCLUDE_DIR 19 | OUTPUT_STRIP_TRAILING_WHITESPACE 20 | ) 21 | 22 | # this does not work on windows 23 | execute_process( 24 | COMMAND 25 | ${PYTHON_EXECUTABLE} -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR'))" 26 | OUTPUT_VARIABLE 27 | PYTHON_LIBRARY 28 | OUTPUT_STRIP_TRAILING_WHITESPACE 29 | ) 30 | 31 | set (PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIR} CACHE STRING "" FORCE) 32 | set (PYTHON_LIBRARY ${PYTHON_LIBRARY} CACHE STRING "" FORCE) 33 | 34 | message(STATUS "Found Python includes: ${PYTHON_INCLUDE_DIR}") 35 | message(STATUS "Found Python libs: ${PYTHON_LIBRARY}") 36 | endif() 37 | 38 | add_subdirectory(extern/nlopt) 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | NLopt-python is a wrapped version of nlopt for python. The licenses will 2 | refer to the underlying routine's license. For more information, refer 3 | to the NLopt license copied below 4 | 5 | --------------------------------------------------------------------------- 6 | 7 | NLopt combines several free/open-source nonlinear optimization 8 | libraries by various authors. See the COPYING, COPYRIGHT, and README 9 | files in the subdirectories for the original copyright and licensing 10 | information of these packages. 11 | 12 | The compiled NLopt library, i.e. the combined work of all of the 13 | included optimization routines, is licensed under the conjunction of 14 | all of these licensing terms. Currently, the most restrictive terms 15 | are for the code in the "luksan" directory, which is licensed under 16 | the GNU Lesser General Public License (GNU LGPL), version 2.1 or 17 | later (see luksan/COPYRIGHT). 18 | 19 | That means that the compiled NLopt library is governed by the terms of 20 | the LGPL. 21 | 22 | --------------------------------------------------------------------------- 23 | 24 | Other portions of NLopt, including any modifications to the abovementioned 25 | packages, are licensed under the standard "MIT License:" 26 | 27 | Copyright (c) 2007-2011 Massachusetts Institute of Technology 28 | 29 | Permission is hereby granted, free of charge, to any person obtaining 30 | a copy of this software and associated documentation files (the 31 | "Software"), to deal in the Software without restriction, including 32 | without limitation the rights to use, copy, modify, merge, publish, 33 | distribute, sublicense, and/or sell copies of the Software, and to 34 | permit persons to whom the Software is furnished to do so, subject to 35 | the following conditions: 36 | 37 | The above copyright notice and this permission notice shall be 38 | included in all copies or substantial portions of the Software. 39 | 40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 41 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 42 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 43 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 44 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 45 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 46 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 47 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include MANIFEST.in 3 | include README.md 4 | include setup.py 5 | recursive-include extern/nlopt 6 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | nlopt = "*" 8 | 9 | [dev-packages] 10 | 11 | [requires] 12 | python_version = "3.10" 13 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "4fe33bc40a343fde96e372b71cd4956f049e55cc94a652ede4b1013e73ae13b8" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.10" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "nlopt": { 20 | "hashes": [ 21 | "sha256:087ff54de5ec0375fd18f843b36e9a8590c0f1e194bb45d3119ba844aeb836dd", 22 | "sha256:33f9370bd37788b4ac792cf161835f1e4e9bbad8bfb5a76f75a295ae38dcd8d0", 23 | "sha256:426c18548d733640449d707c82eb57c09a5f01d4b064f87312808d194d227f24", 24 | "sha256:42b7883704e1285ff40d930699eb7fc7e1341229da33666b4163459cfdf89fb1", 25 | "sha256:479a415f522051f6d728a3279c013aab96a6eaf3c323a89582dcb07eb636f15f", 26 | "sha256:6ba0862162248442fbf1f04b20a321c11ff40ff4442a12aaaafcdaff9abb0ab7", 27 | "sha256:757c41210f3ab6173e5c508c79c7833e33cf90a068d098b1e13d277432120b81", 28 | "sha256:79791a2179d1cf708622eaeea76c88acbadc6af0d2f198df21a74473838686c3", 29 | "sha256:8e7b65cf3a751e822b02f28b65d0c548052523fa6333619af3f24fec60a6b6bd", 30 | "sha256:aad38bab99348f6c3bbf0d5f339b3fd77465b27ef44c330f4ba512a40b87b373", 31 | "sha256:b4a05448f0ffebbab7a6a822297430e018c848652280e6efa13484e210291d5c", 32 | "sha256:d99f1d6217bc3ead6fa6fe84a923577003f9a5f760cd354a3f8dcd1e11d626ce" 33 | ], 34 | "index": "pypi", 35 | "version": "==2.7.1" 36 | }, 37 | "numpy": { 38 | "hashes": [ 39 | "sha256:07a8c89a04997625236c5ecb7afe35a02af3896c8aa01890a849913a2309c676", 40 | "sha256:08d9b008d0156c70dc392bb3ab3abb6e7a711383c3247b410b39962263576cd4", 41 | "sha256:201b4d0552831f7250a08d3b38de0d989d6f6e4658b709a02a73c524ccc6ffce", 42 | "sha256:2c10a93606e0b4b95c9b04b77dc349b398fdfbda382d2a39ba5a822f669a0123", 43 | "sha256:3ca688e1b9b95d80250bca34b11a05e389b1420d00e87a0d12dc45f131f704a1", 44 | "sha256:48a3aecd3b997bf452a2dedb11f4e79bc5bfd21a1d4cc760e703c31d57c84b3e", 45 | "sha256:568dfd16224abddafb1cbcce2ff14f522abe037268514dd7e42c6776a1c3f8e5", 46 | "sha256:5bfb1bb598e8229c2d5d48db1860bcf4311337864ea3efdbe1171fb0c5da515d", 47 | "sha256:639b54cdf6aa4f82fe37ebf70401bbb74b8508fddcf4797f9fe59615b8c5813a", 48 | "sha256:8251ed96f38b47b4295b1ae51631de7ffa8260b5b087808ef09a39a9d66c97ab", 49 | "sha256:92bfa69cfbdf7dfc3040978ad09a48091143cffb778ec3b03fa170c494118d75", 50 | "sha256:97098b95aa4e418529099c26558eeb8486e66bd1e53a6b606d684d0c3616b168", 51 | "sha256:a3bae1a2ed00e90b3ba5f7bd0a7c7999b55d609e0c54ceb2b076a25e345fa9f4", 52 | "sha256:c34ea7e9d13a70bf2ab64a2532fe149a9aced424cd05a2c4ba662fd989e3e45f", 53 | "sha256:dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18", 54 | "sha256:e7927a589df200c5e23c57970bafbd0cd322459aa7b1ff73b7c2e84d6e3eae62", 55 | "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe", 56 | "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430", 57 | "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802", 58 | "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa" 59 | ], 60 | "markers": "python_version >= '3.8'", 61 | "version": "==1.22.3" 62 | } 63 | }, 64 | "develop": {} 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NLopt Python 2 | ============ 3 | 4 | [![PyPI version](https://badge.fury.io/py/nlopt.svg)](https://badge.fury.io/py/nlopt) 5 | ![Build](https://github.com/DanielBok/nlopt-python/workflows/Build/badge.svg?branch=master) 6 | 7 | This project builds Python wheels for the NLopt library. NLopt contains various routines for non-linear optimization. 8 | 9 | ## Versions supported 10 | 11 | The project supports Python versions 3.9+ and above for Windows, MacOS, and Linux. 12 | 13 | ## Installation 14 | 15 | ```bash 16 | pip install nlopt 17 | ``` 18 | 19 | ## Documentation 20 | 21 | For more information on how to use NLopt, refer to the [documentation](https://nlopt.readthedocs.io/en/latest/NLopt_Python_Reference/). 22 | -------------------------------------------------------------------------------- /extensions.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import platform 4 | import shutil 5 | import sys 6 | from pathlib import Path 7 | from subprocess import check_call 8 | from typing import Dict, List 9 | 10 | from setuptools import Extension 11 | from setuptools.command.build_ext import build_ext 12 | 13 | 14 | class NLOptBuildExtension(Extension): 15 | def __init__(self, name: str, version: str): 16 | super().__init__(name, sources=[]) 17 | # Source dir should be at the root directory 18 | self.source_dir = Path(__file__).parent.absolute() 19 | self.version = version 20 | 21 | 22 | class NLOptBuild(build_ext): 23 | def run(self): 24 | try: 25 | check_call(["cmake", "--version"]) 26 | except OSError: 27 | raise RuntimeError("CMake must be installed") 28 | 29 | if platform.system() not in ("Windows", "Linux", "Darwin"): 30 | raise RuntimeError(f"Unsupported os: {platform.system()}") 31 | 32 | for ext in self.extensions: 33 | if isinstance(ext, NLOptBuildExtension): 34 | self.build_extension(ext) 35 | 36 | @property 37 | def config(self): 38 | return "Debug" if self.debug else "Release" 39 | 40 | def build_extension(self, ext: Extension): 41 | # - make sure path ends with delimiter 42 | # - required for auto-detection of auxiliary "native" libs 43 | ext_dir = Path(self.get_ext_fullpath(ext.name)).parent.absolute() 44 | _ed = ext_dir.as_posix() 45 | 46 | build_dir = create_directory(Path(self.build_temp)) 47 | 48 | # package builds in 2 steps, first to compile the nlopt package and second to build the DLL 49 | cmd = [ 50 | "cmake", 51 | "-LAH", 52 | f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={_ed}", 53 | f"-DPython_EXECUTABLE={sys.executable}", 54 | "-DNLOPT_GUILE=OFF", 55 | "-DNLOPT_MATLAB=OFF", 56 | "-DNLOPT_OCTAVE=OFF", 57 | ext.source_dir.as_posix() 58 | ] 59 | 60 | if platform.system() == "Windows": 61 | cmd.insert(2, f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{self.config.upper()}={_ed}") 62 | 63 | execute_command( 64 | cmd=cmd, 65 | cwd=build_dir, 66 | env={ 67 | **os.environ.copy(), 68 | "CXXFLAGS": f'{os.environ.get("CXXFLAGS", "")} -DVERSION_INFO="{self.distribution.get_version()}"' 69 | }) 70 | 71 | # build the DLL 72 | execute_command([ 73 | 'cmake', 74 | '--build', 75 | '.', 76 | '--config', 77 | self.config, 78 | "--", 79 | "-m" if platform.system() == "Windows" else "-j2" 80 | ], cwd=build_dir) 81 | 82 | # Copy over the important bits 83 | nlopt_py = build_dir / "extern" / "nlopt" / "src" / "swig" / "nlopt.py" 84 | 85 | logging.info(f"Ext Dir - {ext_dir}\n" + '\n'.join(f' - {file.as_posix()}' for file in ext_dir.rglob('*'))) 86 | for folder in [ext_dir, nlopt_py.parent]: 87 | logging.info(f'Files in {folder.as_posix()}\n' + '\n'.join(f' - {f.name}' for f in folder.iterdir())) 88 | 89 | logging.info(f"Attempting to copy nlopt.py file from {nlopt_py.parent.as_posix()} to {ext_dir.as_posix()}") 90 | if not nlopt_py.exists(): 91 | raise RuntimeError("swig python file was not generated") 92 | 93 | shutil.copy2(nlopt_py, ext_dir / "nlopt.py") 94 | with open(ext_dir / "__init__.py", 'w') as f: 95 | f.write(f""" 96 | from .nlopt import * 97 | 98 | __version__ = '{ext.version}' 99 | """.strip() + "\n") 100 | 101 | 102 | def create_directory(path: Path): 103 | if path.exists(): 104 | shutil.rmtree(path) 105 | path.mkdir(exist_ok=True, parents=True) 106 | return path 107 | 108 | 109 | def execute_command(cmd: List[str], cwd: Path, env: Dict[str, str] = os.environ): 110 | logging.info(f"Running Command: {cwd.as_posix()}: {' '.join(cmd)}") 111 | check_call(cmd, cwd=cwd.as_posix(), env=env) 112 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = nlopt 3 | author = Daniel Bok 4 | author_email = daniel.bok@outlook.com 5 | project_urls = 6 | Documentation = https://nlopt.readthedocs.io/en/latest/ 7 | Code = https://github.com/DanielBok/nlopt-python 8 | Issue tracker = https://github.com/DanielBok/nlopt-python/issues 9 | license = MIT 10 | maintainer = Daniel Bok 11 | maintainer_email = daniel.bok@outlook.com 12 | description = Library for nonlinear optimization, wrapping many algorithms for global and local, constrained or unconstrained, optimization 13 | long_description = file: README.md 14 | long_description_content_type = text/markdown 15 | keywords = 16 | algorithms 17 | global local constrained unconstrained optimization 18 | optimization 19 | non-linear optimization 20 | classifiers = 21 | Development Status :: 5 - Production/Stable 22 | Intended Audience :: End Users/Desktop 23 | Intended Audience :: Education 24 | License :: OSI Approved :: MIT License 25 | Operating System :: MacOS 26 | Operating System :: Microsoft :: Windows 27 | Operating System :: Unix 28 | Programming Language :: C++ 29 | Programming Language :: Python :: 3.9 30 | Programming Language :: Python :: 3.10 31 | Programming Language :: Python :: 3.11 32 | Programming Language :: Python :: 3.12 33 | Programming Language :: Python :: 3.13 34 | Topic :: Scientific/Engineering 35 | 36 | [options] 37 | python_requires = >= 3.9 38 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import re 2 | from pathlib import Path 3 | 4 | from setuptools import setup 5 | 6 | from extensions import NLOptBuild, NLOptBuildExtension 7 | 8 | with open("README.md") as f: 9 | long_description = f.read() 10 | 11 | with open(Path(__file__).parent / "extern" / "nlopt" / "CMakeLists.txt") as f: 12 | content = f.read() 13 | version = [] 14 | for s in ("MAJOR", "MINOR", "BUGFIX"): 15 | m = re.search(f"NLOPT_{s}_VERSION *['\"](.+)['\"]", content) 16 | version.append(m.group(1)) 17 | version = ".".join(version) 18 | 19 | 20 | setup( 21 | version=version, 22 | python_requires=">=3.9", 23 | install_requires=["numpy >=2,<3"], 24 | setup_requires=["numpy >=2,<3"], 25 | ext_modules=[NLOptBuildExtension("nlopt._nlopt", version)], 26 | cmdclass={"build_ext": NLOptBuild}, 27 | zip_safe=False, 28 | ) 29 | -------------------------------------------------------------------------------- /test_scripts/sample_test_script.py: -------------------------------------------------------------------------------- 1 | import nlopt 2 | import numpy as np 3 | 4 | 5 | def objective(x, grad): 6 | if grad.size > 0: 7 | grad[0] = 0.0 8 | grad[1] = 0.5 / np.sqrt(x[1]) 9 | return np.sqrt(x[1]) 10 | 11 | 12 | def constraint(x, grad, a, b): 13 | if grad.size > 0: 14 | grad[0] = 3 * a * (a * x[0] + b) ** 2 15 | grad[1] = -1.0 16 | return (a * x[0] + b) ** 3 - x[1] 17 | 18 | 19 | opt = nlopt.opt(nlopt.LD_MMA, 2) 20 | opt.set_lower_bounds([-float('inf'), 0]) 21 | opt.set_min_objective(objective) 22 | opt.add_inequality_constraint(lambda x, grad: constraint(x, grad, 2, 0), 1e-8) 23 | opt.add_inequality_constraint(lambda x, grad: constraint(x, grad, -1, 1), 1e-8) 24 | opt.set_xtol_rel(1e-4) 25 | x = opt.optimize([1.234, 5.678]) 26 | minf = opt.last_optimum_value() 27 | 28 | print("optimum at ", x[0], x[1]) 29 | print("minimum value = ", minf) 30 | print("result code = ", opt.last_optimize_result()) 31 | --------------------------------------------------------------------------------