diff --git a/.github/workflows/aarch64_toolchain.yml b/.github/not_used/aarch64_toolchain.yml similarity index 100% rename from .github/workflows/aarch64_toolchain.yml rename to .github/not_used/aarch64_toolchain.yml diff --git a/.github/workflows/amd64_cmake_glop_cpp.yml b/.github/not_used/amd64_cmake_glop_cpp.yml similarity index 100% rename from .github/workflows/amd64_cmake_glop_cpp.yml rename to .github/not_used/amd64_cmake_glop_cpp.yml diff --git a/.github/workflows/amd64_docker_bazel.yml b/.github/not_used/amd64_docker_bazel.yml similarity index 100% rename from .github/workflows/amd64_docker_bazel.yml rename to .github/not_used/amd64_docker_bazel.yml diff --git a/.github/workflows/amd64_docker_cmake.yml b/.github/not_used/amd64_docker_cmake.yml similarity index 100% rename from .github/workflows/amd64_docker_cmake.yml rename to .github/not_used/amd64_docker_cmake.yml diff --git a/.github/workflows/amd64_freebsd_cmake.yml b/.github/not_used/amd64_freebsd_cmake.yml similarity index 100% rename from .github/workflows/amd64_freebsd_cmake.yml rename to .github/not_used/amd64_freebsd_cmake.yml diff --git a/.github/workflows/amd64_linux_bazel.yml b/.github/not_used/amd64_linux_bazel.yml similarity index 100% rename from .github/workflows/amd64_linux_bazel.yml rename to .github/not_used/amd64_linux_bazel.yml diff --git a/.github/workflows/amd64_linux_cmake_coinor_off.yml b/.github/not_used/amd64_linux_cmake_coinor_off.yml similarity index 100% rename from .github/workflows/amd64_linux_cmake_coinor_off.yml rename to .github/not_used/amd64_linux_cmake_coinor_off.yml diff --git a/.github/workflows/amd64_linux_cmake_dotnet.yml b/.github/not_used/amd64_linux_cmake_dotnet.yml similarity index 100% rename from .github/workflows/amd64_linux_cmake_dotnet.yml rename to .github/not_used/amd64_linux_cmake_dotnet.yml diff --git a/.github/workflows/amd64_linux_cmake_scip_off.yml b/.github/not_used/amd64_linux_cmake_scip_off.yml similarity index 100% rename from .github/workflows/amd64_linux_cmake_scip_off.yml rename to .github/not_used/amd64_linux_cmake_scip_off.yml diff --git a/.github/workflows/amd64_macos_bazel.yml b/.github/not_used/amd64_macos_bazel.yml similarity index 100% rename from .github/workflows/amd64_macos_bazel.yml rename to .github/not_used/amd64_macos_bazel.yml diff --git a/.github/workflows/amd64_macos_cmake_cpp.yml b/.github/not_used/amd64_macos_cmake_cpp.yml similarity index 100% rename from .github/workflows/amd64_macos_cmake_cpp.yml rename to .github/not_used/amd64_macos_cmake_cpp.yml diff --git a/.github/workflows/amd64_macos_cmake_dotnet.yml b/.github/not_used/amd64_macos_cmake_dotnet.yml similarity index 100% rename from .github/workflows/amd64_macos_cmake_dotnet.yml rename to .github/not_used/amd64_macos_cmake_dotnet.yml diff --git a/.github/workflows/amd64_macos_cmake_java.yml b/.github/not_used/amd64_macos_cmake_java.yml similarity index 100% rename from .github/workflows/amd64_macos_cmake_java.yml rename to .github/not_used/amd64_macos_cmake_java.yml diff --git a/.github/workflows/amd64_macos_cmake_python.yml b/.github/not_used/amd64_macos_cmake_python.yml similarity index 100% rename from .github/workflows/amd64_macos_cmake_python.yml rename to .github/not_used/amd64_macos_cmake_python.yml diff --git a/.github/workflows/amd64_windows_cmake_dotnet.yml b/.github/not_used/amd64_windows_cmake_dotnet.yml similarity index 100% rename from .github/workflows/amd64_windows_cmake_dotnet.yml rename to .github/not_used/amd64_windows_cmake_dotnet.yml diff --git a/.github/not_used/amd64_windows_cmake_java.yml b/.github/not_used/amd64_windows_cmake_java.yml new file mode 100644 index 00000000000..190ebf7d3ff --- /dev/null +++ b/.github/not_used/amd64_windows_cmake_java.yml @@ -0,0 +1,75 @@ +# ref: https://github.com/actions/runner-images +name: amd64 Windows CMake Java + +on: [push, pull_request, workflow_dispatch] + +# Building using the github runner environement directly. +jobs: + native: + strategy: + matrix: + cmake: [ + {generator: "Visual Studio 17 2022", config: Release, build_target: ALL_BUILD, test_target: RUN_TESTS, install_target: INSTALL}, + ] + java: [ + # see https://endoflife.date/azul-zulu + {distrib: 'zulu', version: '8'}, # 2030/12 + {distrib: 'zulu', version: '11'}, # 2026/09 + {distrib: 'zulu', version: '17'}, # 2029/09 + {distrib: 'zulu', version: '21'}, # 2031/09 + # see https://endoflife.date/eclipse-temurin + {distrib: 'temurin', version: '8'}, # 2026/11 + {distrib: 'temurin', version: '11'}, # 2027/10 + {distrib: 'temurin', version: '17'}, # 2027/10 + {distrib: 'temurin', version: '21'}, # 2029/12 + # see https://endoflife.date/microsoft-build-of-openjdk + {distrib: 'microsoft', version: '11'}, # 2027/09 + {distrib: 'microsoft', version: '17'}, # 2027/09 + {distrib: 'microsoft', version: '21'}, # 2028/09 + ] + fail-fast: false + name: Windows • ${{ matrix.cmake.generator }} • ${{ matrix.java.distrib }}-${{ matrix.java.version }} + runs-on: windows-latest + env: + CTEST_OUTPUT_ON_FAILURE: 1 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: ${{ matrix.java.distrib }} + java-version: ${{ matrix.java.version }} + - name: Update maven + run: | + choco upgrade maven + echo "C:\ProgramData\chocolatey\lib\maven\apache-maven-3.9.9\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - name: Check java + run: | + java -version + mvn --version + - name: Check cmake + run: cmake --version + - name: Configure + run: > + cmake -S. -Bbuild + -G "${{ matrix.cmake.generator }}" + -DCMAKE_BUILD_TYPE=${{ matrix.cmake.config }} + -DBUILD_CXX_SAMPLES=OFF -DBUILD_CXX_EXAMPLES=OFF + -DBUILD_JAVA=ON + - name: Build + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.build_target }} + -v -j2 + - name: Test + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.test_target }} + -v + - name: Install + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.install_target }} + -v diff --git a/.github/workflows/amd64_windows_cmake_python.yml b/.github/not_used/amd64_windows_cmake_python.yml similarity index 100% rename from .github/workflows/amd64_windows_cmake_python.yml rename to .github/not_used/amd64_windows_cmake_python.yml diff --git a/.github/workflows/amd64_windows_bazel.yml b/.github/not_used/arm64_macos_bazel.yml similarity index 70% rename from .github/workflows/amd64_windows_bazel.yml rename to .github/not_used/arm64_macos_bazel.yml index f891de2aacf..8ac4f1d0713 100644 --- a/.github/workflows/amd64_windows_bazel.yml +++ b/.github/not_used/arm64_macos_bazel.yml @@ -1,5 +1,5 @@ # ref: https://github.com/actions/runner-images -name: amd64 Windows Bazel +name: arm64 MacOS Bazel on: [push, pull_request, workflow_dispatch] @@ -8,24 +8,22 @@ jobs: native: strategy: matrix: - runner: [windows-2022] python: [ {version: '3.10'}, {version: '3.11'}, {version: '3.12'}, {version: '3.13'}, ] - fail-fast: false # Don't cancel all jobs if one fails. - name: ${{ matrix.runner }} • Bazel • Python-${{ matrix.python.version }} - runs-on: ${{ matrix.runner }} + fail-fast: false + name: MacOS • Bazel • Python-${{ matrix.python.version }} + runs-on: macos-latest # macos arm64 based runner steps: - uses: actions/checkout@v4 - - uses: actions/setup-java@v3 + - name: Set Java to OpenJDK 17 (Temurin) + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '17' - - name: Check java - run: java -version - name: Check mvn run: mvn --version - name: Setup Python @@ -34,10 +32,14 @@ jobs: python-version: ${{ matrix.python.version }} - name: Check Python run: python --version - - name: Install Bazel - run: choco install bazel - name: Check Bazel run: bazel version + - name: Change Python in WORKSPACE + run: > + sed + -i '' + -e 's/\(DEFAULT_PYTHON =\) "3.[0-9]*"/\1 "${{ matrix.python.version }}"/g' + WORKSPACE - name: Build run: > bazel build diff --git a/.github/not_used/arm64_macos_cmake_cpp.yml b/.github/not_used/arm64_macos_cmake_cpp.yml new file mode 100644 index 00000000000..8388c59aa14 --- /dev/null +++ b/.github/not_used/arm64_macos_cmake_cpp.yml @@ -0,0 +1,47 @@ +# ref: https://github.com/actions/runner-images +name: arm64 MacOS CMake C++ + +on: [push, pull_request, workflow_dispatch] + +# Building using the github runner environement directly. +jobs: + native: + strategy: + matrix: + cmake: [ + {generator: "Xcode", config: Release, build_target: ALL_BUILD, test_target: RUN_TESTS, install_target: install}, + {generator: "Unix Makefiles", config: Release, build_target: all, test_target: test, install_target: install}, + ] + fail-fast: false + name: MacOS • ${{ matrix.cmake.generator }} • C++ + runs-on: macos-latest # macos arm64 based runner + steps: + - uses: actions/checkout@v4 + - name: Check cmake + run: cmake --version + - name: Configure + run: > + cmake -S. -Bbuild + -G "${{ matrix.cmake.generator }}" + -DCMAKE_BUILD_TYPE=${{ matrix.cmake.config }} + -DBUILD_DEPS=ON + -DCMAKE_INSTALL_PREFIX=install + - name: Build + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.build_target }} + -v -j2 + - name: Test + run: > + CTEST_OUTPUT_ON_FAILURE=1 + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.test_target }} + -v + - name: Install + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.install_target }} + -v diff --git a/.github/not_used/arm64_macos_cmake_dotnet.yml b/.github/not_used/arm64_macos_cmake_dotnet.yml new file mode 100644 index 00000000000..193d3675b85 --- /dev/null +++ b/.github/not_used/arm64_macos_cmake_dotnet.yml @@ -0,0 +1,58 @@ +# ref: https://github.com/actions/runner-images +name: arm64 MacOS CMake .Net + +on: [push, pull_request, workflow_dispatch] + +# Building using the github runner environement directly. +jobs: + native: + strategy: + matrix: + cmake: [ + {generator: "Xcode", config: Release, build_target: ALL_BUILD, test_target: RUN_TESTS, install_target: install}, + {generator: "Unix Makefiles", config: Release, build_target: all, test_target: test, install_target: install}, + ] + fail-fast: false + name: MacOS • ${{ matrix.cmake.generator }} • .Net + runs-on: macos-latest # macos arm64 based runner + steps: + - uses: actions/checkout@v4 + - name: Swig install + run: | + brew install swig + swig -version + - name: Setup .NET 6.0 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 6.0.x + - name: Check dotnet + run: dotnet --info + - name: Check cmake + run: cmake --version + - name: Configure + run: > + cmake -S. -Bbuild + -G "${{ matrix.cmake.generator }}" + -DCMAKE_BUILD_TYPE=${{ matrix.cmake.config }} + -DBUILD_CXX_SAMPLES=OFF -DBUILD_CXX_EXAMPLES=OFF + -DBUILD_DOTNET=ON + -DCMAKE_INSTALL_PREFIX=install + - name: Build + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.build_target }} + -v -j2 + - name: Test + run: > + CTEST_OUTPUT_ON_FAILURE=1 + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.test_target }} + -v + - name: Install + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.install_target }} + -v diff --git a/.github/not_used/arm64_macos_cmake_java.yml b/.github/not_used/arm64_macos_cmake_java.yml new file mode 100644 index 00000000000..21e25b5c811 --- /dev/null +++ b/.github/not_used/arm64_macos_cmake_java.yml @@ -0,0 +1,55 @@ +# ref: https://github.com/actions/runner-images +name: arm64 MacOS CMake Java + +on: [push, pull_request, workflow_dispatch] + +# Building using the github runner environement directly. +jobs: + native: + strategy: + matrix: + cmake: [ + {generator: "Xcode", config: Release, build_target: ALL_BUILD, test_target: RUN_TESTS, install_target: install}, + {generator: "Unix Makefiles", config: Release, build_target: all, test_target: test, install_target: install}, + ] + fail-fast: false + name: MacOS • ${{ matrix.cmake.generator }} • Java + runs-on: macos-latest # macos arm64 based runner + steps: + - uses: actions/checkout@v4 + - name: Swig install + run: | + brew install swig + swig -version + - name: Check java + run: java -version + - name: Check cmake + run: cmake --version + - name: Configure + run: > + cmake -S. -Bbuild + -G "${{ matrix.cmake.generator }}" + -DCMAKE_BUILD_TYPE=${{ matrix.cmake.config }} + -DBUILD_CXX_SAMPLES=OFF -DBUILD_CXX_EXAMPLES=OFF + -DBUILD_JAVA=ON -DSKIP_GPG=ON + -DCMAKE_INSTALL_PREFIX=install + - name: Build + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.build_target }} + -v -j2 + - name: Test + run: > + CTEST_OUTPUT_ON_FAILURE=1 + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.test_target }} + -v + - name: Install + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.install_target }} + -v + \ No newline at end of file diff --git a/.github/workflows/amd64_linux_cmake_python.yml b/.github/not_used/arm64_macos_cmake_python.yml similarity index 76% rename from .github/workflows/amd64_linux_cmake_python.yml rename to .github/not_used/arm64_macos_cmake_python.yml index 20c6d90feab..5de445d2fe4 100644 --- a/.github/workflows/amd64_linux_cmake_python.yml +++ b/.github/not_used/arm64_macos_cmake_python.yml @@ -1,5 +1,5 @@ # ref: https://github.com/actions/runner-images -name: amd64 Linux CMake Python +name: arm64 MacOS CMake Python on: [push, pull_request, workflow_dispatch] @@ -9,8 +9,7 @@ jobs: strategy: matrix: cmake: [ - {generator: "Ninja", config: Release, build_target: all, test_target: test, install_target: install}, - {generator: "Ninja Multi-Config", config: Release, build_target: all, test_target: test, install_target: install}, + {generator: "Xcode", config: Release, build_target: ALL_BUILD, test_target: RUN_TESTS, install_target: install}, {generator: "Unix Makefiles", config: Release, build_target: all, test_target: test, install_target: install}, ] python: [ @@ -21,24 +20,22 @@ jobs: {version: "3.13"}, ] fail-fast: false - name: Linux • ${{ matrix.cmake.generator }} • Python-${{ matrix.python.version }} - runs-on: ubuntu-latest + name: MacOS • ${{ matrix.cmake.generator }} • Python-${{ matrix.python.version }} + runs-on: macos-latest # macos arm64 based runner steps: - uses: actions/checkout@v4 - - name: Install Ninja - run: | - sudo apt update - sudo apt install -y ninja-build - name: Swig install run: | - sudo apt install -y swig + brew install swig swig -version - name: Setup Python uses: actions/setup-python@v4 with: python-version: ${{ matrix.python.version }} - name: Update Path - run: echo "$HOME/.local/bin" >> $GITHUB_PATH + run: | + echo "$HOME/Library/Python/${{ matrix.python.version }}/bin" >> $GITHUB_PATH + echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Check cmake run: cmake --version - name: Configure diff --git a/.github/workflows/mips_toolchain.yml b/.github/not_used/mips_toolchain.yml similarity index 100% rename from .github/workflows/mips_toolchain.yml rename to .github/not_used/mips_toolchain.yml diff --git a/.github/workflows/powerpc_toolchain.yml b/.github/not_used/powerpc_toolchain.yml similarity index 100% rename from .github/workflows/powerpc_toolchain.yml rename to .github/not_used/powerpc_toolchain.yml diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile deleted file mode 100644 index 4b93054b8d1..00000000000 --- a/.github/workflows/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -# Create a virtual environment with all tools installed -# ref: https://hub.docker.com/_/alpine -FROM alpine:edge -# Install system build dependencies -RUN apk add --no-cache git clang-extra-tools -RUN apk add --no-cache python3 py3-pip \ -&& rm -f /usr/lib/python3.*/EXTERNALLY-MANAGED \ -&& python3 -m pip install black diff --git a/.github/workflows/amd64_linux_cmake_cpp.yml b/.github/workflows/amd64_linux_cmake_cpp.yml index c54acef4ef9..233f9175473 100644 --- a/.github/workflows/amd64_linux_cmake_cpp.yml +++ b/.github/workflows/amd64_linux_cmake_cpp.yml @@ -6,6 +6,10 @@ on: [push, pull_request, workflow_dispatch] # Building using the github runner environement directly. jobs: native: + env: + KNITRODIR: ${{ github.workspace }}/knitro_distrib/knitro-14.0.0-Linux64 + ARTELYS_LICENSE: ${{ github.workspace }}/knitro_distrib + OR_ROOT: ${{ github.workspace }} strategy: matrix: cmake: [ @@ -18,6 +22,35 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Checkout Knitro Linux + uses: actions/checkout@v4 + with: + repository: yojvr/knitro1400-Linux64 + path: knitro_distrib + token: ${{ secrets.KNITRO_DISTRIB }} + - name: Untar large files + run: | + cd ${{ env.KNITRODIR }} + cd knitromatlab + tar -xzf knitromatlab_mex.mexa64.tar.gz + rm knitromatlab_mex.mexa64.tar.gz + cd ../knitroampl + tar -xzf knitroampl.tar.gz + rm knitroampl.tar.gz + cd ../lib + tar -xzf libknitro1400.a.tar.gz + tar -xzf libknitro1400.so.tar.gz + rm libknitro1400.*.tar.gz + - name: Copy license + run: | + echo "${{ secrets.KNITRO_DISTRIB_LICENSE }}" >> ${{ env.ARTELYS_LICENSE }}/artelys_lic_cicd.txt + - name: Check Knitro install + run: | + ls -l ${{ env.ARTELYS_LICENSE }} + ls -l ${{ env.KNITRODIR }} + ls -l ${{ env.KNITRODIR }}/lib + ls -l ${{ env.KNITRODIR }}/knitroampl + ls -l ${{ env.KNITRODIR }}/knitromatlab - name: Install Ninja run: | sudo apt-get update diff --git a/.github/workflows/amd64_linux_cmake_glpk_on.yml b/.github/workflows/amd64_linux_cmake_glpk_on.yml deleted file mode 100644 index ba6acab4fac..00000000000 --- a/.github/workflows/amd64_linux_cmake_glpk_on.yml +++ /dev/null @@ -1,41 +0,0 @@ -# ref: https://github.com/actions/runner-images -name: amd64 Linux CMake GLPK ON - -on: [push, pull_request, workflow_dispatch] - -# Building using the github runner environement directly. -jobs: - native: - name: Linux • CMake • GLPK ON - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Check cmake - run: cmake --version - - name: Configure - run: > - cmake -S. -Bbuild - -DCMAKE_BUILD_TYPE=Release - -DBUILD_DEPS=ON - -DUSE_SCIP=OFF -DUSE_COINOR=OFF - -DUSE_GLPK=ON - - name: Build - run: > - cmake --build build - --config Release - --target all - -v -j2 - - name: Test - run: > - CTEST_OUTPUT_ON_FAILURE=1 - cmake --build build - --config Release - --target test - -v - - name: Install - run: > - cmake --build build - --config Release - --target install - -v - -- DESTDIR=install diff --git a/.github/workflows/amd64_linux_cmake_java.yml b/.github/workflows/amd64_linux_cmake_java.yml index 27ef4936389..edf3840ca7a 100644 --- a/.github/workflows/amd64_linux_cmake_java.yml +++ b/.github/workflows/amd64_linux_cmake_java.yml @@ -43,4 +43,4 @@ jobs: cmake --build build --config Release --target install - -v + -v \ No newline at end of file diff --git a/.github/workflows/amd64_linux_cmake_no_lp_parser.yml b/.github/workflows/amd64_linux_cmake_no_lp_parser.yml deleted file mode 100644 index 9da054149ef..00000000000 --- a/.github/workflows/amd64_linux_cmake_no_lp_parser.yml +++ /dev/null @@ -1,40 +0,0 @@ -# ref: https://github.com/actions/runner-images -name: amd64 Linux CMake C++ LP_PARSER OFF - -on: [push, pull_request, workflow_dispatch] - -# Building using the github runner environement directly. -jobs: - native: - name: Linux • CMake • LP_PARSER OFF - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Check cmake - run: cmake --version - - name: Configure - run: > - cmake -S. -Bbuild - -DCMAKE_BUILD_TYPE=Release - -DBUILD_DEPS=ON - -DBUILD_LP_PARSER=OFF - - name: Build - run: > - cmake --build build - --config Release - --target all - -v -j2 - - name: Test - run: > - CTEST_OUTPUT_ON_FAILURE=1 - cmake --build build - --config Release - --target test - -v - - name: Install - run: > - cmake --build build - --config Release - --target install - -v - -- DESTDIR=install diff --git a/.github/workflows/amd64_linux_cmake_system_deps.yml b/.github/workflows/amd64_linux_cmake_system_deps.yml deleted file mode 100644 index c818ca9b149..00000000000 --- a/.github/workflows/amd64_linux_cmake_system_deps.yml +++ /dev/null @@ -1,39 +0,0 @@ -# Test or-tools using system wide install dependencies. -name: amd64 Linux CMake System Dependencies - -on: [push, pull_request, workflow_dispatch] - -jobs: - native: - strategy: - matrix: - distro: [system_deps] - lang: [cpp, python, dotnet, java] - fail-fast: false - name: Archlinux • CMake • ${{ matrix.lang }} • BUILD_DEPS OFF - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build base image - run: make --directory=cmake ${{ matrix.distro }}_base - - name: Build env image - run: make --directory=cmake ${{ matrix.distro }}_${{ matrix.lang }}_env - - name: Build devel image - run: make --directory=cmake ${{ matrix.distro }}_${{ matrix.lang }}_devel - - name: Build project - run: make --directory=cmake ${{ matrix.distro }}_${{ matrix.lang }}_build - - name: Test project - run: make --directory=cmake ${{ matrix.distro }}_${{ matrix.lang }}_test - - - name: Build Install env image - run: make --directory=cmake ${{ matrix.distro }}_${{ matrix.lang }}_install_env - - name: Build Install devel image - run: make --directory=cmake ${{ matrix.distro }}_${{ matrix.lang }}_install_devel - - name: Build Install - run: make --directory=cmake ${{ matrix.distro }}_${{ matrix.lang }}_install_build - - name: Test Install - run: make --directory=cmake ${{ matrix.distro }}_${{ matrix.lang }}_install_test - -# TODO(user): Add macOS + brew job -# TODO(user): Add Windows + choco/vcpkg job - diff --git a/.github/workflows/amd64_web.yml b/.github/workflows/amd64_web.yml deleted file mode 100644 index 06150646dcc..00000000000 --- a/.github/workflows/amd64_web.yml +++ /dev/null @@ -1,23 +0,0 @@ -# ref: https://github.com/docker-library/official-images -name: amd64 Web - -on: [push, pull_request, workflow_dispatch] - -jobs: - emscripten: - name: Linux • Emscripten - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Check docker - run: | - docker info - docker buildx ls - - name: Build env image - run: make --directory=cmake web_env - - name: Build devel project - run: make --directory=cmake web_devel - - name: Build project - run: make --directory=cmake web_build - - name: Test project - run: make --directory=cmake web_test diff --git a/.github/workflows/amd64_windows_cmake_cpp.yml b/.github/workflows/amd64_windows_cmake_cpp.yml index 05a8917acb0..1c728b08bf9 100644 --- a/.github/workflows/amd64_windows_cmake_cpp.yml +++ b/.github/workflows/amd64_windows_cmake_cpp.yml @@ -6,6 +6,10 @@ on: [push, pull_request, workflow_dispatch] # Building using the github runner environement directly. jobs: native: + env : + KNITRODIR: ${{ github.workspace }}\knitro_distrib\knitro-14.0.0-Win64 + ARTELYS_LICENSE: ${{ github.workspace }}\knitro_distrib + OR_ROOT: ${{ github.workspace }} strategy: matrix: cmake: [ @@ -18,7 +22,36 @@ jobs: env: CTEST_OUTPUT_ON_FAILURE: 1 steps: - - uses: actions/checkout@v4 + - name: Checkout or-tools + uses: actions/checkout@v4 + - name: Checkout Knitro Windows + uses: actions/checkout@v4 + with: + repository: yojvr/knitro1400-Win64 + path: knitro_distrib + token: ${{ secrets.KNITRO_DISTRIB }} + - name: Unzip + run: | + 7z x "${{ env.KNITRODIR }}/knitroampl/knitroampl.zip" -o"${{ env.KNITRODIR }}/knitroampl" + 7z x "${{ env.KNITRODIR }}/knitromatlab/knitromatlab_mex.zip" -o"${{ env.KNITRODIR }}/knitromatlab" + 7z x "${{ env.KNITRODIR }}/lib/knitro.zip" -o"${{ env.KNITRODIR }}/lib" + rm ${{ env.KNITRODIR }}/knitroampl/knitroampl.zip + rm ${{ env.KNITRODIR }}/knitromatlab/knitromatlab_mex.zip + rm ${{ env.KNITRODIR }}/lib/knitro.zip + - name: Copy license + run: | + echo "${{ secrets.KNITRO_DISTRIB_LICENSE }}" >> ${{ env.ARTELYS_LICENSE }}/artelys_lic_cicd.txt + - name: Grant access to knitro distrib + run: | + icacls ${{ env.KNITRODIR }} /grant Everyone:RX /t + - name: Check what I have + run: | + ls -l . + ls -l ${{ env.ARTELYS_LICENSE }} + ls -l ${{ env.KNITRODIR }} + ls -l ${{ env.KNITRODIR }}/knitroampl/ + ls -l ${{ env.KNITRODIR }}/knitromatlab/ + ls -l ${{ env.KNITRODIR }}/lib/ - name: Check cmake run: | cmake --version @@ -29,6 +62,8 @@ jobs: -G "${{ matrix.cmake.generator }}" -DCMAKE_CONFIGURATION_TYPES=${{ matrix.cmake.config }} -DBUILD_DEPS=ON + -DUSE_KNITRO=ON + -DBUILD_TESTING=ON -DCMAKE_INSTALL_PREFIX=install - name: Build run: > diff --git a/.github/workflows/amd64_windows_cmake_java.yml b/.github/workflows/amd64_windows_cmake_java.yml index 190ebf7d3ff..8c5da91087a 100644 --- a/.github/workflows/amd64_windows_cmake_java.yml +++ b/.github/workflows/amd64_windows_cmake_java.yml @@ -63,6 +63,7 @@ jobs: -v -j2 - name: Test run: > + CTEST_OUTPUT_ON_FAILURE=1 cmake --build build --config ${{ matrix.cmake.config }} --target ${{ matrix.cmake.test_target }} @@ -72,4 +73,4 @@ jobs: cmake --build build --config ${{ matrix.cmake.config }} --target ${{ matrix.cmake.install_target }} - -v + -v \ No newline at end of file diff --git a/.github/workflows/check_format.yml b/.github/workflows/check_format.yml deleted file mode 100644 index 16bedf598bb..00000000000 --- a/.github/workflows/check_format.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Check Format - -on: [push, pull_request, workflow_dispatch] - -jobs: - # Building using the github runner environement directly. - clang-format: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Fetch origin/main - run: git fetch origin main - - name: List of changed file(s) - run: git diff --name-only FETCH_HEAD - - - name: Build clang-format docker - run: cd .github/workflows && docker build --tag=linter . - - name: Check clang-format - run: docker run --rm --init -v $(pwd):/repo linter:latest clang-format --version - - name: clang-format help - run: docker run --rm --init -v $(pwd):/repo linter:latest clang-format --help - - - name: Check current commit - run: docker run --rm --init -v $(pwd):/repo -w /repo linter:latest sh -c "git diff --diff-filter=d --name-only FETCH_HEAD | grep '\.c$\|\.h$\|\.cc$\|\.java$\|\.cs$' | xargs clang-format --verbose --style=file --dry-run --Werror " diff --git a/.github/workflows/linux_knitro_tests.yml b/.github/workflows/linux_knitro_tests.yml new file mode 100644 index 00000000000..9dec24e6029 --- /dev/null +++ b/.github/workflows/linux_knitro_tests.yml @@ -0,0 +1,68 @@ +# ref: https://github.com/actions/runner-images +name: Linux Knitro Test + +on: [push, pull_request, workflow_dispatch] + +# Building using the github runner environement directly. +jobs: + native: + env: + KNITRODIR: ${{ github.workspace }}/knitro_distrib/knitro-14.0.0-Linux64 + ARTELYS_LICENSE: ${{ github.workspace }}/knitro_distrib + OR_ROOT: ${{ github.workspace }} + strategy: + matrix: + cmake: [ + {generator: "Unix Makefiles", config: "Release", binDir: ""}, + {generator: "Ninja", config: "Release", binDir: ""}, + {generator: "Ninja Multi-Config", config: "Release", binDir: "RELEASE"}, + ] + fail-fast: false + name: Linux • Knitro Test • C++ + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Checkout Knitro Linux + uses: actions/checkout@v4 + with: + repository: yojvr/knitro1400-Linux64 + path: knitro_distrib + token: ${{ secrets.KNITRO_DISTRIB }} + - name: Untar large files + run: | + cd ${{ env.KNITRODIR }} + cd knitromatlab + tar -xzf knitromatlab_mex.mexa64.tar.gz + rm knitromatlab_mex.mexa64.tar.gz + cd ../knitroampl + tar -xzf knitroampl.tar.gz + rm knitroampl.tar.gz + cd ../lib + tar -xzf libknitro1400.a.tar.gz + tar -xzf libknitro1400.so.tar.gz + rm libknitro1400.*.tar.gz + - name: Copy license + run: | + echo "${{ secrets.KNITRO_DISTRIB_LICENSE }}" >> ${{ env.ARTELYS_LICENSE }}/artelys_lic_cicd.txt + - name: Install Ninja + run: | + sudo apt-get update + sudo apt-get install ninja-build + - name: Check cmake + run: cmake --version + - name: Configure + run: > + cmake -S. -Bbuild + -G "${{ matrix.cmake.generator }}" + -DCMAKE_BUILD_TYPE="$BUILD_TYPE" + -DBUILD_DEPS=ON + -DCMAKE_INSTALL_PREFIX=install + - name: Build + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target all + -v -j2 + - name: Run Knitro Test + run: > + ./build/${{ matrix.cmake.binDir }}/bin/test_knitro_interface diff --git a/.github/workflows/windows_knitro_tests.yml b/.github/workflows/windows_knitro_tests.yml new file mode 100644 index 00000000000..a0e4c83713f --- /dev/null +++ b/.github/workflows/windows_knitro_tests.yml @@ -0,0 +1,72 @@ +# ref: https://github.com/actions/runner-images +name: Windows knitro tests + +on: [push, pull_request, workflow_dispatch] + +# Building using the github runner environement directly. +jobs: + native: + env : + KNITRODIR: ${{ github.workspace }}\knitro_distrib\knitro-14.0.0-Win64 + ARTELYS_LICENSE: ${{ github.workspace }}\knitro_distrib + OR_ROOT: ${{ github.workspace }} + strategy: + matrix: + cmake: [ + {generator: "Visual Studio 17 2022", config: Release, build_target: ALL_BUILD, test_target: RUN_TESTS, install_target: INSTALL}, + ] + fail-fast: false + name: Windows • Knitro Test • C++ + runs-on: windows-latest + steps: + - name: Checkout or-tools + uses: actions/checkout@v4 + - name: Checkout Knitro Windows + uses: actions/checkout@v4 + with: + repository: yojvr/knitro1400-Win64 + path: knitro_distrib + token: ${{ secrets.KNITRO_DISTRIB }} + - name: Unzip + run: | + unzip "${{ env.KNITRODIR }}/knitroampl/knitroampl.zip" -d "${{ env.KNITRODIR }}/knitroampl" + unzip "${{ env.KNITRODIR }}/knitromatlab/knitromatlab_mex.zip" -d "${{ env.KNITRODIR }}/knitromatlab" + unzip "${{ env.KNITRODIR }}/lib/knitro.zip" -d "${{ env.KNITRODIR }}/lib" + rm ${{ env.KNITRODIR }}/knitroampl/knitroampl.zip + rm ${{ env.KNITRODIR }}/knitromatlab/knitromatlab_mex.zip + rm ${{ env.KNITRODIR }}/lib/knitro.zip + - name: Copy license + run: | + echo "${{ secrets.KNITRO_DISTRIB_LICENSE }}" >> ${{ env.ARTELYS_LICENSE }}/artelys_lic_cicd.txt + - name: Grant access to knitro distrib + run: | + icacls ${{ env.KNITRODIR }} /grant Everyone:RX /t + - name: Check cmake + run: | + cmake --version + cmake -G || true + - name: Configure + run: > + cmake -S. -Bbuild + -G "${{ matrix.cmake.generator }}" + -DCMAKE_BUILD_TYPE=${{ matrix.cmake.config }} + -DBUILD_DEPS=ON + -DUSE_KNITRO=ON + -DBUILD_TESTING=ON + - name: Build + run: > + cmake --build build + --config ${{ matrix.cmake.config }} + --target ${{ matrix.cmake.build_target }} + -v -j2 + - name: Check Build dir + run: | + ls -l . + ls -l ${{ env.ARTELYS_LICENSE }} + ls -l ${{ env.KNITRODIR }} + ls -l ${{ env.KNITRODIR }}/knitroampl/ + ls -l ${{ env.KNITRODIR }}/knitromatlab/ + ls -l ${{ env.KNITRODIR }}/lib/ + - name: Run Knitro Test + run: > + ./build/RELEASE/bin/test_knitro_interface diff --git a/.gitignore b/.gitignore index fdebdf0ccc5..c9b7a197937 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,7 @@ CMakeFiles DartConfiguration.tcl *build*/* build/ + +# workflow stuff +.github/workflows/hyrae/ +.github/workflows/not_used/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fd2682a29b..695133b375a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,6 +313,10 @@ message(STATUS "CPLEX support: ${USE_CPLEX}") CMAKE_DEPENDENT_OPTION(USE_XPRESS "Use the Xpress solver" ON "BUILD_CXX" OFF) message(STATUS "Xpress support: ${USE_XPRESS}") +## KNITRO +CMAKE_DEPENDENT_OPTION(USE_KNITRO "Use the Knitro solver" ON "BUILD_CXX" OFF) +message(STATUS "Knitro support: ${USE_KNITRO}") + # Language specific options if(BUILD_CXX) CMAKE_DEPENDENT_OPTION(BUILD_CXX_DOC "Build the C++ doc" OFF "NOT BUILD_DOC" ON) diff --git a/bazel/notebook_requirements.txt b/bazel/notebook_requirements.txt index 3c4a2bbc3ed..0ca37a6b7ed 100644 --- a/bazel/notebook_requirements.txt +++ b/bazel/notebook_requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.12 # by the following command: # # bazel run //bazel:notebook_requirements.update diff --git a/bazel/ortools_requirements.txt b/bazel/ortools_requirements.txt index f32aeb1dba3..85f3902027d 100644 --- a/bazel/ortools_requirements.txt +++ b/bazel/ortools_requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.12 # by the following command: # # bazel run //bazel:ortools_requirements.update diff --git a/cmake/cpp.cmake b/cmake/cpp.cmake index b099b35ab38..8c9ecf16c44 100644 --- a/cmake/cpp.cmake +++ b/cmake/cpp.cmake @@ -518,6 +518,7 @@ foreach(SUBPROJECT IN ITEMS ${PDLP_DIR} sat xpress + knitro lp_data packing routing diff --git a/ortools/graph/BUILD.bazel b/ortools/graph/BUILD.bazel index 58fd4301699..188bea7ec5b 100644 --- a/ortools/graph/BUILD.bazel +++ b/ortools/graph/BUILD.bazel @@ -447,6 +447,7 @@ cc_library( ":graph", ":graphs", "//ortools/base", + "//ortools/base:types", "//ortools/util:stats", "//ortools/util:zvector", "@com_google_absl//absl/log:check", diff --git a/ortools/java/Doxyfile.in b/ortools/java/Doxyfile.in index 5e35f022815..cd0afa91a64 100644 --- a/ortools/java/Doxyfile.in +++ b/ortools/java/Doxyfile.in @@ -2314,7 +2314,8 @@ PREDEFINED = USE_BOP \ USE_PDLP \ USE_SCIP \ USE_CPLEX \ - USE_XPRESS + USE_XPRESS \ + USE_KNITRO # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/ortools/knitro/BUILD.bazel b/ortools/knitro/BUILD.bazel new file mode 100644 index 00000000000..22b6ed93eb0 --- /dev/null +++ b/ortools/knitro/BUILD.bazel @@ -0,0 +1,35 @@ +# Copyright 2010-2024 Google LLC +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "environment", + srcs = [ + "environment.cc", + ], + hdrs = [ + "environment.h", + ], + deps = [ + "//ortools/base", + "//ortools/base:dynamic_library", + "//ortools/base:file", + "//ortools/base:status_macros", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/types:optional", + ], +) diff --git a/ortools/knitro/CMakeLists.txt b/ortools/knitro/CMakeLists.txt new file mode 100644 index 00000000000..d19f6ea618c --- /dev/null +++ b/ortools/knitro/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright 2010-2024 Google LLC +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +file(GLOB _SRCS "*.h" "*.cc") +set(NAME ${PROJECT_NAME}_knitro) + +add_library(${NAME} OBJECT ${_SRCS}) +set_target_properties(${NAME} PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF + POSITION_INDEPENDENT_CODE ON + ) +target_include_directories(${NAME} PRIVATE + ${PROJECT_SOURCE_DIR} + ${PROJECT_BINARY_DIR}) +target_link_libraries(${NAME} PRIVATE + absl::hash + absl::meta + absl::memory + absl::strings + absl::str_format + protobuf::libprotobuf + ${PROJECT_NAMESPACE}::${PROJECT_NAME}_proto) diff --git a/ortools/knitro/environment.cc b/ortools/knitro/environment.cc new file mode 100644 index 00000000000..57e9b32ee7e --- /dev/null +++ b/ortools/knitro/environment.cc @@ -0,0 +1,1440 @@ +// INSERT HEADER + +#include "ortools/knitro/environment.h" + +#include +#include +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/synchronization/mutex.h" +#include "ortools/base/dynamic_library.h" +#include "ortools/base/logging.h" + +namespace operations_research { + +// 'define' section +std::function + KN_get_release = nullptr; +std::function KN_new = nullptr; +std::function KN_free = nullptr; +std::function KN_checkout_license = + nullptr; +std::function + KN_new_lm = nullptr; +std::function KN_release_license = nullptr; +std::function KN_reset_params_to_defaults = + nullptr; +std::function + KN_load_param_file = nullptr; +std::function + KN_load_tuner_file = nullptr; +std::function + KN_save_param_file = nullptr; +std::function + KN_set_int_param_by_name = nullptr; +std::function + KN_set_char_param_by_name = nullptr; +std::function + KN_set_double_param_by_name = nullptr; +std::function + KN_set_param_by_name = nullptr; +std::function + KN_set_int_param = nullptr; +std::function + KN_set_char_param = nullptr; +std::function + KN_set_double_param = nullptr; +std::function + KN_get_int_param_by_name = nullptr; +std::function + KN_get_double_param_by_name = nullptr; +std::function + KN_get_int_param = nullptr; +std::function + KN_get_double_param = nullptr; +std::function + KN_get_param_name = nullptr; +std::function + KN_get_param_doc = nullptr; +std::function + KN_get_param_type = nullptr; +std::function + KN_get_num_param_values = nullptr; +std::function + KN_get_param_value_doc = nullptr; +std::function + KN_get_param_id = nullptr; +std::function + KN_add_vars = nullptr; +std::function + KN_add_var = nullptr; +std::function + KN_add_cons = nullptr; +std::function + KN_add_con = nullptr; +std::function + KN_add_rsds = nullptr; +std::function + KN_add_rsd = nullptr; +std::function + KN_set_var_lobnds = nullptr; +std::function + KN_set_var_lobnds_all = nullptr; +std::function + KN_set_var_lobnd = nullptr; +std::function + KN_set_var_upbnds = nullptr; +std::function + KN_set_var_upbnds_all = nullptr; +std::function + KN_set_var_upbnd = nullptr; +std::function + KN_set_var_fxbnds = nullptr; +std::function + KN_set_var_fxbnds_all = nullptr; +std::function + KN_set_var_fxbnd = nullptr; +std::function + KN_get_var_lobnds = nullptr; +std::function + KN_get_var_lobnds_all = nullptr; +std::function + KN_get_var_lobnd = nullptr; +std::function + KN_get_var_upbnds = nullptr; +std::function + KN_get_var_upbnds_all = nullptr; +std::function + KN_get_var_upbnd = nullptr; +std::function + KN_get_var_fxbnds = nullptr; +std::function + KN_get_var_fxbnds_all = nullptr; +std::function + KN_get_var_fxbnd = nullptr; +std::function + KN_set_var_types = nullptr; +std::function + KN_set_var_types_all = nullptr; +std::function + KN_set_var_type = nullptr; +std::function + KN_get_var_types = nullptr; +std::function + KN_get_var_types_all = nullptr; +std::function + KN_get_var_type = nullptr; +std::function + KN_set_var_properties = nullptr; +std::function + KN_set_var_properties_all = nullptr; +std::function + KN_set_var_property = nullptr; +std::function + KN_set_con_lobnds = nullptr; +std::function + KN_set_con_lobnds_all = nullptr; +std::function + KN_set_con_lobnd = nullptr; +std::function + KN_set_con_upbnds = nullptr; +std::function + KN_set_con_upbnds_all = nullptr; +std::function + KN_set_con_upbnd = nullptr; +std::function + KN_set_con_eqbnds = nullptr; +std::function + KN_set_con_eqbnds_all = nullptr; +std::function + KN_set_con_eqbnd = nullptr; +std::function + KN_get_con_lobnds = nullptr; +std::function + KN_get_con_lobnds_all = nullptr; +std::function + KN_get_con_lobnd = nullptr; +std::function + KN_get_con_upbnds = nullptr; +std::function + KN_get_con_upbnds_all = nullptr; +std::function + KN_get_con_upbnd = nullptr; +std::function + KN_get_con_eqbnds = nullptr; +std::function + KN_get_con_eqbnds_all = nullptr; +std::function + KN_get_con_eqbnd = nullptr; +std::function + KN_set_obj_property = nullptr; +std::function + KN_set_con_properties = nullptr; +std::function + KN_set_con_properties_all = nullptr; +std::function + KN_set_con_property = nullptr; +std::function + KN_set_obj_goal = nullptr; +std::function + KN_set_var_primal_init_values = nullptr; +std::function + KN_set_var_primal_init_values_all = nullptr; +std::function + KN_set_var_primal_init_value = nullptr; +std::function + KN_set_var_dual_init_values = nullptr; +std::function + KN_set_var_dual_init_values_all = nullptr; +std::function + KN_set_var_dual_init_value = nullptr; +std::function + KN_set_con_dual_init_values = nullptr; +std::function + KN_set_con_dual_init_values_all = nullptr; +std::function + KN_set_con_dual_init_value = nullptr; +std::function + KN_add_obj_constant = nullptr; +std::function KN_del_obj_constant = nullptr; +std::function + KN_chg_obj_constant = nullptr; +std::function + KN_add_con_constants = nullptr; +std::function + KN_add_con_constants_all = nullptr; +std::function + KN_add_con_constant = nullptr; +std::function + KN_del_con_constants = nullptr; +std::function KN_del_con_constants_all = + nullptr; +std::function + KN_del_con_constant = nullptr; +std::function + KN_chg_con_constants = nullptr; +std::function + KN_chg_con_constants_all = nullptr; +std::function + KN_chg_con_constant = nullptr; +std::function + KN_add_rsd_constants = nullptr; +std::function + KN_add_rsd_constants_all = nullptr; +std::function + KN_add_rsd_constant = nullptr; +std::function + KN_add_obj_linear_struct = nullptr; +std::function + KN_add_obj_linear_term = nullptr; +std::function + KN_del_obj_linear_struct = nullptr; +std::function + KN_del_obj_linear_term = nullptr; +std::function + KN_chg_obj_linear_struct = nullptr; +std::function + KN_chg_obj_linear_term = nullptr; +std::function + KN_add_con_linear_struct = nullptr; +std::function + KN_add_con_linear_struct_one = nullptr; +std::function + KN_add_con_linear_term = nullptr; +std::function + KN_del_con_linear_struct = nullptr; +std::function + KN_del_con_linear_struct_one = nullptr; +std::function + KN_del_con_linear_term = nullptr; +std::function + KN_chg_con_linear_struct = nullptr; +std::function + KN_chg_con_linear_struct_one = nullptr; +std::function + KN_chg_con_linear_term = nullptr; +std::function + KN_add_rsd_linear_struct = nullptr; +std::function + KN_add_rsd_linear_struct_one = nullptr; +std::function + KN_add_rsd_linear_term = nullptr; +std::function + KN_add_obj_quadratic_struct = nullptr; +std::function + KN_add_obj_quadratic_term = nullptr; +std::function + KN_add_con_quadratic_struct = nullptr; +std::function + KN_add_con_quadratic_struct_one = nullptr; +std::function + KN_add_con_quadratic_term = nullptr; +std::function + KN_add_con_L2norm = nullptr; +std::function + KN_set_compcons = nullptr; +std::function + KN_load_mps_file = nullptr; +std::function + KN_write_mps_file = nullptr; +std::function + KN_add_eval_callback = nullptr; +std::function + KN_add_eval_callback_all = nullptr; +std::function + KN_add_eval_callback_one = nullptr; +std::function + KN_add_lsq_eval_callback = nullptr; +std::function + KN_add_lsq_eval_callback_all = nullptr; +std::function + KN_add_lsq_eval_callback_one = nullptr; +std::function + KN_set_cb_grad = nullptr; +std::function + KN_set_cb_hess = nullptr; +std::function + KN_set_cb_rsd_jac = nullptr; +std::function + KN_set_cb_user_params = nullptr; +std::function + KN_set_cb_gradopt = nullptr; +std::function + KN_set_cb_relstepsizes = nullptr; +std::function + KN_set_cb_relstepsizes_all = nullptr; +std::function + KN_set_cb_relstepsize = nullptr; +std::function + KN_get_cb_number_cons = nullptr; +std::function + KN_get_cb_number_rsds = nullptr; +std::function + KN_get_cb_objgrad_nnz = nullptr; +std::function + KN_get_cb_jacobian_nnz = nullptr; +std::function + KN_get_cb_rsd_jacobian_nnz = nullptr; +std::function + KN_get_cb_hessian_nnz = nullptr; +std::function + KN_set_newpt_callback = nullptr; +std::function + KN_set_mip_node_callback = nullptr; +std::function + KN_set_mip_usercuts_callback = nullptr; +std::function + KN_set_mip_lazyconstraints_callback = nullptr; +std::function + KN_set_ms_process_callback = nullptr; +std::function + KN_set_ms_initpt_callback = nullptr; +std::function + KN_set_puts_callback = nullptr; +std::function + KN_set_linsolver_callback = nullptr; +std::function + KN_load_lp = nullptr; +std::function + KN_load_qp = nullptr; +std::function + KN_load_qcqp = nullptr; +std::function + KN_set_var_feastols = nullptr; +std::function + KN_set_var_feastols_all = nullptr; +std::function + KN_set_var_feastol = nullptr; +std::function + KN_set_con_feastols = nullptr; +std::function + KN_set_con_feastols_all = nullptr; +std::function + KN_set_con_feastol = nullptr; +std::function + KN_set_compcon_feastols = nullptr; +std::function + KN_set_compcon_feastols_all = nullptr; +std::function + KN_set_compcon_feastol = nullptr; +std::function + KN_set_var_scalings = nullptr; +std::function + KN_set_var_scalings_all = nullptr; +std::function + KN_set_var_scaling = nullptr; +std::function + KN_set_con_scalings = nullptr; +std::function + KN_set_con_scalings_all = nullptr; +std::function + KN_set_con_scaling = nullptr; +std::function + KN_set_compcon_scalings = nullptr; +std::function + KN_set_compcon_scalings_all = nullptr; +std::function + KN_set_compcon_scaling = nullptr; +std::function + KN_set_obj_scaling = nullptr; +std::function + KN_set_var_names = nullptr; +std::function + KN_set_var_names_all = nullptr; +std::function + KN_set_var_name = nullptr; +std::function + KN_set_con_names = nullptr; +std::function + KN_set_con_names_all = nullptr; +std::function + KN_set_con_name = nullptr; +std::function + KN_set_compcon_names = nullptr; +std::function + KN_set_compcon_names_all = nullptr; +std::function + KN_set_compcon_name = nullptr; +std::function + KN_set_obj_name = nullptr; +std::function + KN_get_var_names = nullptr; +std::function + KN_get_var_names_all = nullptr; +std::function + KN_get_var_name = nullptr; +std::function + KN_get_con_names = nullptr; +std::function + KN_get_con_names_all = nullptr; +std::function + KN_get_con_name = nullptr; +std::function + KN_set_var_honorbnds = nullptr; +std::function + KN_set_var_honorbnds_all = nullptr; +std::function + KN_set_var_honorbnd = nullptr; +std::function + KN_set_con_honorbnds = nullptr; +std::function + KN_set_con_honorbnds_all = nullptr; +std::function + KN_set_con_honorbnd = nullptr; +std::function + KN_set_mip_var_primal_init_values = nullptr; +std::function + KN_set_mip_var_primal_init_values_all = nullptr; +std::function + KN_set_mip_var_primal_init_value = nullptr; +std::function + KN_set_mip_branching_priorities = nullptr; +std::function + KN_set_mip_branching_priorities_all = nullptr; +std::function + KN_set_mip_branching_priority = nullptr; +std::function + KN_set_mip_intvar_strategies = nullptr; +std::function + KN_set_mip_intvar_strategies_all = nullptr; +std::function + KN_set_mip_intvar_strategy = nullptr; +std::function KN_solve = nullptr; +std::function KN_update = nullptr; +std::function + KN_get_number_vars = nullptr; +std::function + KN_get_number_cons = nullptr; +std::function + KN_get_number_compcons = nullptr; +std::function + KN_get_number_rsds = nullptr; +std::function + KN_get_number_FC_evals = nullptr; +std::function + KN_get_number_GA_evals = nullptr; +std::function + KN_get_number_H_evals = nullptr; +std::function + KN_get_number_HV_evals = nullptr; +std::function + KN_get_solve_time_cpu = nullptr; +std::function + KN_get_solve_time_real = nullptr; +std::function + KN_get_solution = nullptr; +std::function + KN_get_obj_value = nullptr; +std::function + KN_get_obj_type = nullptr; +std::function + KN_get_var_primal_values = nullptr; +std::function + KN_get_var_primal_values_all = nullptr; +std::function + KN_get_var_primal_value = nullptr; +std::function + KN_get_var_dual_values = nullptr; +std::function + KN_get_var_dual_values_all = nullptr; +std::function + KN_get_var_dual_value = nullptr; +std::function + KN_get_con_dual_values = nullptr; +std::function + KN_get_con_dual_values_all = nullptr; +std::function + KN_get_con_dual_value = nullptr; +std::function + KN_get_con_values = nullptr; +std::function + KN_get_con_values_all = nullptr; +std::function + KN_get_con_value = nullptr; +std::function + KN_get_con_types = nullptr; +std::function + KN_get_con_types_all = nullptr; +std::function + KN_get_con_type = nullptr; +std::function + KN_get_rsd_values = nullptr; +std::function + KN_get_rsd_values_all = nullptr; +std::function + KN_get_rsd_value = nullptr; +std::function + KN_get_var_viols = nullptr; +std::function + KN_get_var_viols_all = nullptr; +std::function + KN_get_var_viol = nullptr; +std::function + KN_get_con_viols = nullptr; +std::function + KN_get_con_viols_all = nullptr; +std::function + KN_get_con_viol = nullptr; +std::function + KN_get_presolve_error = nullptr; +std::function + KN_get_number_iters = nullptr; +std::function + KN_get_number_cg_iters = nullptr; +std::function + KN_get_abs_feas_error = nullptr; +std::function + KN_get_rel_feas_error = nullptr; +std::function + KN_get_abs_opt_error = nullptr; +std::function + KN_get_rel_opt_error = nullptr; +std::function + KN_get_objgrad_nnz = nullptr; +std::function + KN_get_objgrad_values = nullptr; +std::function + KN_get_objgrad_values_all = nullptr; +std::function + KN_get_jacobian_nnz = nullptr; +std::function + KN_get_jacobian_values = nullptr; +std::function + KN_get_jacobian_nnz_one = nullptr; +std::function + KN_get_jacobian_values_one = nullptr; +std::function + KN_get_rsd_jacobian_nnz = nullptr; +std::function + KN_get_rsd_jacobian_values = nullptr; +std::function + KN_get_hessian_nnz = nullptr; +std::function + KN_get_hessian_values = nullptr; +std::function + KN_get_mip_number_nodes = nullptr; +std::function + KN_get_mip_number_solves = nullptr; +std::function + KN_get_mip_abs_gap = nullptr; +std::function + KN_get_mip_rel_gap = nullptr; +std::function + KN_get_mip_incumbent_obj = nullptr; +std::function + KN_get_mip_relaxation_bnd = nullptr; +std::function + KN_get_mip_lastnode_obj = nullptr; +std::function + KN_get_mip_incumbent_x = nullptr; + +// auto generated +void LoadKnitroFunctions(DynamicLibrary* knitro_dynamic_library) { + knitro_dynamic_library->GetFunction(&KN_get_release, "KN_get_release"); + knitro_dynamic_library->GetFunction(&KN_new, "KN_new"); + knitro_dynamic_library->GetFunction(&KN_free, "KN_free"); + knitro_dynamic_library->GetFunction(&KN_checkout_license, + "KN_checkout_license"); + knitro_dynamic_library->GetFunction(&KN_new_lm, "KN_new_lm"); + knitro_dynamic_library->GetFunction(&KN_release_license, + "KN_release_license"); + knitro_dynamic_library->GetFunction(&KN_reset_params_to_defaults, + "KN_reset_params_to_defaults"); + knitro_dynamic_library->GetFunction(&KN_load_param_file, + "KN_load_param_file"); + knitro_dynamic_library->GetFunction(&KN_load_tuner_file, + "KN_load_tuner_file"); + knitro_dynamic_library->GetFunction(&KN_save_param_file, + "KN_save_param_file"); + knitro_dynamic_library->GetFunction(&KN_set_int_param_by_name, + "KN_set_int_param_by_name"); + knitro_dynamic_library->GetFunction(&KN_set_char_param_by_name, + "KN_set_char_param_by_name"); + knitro_dynamic_library->GetFunction(&KN_set_double_param_by_name, + "KN_set_double_param_by_name"); + knitro_dynamic_library->GetFunction(&KN_set_param_by_name, + "KN_set_param_by_name"); + knitro_dynamic_library->GetFunction(&KN_set_int_param, "KN_set_int_param"); + knitro_dynamic_library->GetFunction(&KN_set_char_param, "KN_set_char_param"); + knitro_dynamic_library->GetFunction(&KN_set_double_param, + "KN_set_double_param"); + knitro_dynamic_library->GetFunction(&KN_get_int_param_by_name, + "KN_get_int_param_by_name"); + knitro_dynamic_library->GetFunction(&KN_get_double_param_by_name, + "KN_get_double_param_by_name"); + knitro_dynamic_library->GetFunction(&KN_get_int_param, "KN_get_int_param"); + knitro_dynamic_library->GetFunction(&KN_get_double_param, + "KN_get_double_param"); + knitro_dynamic_library->GetFunction(&KN_get_param_name, "KN_get_param_name"); + knitro_dynamic_library->GetFunction(&KN_get_param_doc, "KN_get_param_doc"); + knitro_dynamic_library->GetFunction(&KN_get_param_type, "KN_get_param_type"); + knitro_dynamic_library->GetFunction(&KN_get_num_param_values, + "KN_get_num_param_values"); + knitro_dynamic_library->GetFunction(&KN_get_param_value_doc, + "KN_get_param_value_doc"); + knitro_dynamic_library->GetFunction(&KN_get_param_id, "KN_get_param_id"); + knitro_dynamic_library->GetFunction(&KN_add_vars, "KN_add_vars"); + knitro_dynamic_library->GetFunction(&KN_add_var, "KN_add_var"); + knitro_dynamic_library->GetFunction(&KN_add_cons, "KN_add_cons"); + knitro_dynamic_library->GetFunction(&KN_add_con, "KN_add_con"); + knitro_dynamic_library->GetFunction(&KN_add_rsds, "KN_add_rsds"); + knitro_dynamic_library->GetFunction(&KN_add_rsd, "KN_add_rsd"); + knitro_dynamic_library->GetFunction(&KN_set_var_lobnds, "KN_set_var_lobnds"); + knitro_dynamic_library->GetFunction(&KN_set_var_lobnds_all, + "KN_set_var_lobnds_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_lobnd, "KN_set_var_lobnd"); + knitro_dynamic_library->GetFunction(&KN_set_var_upbnds, "KN_set_var_upbnds"); + knitro_dynamic_library->GetFunction(&KN_set_var_upbnds_all, + "KN_set_var_upbnds_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_upbnd, "KN_set_var_upbnd"); + knitro_dynamic_library->GetFunction(&KN_set_var_fxbnds, "KN_set_var_fxbnds"); + knitro_dynamic_library->GetFunction(&KN_set_var_fxbnds_all, + "KN_set_var_fxbnds_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_fxbnd, "KN_set_var_fxbnd"); + knitro_dynamic_library->GetFunction(&KN_get_var_lobnds, "KN_get_var_lobnds"); + knitro_dynamic_library->GetFunction(&KN_get_var_lobnds_all, + "KN_get_var_lobnds_all"); + knitro_dynamic_library->GetFunction(&KN_get_var_lobnd, "KN_get_var_lobnd"); + knitro_dynamic_library->GetFunction(&KN_get_var_upbnds, "KN_get_var_upbnds"); + knitro_dynamic_library->GetFunction(&KN_get_var_upbnds_all, + "KN_get_var_upbnds_all"); + knitro_dynamic_library->GetFunction(&KN_get_var_upbnd, "KN_get_var_upbnd"); + knitro_dynamic_library->GetFunction(&KN_get_var_fxbnds, "KN_get_var_fxbnds"); + knitro_dynamic_library->GetFunction(&KN_get_var_fxbnds_all, + "KN_get_var_fxbnds_all"); + knitro_dynamic_library->GetFunction(&KN_get_var_fxbnd, "KN_get_var_fxbnd"); + knitro_dynamic_library->GetFunction(&KN_set_var_types, "KN_set_var_types"); + knitro_dynamic_library->GetFunction(&KN_set_var_types_all, + "KN_set_var_types_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_type, "KN_set_var_type"); + knitro_dynamic_library->GetFunction(&KN_get_var_types, "KN_get_var_types"); + knitro_dynamic_library->GetFunction(&KN_get_var_types_all, + "KN_get_var_types_all"); + knitro_dynamic_library->GetFunction(&KN_get_var_type, "KN_get_var_type"); + knitro_dynamic_library->GetFunction(&KN_set_var_properties, + "KN_set_var_properties"); + knitro_dynamic_library->GetFunction(&KN_set_var_properties_all, + "KN_set_var_properties_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_property, + "KN_set_var_property"); + knitro_dynamic_library->GetFunction(&KN_set_con_lobnds, "KN_set_con_lobnds"); + knitro_dynamic_library->GetFunction(&KN_set_con_lobnds_all, + "KN_set_con_lobnds_all"); + knitro_dynamic_library->GetFunction(&KN_set_con_lobnd, "KN_set_con_lobnd"); + knitro_dynamic_library->GetFunction(&KN_set_con_upbnds, "KN_set_con_upbnds"); + knitro_dynamic_library->GetFunction(&KN_set_con_upbnds_all, + "KN_set_con_upbnds_all"); + knitro_dynamic_library->GetFunction(&KN_set_con_upbnd, "KN_set_con_upbnd"); + knitro_dynamic_library->GetFunction(&KN_set_con_eqbnds, "KN_set_con_eqbnds"); + knitro_dynamic_library->GetFunction(&KN_set_con_eqbnds_all, + "KN_set_con_eqbnds_all"); + knitro_dynamic_library->GetFunction(&KN_set_con_eqbnd, "KN_set_con_eqbnd"); + knitro_dynamic_library->GetFunction(&KN_get_con_lobnds, "KN_get_con_lobnds"); + knitro_dynamic_library->GetFunction(&KN_get_con_lobnds_all, + "KN_get_con_lobnds_all"); + knitro_dynamic_library->GetFunction(&KN_get_con_lobnd, "KN_get_con_lobnd"); + knitro_dynamic_library->GetFunction(&KN_get_con_upbnds, "KN_get_con_upbnds"); + knitro_dynamic_library->GetFunction(&KN_get_con_upbnds_all, + "KN_get_con_upbnds_all"); + knitro_dynamic_library->GetFunction(&KN_get_con_upbnd, "KN_get_con_upbnd"); + knitro_dynamic_library->GetFunction(&KN_get_con_eqbnds, "KN_get_con_eqbnds"); + knitro_dynamic_library->GetFunction(&KN_get_con_eqbnds_all, + "KN_get_con_eqbnds_all"); + knitro_dynamic_library->GetFunction(&KN_get_con_eqbnd, "KN_get_con_eqbnd"); + knitro_dynamic_library->GetFunction(&KN_set_obj_property, + "KN_set_obj_property"); + knitro_dynamic_library->GetFunction(&KN_set_con_properties, + "KN_set_con_properties"); + knitro_dynamic_library->GetFunction(&KN_set_con_properties_all, + "KN_set_con_properties_all"); + knitro_dynamic_library->GetFunction(&KN_set_con_property, + "KN_set_con_property"); + knitro_dynamic_library->GetFunction(&KN_set_obj_goal, "KN_set_obj_goal"); + knitro_dynamic_library->GetFunction(&KN_set_var_primal_init_values, + "KN_set_var_primal_init_values"); + knitro_dynamic_library->GetFunction(&KN_set_var_primal_init_values_all, + "KN_set_var_primal_init_values_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_primal_init_value, + "KN_set_var_primal_init_value"); + knitro_dynamic_library->GetFunction(&KN_set_var_dual_init_values, + "KN_set_var_dual_init_values"); + knitro_dynamic_library->GetFunction(&KN_set_var_dual_init_values_all, + "KN_set_var_dual_init_values_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_dual_init_value, + "KN_set_var_dual_init_value"); + knitro_dynamic_library->GetFunction(&KN_set_con_dual_init_values, + "KN_set_con_dual_init_values"); + knitro_dynamic_library->GetFunction(&KN_set_con_dual_init_values_all, + "KN_set_con_dual_init_values_all"); + knitro_dynamic_library->GetFunction(&KN_set_con_dual_init_value, + "KN_set_con_dual_init_value"); + knitro_dynamic_library->GetFunction(&KN_add_obj_constant, + "KN_add_obj_constant"); + knitro_dynamic_library->GetFunction(&KN_del_obj_constant, + "KN_del_obj_constant"); + knitro_dynamic_library->GetFunction(&KN_chg_obj_constant, + "KN_chg_obj_constant"); + knitro_dynamic_library->GetFunction(&KN_add_con_constants, + "KN_add_con_constants"); + knitro_dynamic_library->GetFunction(&KN_add_con_constants_all, + "KN_add_con_constants_all"); + knitro_dynamic_library->GetFunction(&KN_add_con_constant, + "KN_add_con_constant"); + knitro_dynamic_library->GetFunction(&KN_del_con_constants, + "KN_del_con_constants"); + knitro_dynamic_library->GetFunction(&KN_del_con_constants_all, + "KN_del_con_constants_all"); + knitro_dynamic_library->GetFunction(&KN_del_con_constant, + "KN_del_con_constant"); + knitro_dynamic_library->GetFunction(&KN_chg_con_constants, + "KN_chg_con_constants"); + knitro_dynamic_library->GetFunction(&KN_chg_con_constants_all, + "KN_chg_con_constants_all"); + knitro_dynamic_library->GetFunction(&KN_chg_con_constant, + "KN_chg_con_constant"); + knitro_dynamic_library->GetFunction(&KN_add_rsd_constants, + "KN_add_rsd_constants"); + knitro_dynamic_library->GetFunction(&KN_add_rsd_constants_all, + "KN_add_rsd_constants_all"); + knitro_dynamic_library->GetFunction(&KN_add_rsd_constant, + "KN_add_rsd_constant"); + knitro_dynamic_library->GetFunction(&KN_add_obj_linear_struct, + "KN_add_obj_linear_struct"); + knitro_dynamic_library->GetFunction(&KN_add_obj_linear_term, + "KN_add_obj_linear_term"); + knitro_dynamic_library->GetFunction(&KN_del_obj_linear_struct, + "KN_del_obj_linear_struct"); + knitro_dynamic_library->GetFunction(&KN_del_obj_linear_term, + "KN_del_obj_linear_term"); + knitro_dynamic_library->GetFunction(&KN_chg_obj_linear_struct, + "KN_chg_obj_linear_struct"); + knitro_dynamic_library->GetFunction(&KN_chg_obj_linear_term, + "KN_chg_obj_linear_term"); + knitro_dynamic_library->GetFunction(&KN_add_con_linear_struct, + "KN_add_con_linear_struct"); + knitro_dynamic_library->GetFunction(&KN_add_con_linear_struct_one, + "KN_add_con_linear_struct_one"); + knitro_dynamic_library->GetFunction(&KN_add_con_linear_term, + "KN_add_con_linear_term"); + knitro_dynamic_library->GetFunction(&KN_del_con_linear_struct, + "KN_del_con_linear_struct"); + knitro_dynamic_library->GetFunction(&KN_del_con_linear_struct_one, + "KN_del_con_linear_struct_one"); + knitro_dynamic_library->GetFunction(&KN_del_con_linear_term, + "KN_del_con_linear_term"); + knitro_dynamic_library->GetFunction(&KN_chg_con_linear_struct, + "KN_chg_con_linear_struct"); + knitro_dynamic_library->GetFunction(&KN_chg_con_linear_struct_one, + "KN_chg_con_linear_struct_one"); + knitro_dynamic_library->GetFunction(&KN_chg_con_linear_term, + "KN_chg_con_linear_term"); + knitro_dynamic_library->GetFunction(&KN_add_rsd_linear_struct, + "KN_add_rsd_linear_struct"); + knitro_dynamic_library->GetFunction(&KN_add_rsd_linear_struct_one, + "KN_add_rsd_linear_struct_one"); + knitro_dynamic_library->GetFunction(&KN_add_rsd_linear_term, + "KN_add_rsd_linear_term"); + knitro_dynamic_library->GetFunction(&KN_add_obj_quadratic_struct, + "KN_add_obj_quadratic_struct"); + knitro_dynamic_library->GetFunction(&KN_add_obj_quadratic_term, + "KN_add_obj_quadratic_term"); + knitro_dynamic_library->GetFunction(&KN_add_con_quadratic_struct, + "KN_add_con_quadratic_struct"); + knitro_dynamic_library->GetFunction(&KN_add_con_quadratic_struct_one, + "KN_add_con_quadratic_struct_one"); + knitro_dynamic_library->GetFunction(&KN_add_con_quadratic_term, + "KN_add_con_quadratic_term"); + knitro_dynamic_library->GetFunction(&KN_add_con_L2norm, "KN_add_con_L2norm"); + knitro_dynamic_library->GetFunction(&KN_set_compcons, "KN_set_compcons"); + knitro_dynamic_library->GetFunction(&KN_load_mps_file, "KN_load_mps_file"); + knitro_dynamic_library->GetFunction(&KN_write_mps_file, "KN_write_mps_file"); + knitro_dynamic_library->GetFunction(&KN_add_eval_callback, + "KN_add_eval_callback"); + knitro_dynamic_library->GetFunction(&KN_add_eval_callback_all, + "KN_add_eval_callback_all"); + knitro_dynamic_library->GetFunction(&KN_add_eval_callback_one, + "KN_add_eval_callback_one"); + knitro_dynamic_library->GetFunction(&KN_add_lsq_eval_callback, + "KN_add_lsq_eval_callback"); + knitro_dynamic_library->GetFunction(&KN_add_lsq_eval_callback_all, + "KN_add_lsq_eval_callback_all"); + knitro_dynamic_library->GetFunction(&KN_add_lsq_eval_callback_one, + "KN_add_lsq_eval_callback_one"); + knitro_dynamic_library->GetFunction(&KN_set_cb_grad, "KN_set_cb_grad"); + knitro_dynamic_library->GetFunction(&KN_set_cb_hess, "KN_set_cb_hess"); + knitro_dynamic_library->GetFunction(&KN_set_cb_rsd_jac, "KN_set_cb_rsd_jac"); + knitro_dynamic_library->GetFunction(&KN_set_cb_user_params, + "KN_set_cb_user_params"); + knitro_dynamic_library->GetFunction(&KN_set_cb_gradopt, "KN_set_cb_gradopt"); + knitro_dynamic_library->GetFunction(&KN_set_cb_relstepsizes, + "KN_set_cb_relstepsizes"); + knitro_dynamic_library->GetFunction(&KN_set_cb_relstepsizes_all, + "KN_set_cb_relstepsizes_all"); + knitro_dynamic_library->GetFunction(&KN_set_cb_relstepsize, + "KN_set_cb_relstepsize"); + knitro_dynamic_library->GetFunction(&KN_get_cb_number_cons, + "KN_get_cb_number_cons"); + knitro_dynamic_library->GetFunction(&KN_get_cb_number_rsds, + "KN_get_cb_number_rsds"); + knitro_dynamic_library->GetFunction(&KN_get_cb_objgrad_nnz, + "KN_get_cb_objgrad_nnz"); + knitro_dynamic_library->GetFunction(&KN_get_cb_jacobian_nnz, + "KN_get_cb_jacobian_nnz"); + knitro_dynamic_library->GetFunction(&KN_get_cb_rsd_jacobian_nnz, + "KN_get_cb_rsd_jacobian_nnz"); + knitro_dynamic_library->GetFunction(&KN_get_cb_hessian_nnz, + "KN_get_cb_hessian_nnz"); + knitro_dynamic_library->GetFunction(&KN_set_newpt_callback, + "KN_set_newpt_callback"); + knitro_dynamic_library->GetFunction(&KN_set_mip_node_callback, + "KN_set_mip_node_callback"); + knitro_dynamic_library->GetFunction(&KN_set_mip_usercuts_callback, + "KN_set_mip_usercuts_callback"); + knitro_dynamic_library->GetFunction(&KN_set_mip_lazyconstraints_callback, + "KN_set_mip_lazyconstraints_callback"); + knitro_dynamic_library->GetFunction(&KN_set_ms_process_callback, + "KN_set_ms_process_callback"); + knitro_dynamic_library->GetFunction(&KN_set_ms_initpt_callback, + "KN_set_ms_initpt_callback"); + knitro_dynamic_library->GetFunction(&KN_set_puts_callback, + "KN_set_puts_callback"); + knitro_dynamic_library->GetFunction(&KN_set_linsolver_callback, + "KN_set_linsolver_callback"); + knitro_dynamic_library->GetFunction(&KN_load_lp, "KN_load_lp"); + knitro_dynamic_library->GetFunction(&KN_load_qp, "KN_load_qp"); + knitro_dynamic_library->GetFunction(&KN_load_qcqp, "KN_load_qcqp"); + knitro_dynamic_library->GetFunction(&KN_set_var_feastols, + "KN_set_var_feastols"); + knitro_dynamic_library->GetFunction(&KN_set_var_feastols_all, + "KN_set_var_feastols_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_feastol, + "KN_set_var_feastol"); + knitro_dynamic_library->GetFunction(&KN_set_con_feastols, + "KN_set_con_feastols"); + knitro_dynamic_library->GetFunction(&KN_set_con_feastols_all, + "KN_set_con_feastols_all"); + knitro_dynamic_library->GetFunction(&KN_set_con_feastol, + "KN_set_con_feastol"); + knitro_dynamic_library->GetFunction(&KN_set_compcon_feastols, + "KN_set_compcon_feastols"); + knitro_dynamic_library->GetFunction(&KN_set_compcon_feastols_all, + "KN_set_compcon_feastols_all"); + knitro_dynamic_library->GetFunction(&KN_set_compcon_feastol, + "KN_set_compcon_feastol"); + knitro_dynamic_library->GetFunction(&KN_set_var_scalings, + "KN_set_var_scalings"); + knitro_dynamic_library->GetFunction(&KN_set_var_scalings_all, + "KN_set_var_scalings_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_scaling, + "KN_set_var_scaling"); + knitro_dynamic_library->GetFunction(&KN_set_con_scalings, + "KN_set_con_scalings"); + knitro_dynamic_library->GetFunction(&KN_set_con_scalings_all, + "KN_set_con_scalings_all"); + knitro_dynamic_library->GetFunction(&KN_set_con_scaling, + "KN_set_con_scaling"); + knitro_dynamic_library->GetFunction(&KN_set_compcon_scalings, + "KN_set_compcon_scalings"); + knitro_dynamic_library->GetFunction(&KN_set_compcon_scalings_all, + "KN_set_compcon_scalings_all"); + knitro_dynamic_library->GetFunction(&KN_set_compcon_scaling, + "KN_set_compcon_scaling"); + knitro_dynamic_library->GetFunction(&KN_set_obj_scaling, + "KN_set_obj_scaling"); + knitro_dynamic_library->GetFunction(&KN_set_var_names, "KN_set_var_names"); + knitro_dynamic_library->GetFunction(&KN_set_var_names_all, + "KN_set_var_names_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_name, "KN_set_var_name"); + knitro_dynamic_library->GetFunction(&KN_set_con_names, "KN_set_con_names"); + knitro_dynamic_library->GetFunction(&KN_set_con_names_all, + "KN_set_con_names_all"); + knitro_dynamic_library->GetFunction(&KN_set_con_name, "KN_set_con_name"); + knitro_dynamic_library->GetFunction(&KN_set_compcon_names, + "KN_set_compcon_names"); + knitro_dynamic_library->GetFunction(&KN_set_compcon_names_all, + "KN_set_compcon_names_all"); + knitro_dynamic_library->GetFunction(&KN_set_compcon_name, + "KN_set_compcon_name"); + knitro_dynamic_library->GetFunction(&KN_set_obj_name, "KN_set_obj_name"); + knitro_dynamic_library->GetFunction(&KN_get_var_names, "KN_get_var_names"); + knitro_dynamic_library->GetFunction(&KN_get_var_names_all, + "KN_get_var_names_all"); + knitro_dynamic_library->GetFunction(&KN_get_var_name, "KN_get_var_name"); + knitro_dynamic_library->GetFunction(&KN_get_con_names, "KN_get_con_names"); + knitro_dynamic_library->GetFunction(&KN_get_con_names_all, + "KN_get_con_names_all"); + knitro_dynamic_library->GetFunction(&KN_get_con_name, "KN_get_con_name"); + knitro_dynamic_library->GetFunction(&KN_set_var_honorbnds, + "KN_set_var_honorbnds"); + knitro_dynamic_library->GetFunction(&KN_set_var_honorbnds_all, + "KN_set_var_honorbnds_all"); + knitro_dynamic_library->GetFunction(&KN_set_var_honorbnd, + "KN_set_var_honorbnd"); + knitro_dynamic_library->GetFunction(&KN_set_con_honorbnds, + "KN_set_con_honorbnds"); + knitro_dynamic_library->GetFunction(&KN_set_con_honorbnds_all, + "KN_set_con_honorbnds_all"); + knitro_dynamic_library->GetFunction(&KN_set_con_honorbnd, + "KN_set_con_honorbnd"); + knitro_dynamic_library->GetFunction(&KN_set_mip_var_primal_init_values, + "KN_set_mip_var_primal_init_values"); + knitro_dynamic_library->GetFunction(&KN_set_mip_var_primal_init_values_all, + "KN_set_mip_var_primal_init_values_all"); + knitro_dynamic_library->GetFunction(&KN_set_mip_var_primal_init_value, + "KN_set_mip_var_primal_init_value"); + knitro_dynamic_library->GetFunction(&KN_set_mip_branching_priorities, + "KN_set_mip_branching_priorities"); + knitro_dynamic_library->GetFunction(&KN_set_mip_branching_priorities_all, + "KN_set_mip_branching_priorities_all"); + knitro_dynamic_library->GetFunction(&KN_set_mip_branching_priority, + "KN_set_mip_branching_priority"); + knitro_dynamic_library->GetFunction(&KN_set_mip_intvar_strategies, + "KN_set_mip_intvar_strategies"); + knitro_dynamic_library->GetFunction(&KN_set_mip_intvar_strategies_all, + "KN_set_mip_intvar_strategies_all"); + knitro_dynamic_library->GetFunction(&KN_set_mip_intvar_strategy, + "KN_set_mip_intvar_strategy"); + knitro_dynamic_library->GetFunction(&KN_solve, "KN_solve"); + knitro_dynamic_library->GetFunction(&KN_update, "KN_update"); + knitro_dynamic_library->GetFunction(&KN_get_number_vars, + "KN_get_number_vars"); + knitro_dynamic_library->GetFunction(&KN_get_number_cons, + "KN_get_number_cons"); + knitro_dynamic_library->GetFunction(&KN_get_number_compcons, + "KN_get_number_compcons"); + knitro_dynamic_library->GetFunction(&KN_get_number_rsds, + "KN_get_number_rsds"); + knitro_dynamic_library->GetFunction(&KN_get_number_FC_evals, + "KN_get_number_FC_evals"); + knitro_dynamic_library->GetFunction(&KN_get_number_GA_evals, + "KN_get_number_GA_evals"); + knitro_dynamic_library->GetFunction(&KN_get_number_H_evals, + "KN_get_number_H_evals"); + knitro_dynamic_library->GetFunction(&KN_get_number_HV_evals, + "KN_get_number_HV_evals"); + knitro_dynamic_library->GetFunction(&KN_get_solve_time_cpu, + "KN_get_solve_time_cpu"); + knitro_dynamic_library->GetFunction(&KN_get_solve_time_real, + "KN_get_solve_time_real"); + knitro_dynamic_library->GetFunction(&KN_get_solution, "KN_get_solution"); + knitro_dynamic_library->GetFunction(&KN_get_obj_value, "KN_get_obj_value"); + knitro_dynamic_library->GetFunction(&KN_get_obj_type, "KN_get_obj_type"); + knitro_dynamic_library->GetFunction(&KN_get_var_primal_values, + "KN_get_var_primal_values"); + knitro_dynamic_library->GetFunction(&KN_get_var_primal_values_all, + "KN_get_var_primal_values_all"); + knitro_dynamic_library->GetFunction(&KN_get_var_primal_value, + "KN_get_var_primal_value"); + knitro_dynamic_library->GetFunction(&KN_get_var_dual_values, + "KN_get_var_dual_values"); + knitro_dynamic_library->GetFunction(&KN_get_var_dual_values_all, + "KN_get_var_dual_values_all"); + knitro_dynamic_library->GetFunction(&KN_get_var_dual_value, + "KN_get_var_dual_value"); + knitro_dynamic_library->GetFunction(&KN_get_con_dual_values, + "KN_get_con_dual_values"); + knitro_dynamic_library->GetFunction(&KN_get_con_dual_values_all, + "KN_get_con_dual_values_all"); + knitro_dynamic_library->GetFunction(&KN_get_con_dual_value, + "KN_get_con_dual_value"); + knitro_dynamic_library->GetFunction(&KN_get_con_values, "KN_get_con_values"); + knitro_dynamic_library->GetFunction(&KN_get_con_values_all, + "KN_get_con_values_all"); + knitro_dynamic_library->GetFunction(&KN_get_con_value, "KN_get_con_value"); + knitro_dynamic_library->GetFunction(&KN_get_con_types, "KN_get_con_types"); + knitro_dynamic_library->GetFunction(&KN_get_con_types_all, + "KN_get_con_types_all"); + knitro_dynamic_library->GetFunction(&KN_get_con_type, "KN_get_con_type"); + knitro_dynamic_library->GetFunction(&KN_get_rsd_values, "KN_get_rsd_values"); + knitro_dynamic_library->GetFunction(&KN_get_rsd_values_all, + "KN_get_rsd_values_all"); + knitro_dynamic_library->GetFunction(&KN_get_rsd_value, "KN_get_rsd_value"); + knitro_dynamic_library->GetFunction(&KN_get_var_viols, "KN_get_var_viols"); + knitro_dynamic_library->GetFunction(&KN_get_var_viols_all, + "KN_get_var_viols_all"); + knitro_dynamic_library->GetFunction(&KN_get_var_viol, "KN_get_var_viol"); + knitro_dynamic_library->GetFunction(&KN_get_con_viols, "KN_get_con_viols"); + knitro_dynamic_library->GetFunction(&KN_get_con_viols_all, + "KN_get_con_viols_all"); + knitro_dynamic_library->GetFunction(&KN_get_con_viol, "KN_get_con_viol"); + knitro_dynamic_library->GetFunction(&KN_get_presolve_error, + "KN_get_presolve_error"); + knitro_dynamic_library->GetFunction(&KN_get_number_iters, + "KN_get_number_iters"); + knitro_dynamic_library->GetFunction(&KN_get_number_cg_iters, + "KN_get_number_cg_iters"); + knitro_dynamic_library->GetFunction(&KN_get_abs_feas_error, + "KN_get_abs_feas_error"); + knitro_dynamic_library->GetFunction(&KN_get_rel_feas_error, + "KN_get_rel_feas_error"); + knitro_dynamic_library->GetFunction(&KN_get_abs_opt_error, + "KN_get_abs_opt_error"); + knitro_dynamic_library->GetFunction(&KN_get_rel_opt_error, + "KN_get_rel_opt_error"); + knitro_dynamic_library->GetFunction(&KN_get_objgrad_nnz, + "KN_get_objgrad_nnz"); + knitro_dynamic_library->GetFunction(&KN_get_objgrad_values, + "KN_get_objgrad_values"); + knitro_dynamic_library->GetFunction(&KN_get_objgrad_values_all, + "KN_get_objgrad_values_all"); + knitro_dynamic_library->GetFunction(&KN_get_jacobian_nnz, + "KN_get_jacobian_nnz"); + knitro_dynamic_library->GetFunction(&KN_get_jacobian_values, + "KN_get_jacobian_values"); + knitro_dynamic_library->GetFunction(&KN_get_jacobian_nnz_one, + "KN_get_jacobian_nnz_one"); + knitro_dynamic_library->GetFunction(&KN_get_jacobian_values_one, + "KN_get_jacobian_values_one"); + knitro_dynamic_library->GetFunction(&KN_get_rsd_jacobian_nnz, + "KN_get_rsd_jacobian_nnz"); + knitro_dynamic_library->GetFunction(&KN_get_rsd_jacobian_values, + "KN_get_rsd_jacobian_values"); + knitro_dynamic_library->GetFunction(&KN_get_hessian_nnz, + "KN_get_hessian_nnz"); + knitro_dynamic_library->GetFunction(&KN_get_hessian_values, + "KN_get_hessian_values"); + knitro_dynamic_library->GetFunction(&KN_get_mip_number_nodes, + "KN_get_mip_number_nodes"); + knitro_dynamic_library->GetFunction(&KN_get_mip_number_solves, + "KN_get_mip_number_solves"); + knitro_dynamic_library->GetFunction(&KN_get_mip_abs_gap, + "KN_get_mip_abs_gap"); + knitro_dynamic_library->GetFunction(&KN_get_mip_rel_gap, + "KN_get_mip_rel_gap"); + knitro_dynamic_library->GetFunction(&KN_get_mip_incumbent_obj, + "KN_get_mip_incumbent_obj"); + knitro_dynamic_library->GetFunction(&KN_get_mip_relaxation_bnd, + "KN_get_mip_relaxation_bnd"); + knitro_dynamic_library->GetFunction(&KN_get_mip_lastnode_obj, + "KN_get_mip_lastnode_obj"); + knitro_dynamic_library->GetFunction(&KN_get_mip_incumbent_x, + "KN_get_mip_incumbent_x"); +} + +std::vector KnitroDynamicLibraryPotentialPaths() { + std::vector potential_paths; + + // Look for libraries pointed by KNITRODIR first. + const char* knitrodir_env = getenv("KNITRODIR"); + if (knitrodir_env != nullptr) { + LOG(INFO) << "Environment variable KNITRODIR = " << knitrodir_env; +#if defined(_MSC_VER) // Windows + potential_paths.push_back(absl::StrCat(knitrodir_env, "\\lib\\knitro.dll")); +#elif defined(__APPLE__) // OS X + potential_paths.push_back( + absl::StrCat(knitrodir_env, "/lib/libknitro.dylib")); +#elif defined(__GNUC__) // Linux + potential_paths.push_back(absl::StrCat(knitrodir_env, "/lib/libknitro.so")); +#else + LOG(ERROR) << "OS Not recognized by knitro/environment.cc." + << " You won't be able to use Knitro."; +#endif + } else { + LOG(WARNING) << "Environment variable KNITRODIR undefined."; + } + + return potential_paths; +} + +absl::Status LoadKnitroDynamicLibrary(std::string& knitropath) { + static std::string knitro_lib_path; + static std::once_flag knitro_loading_done; + static absl::Status knitro_load_status; + static DynamicLibrary knitro_library; + static absl::Mutex mutex(absl::kConstInit); + + absl::MutexLock lock(&mutex); + + std::call_once(knitro_loading_done, []() { + const std::vector canonical_paths = + KnitroDynamicLibraryPotentialPaths(); + for (const std::string& path : canonical_paths) { + const char* command = ("ls -l " + path).c_str(); + system("ls ."); + system(command); + if (knitro_library.TryToLoad(path)) { + LOG(INFO) << "Found the Knitro library in " << path << "."; + knitro_lib_path.clear(); + std::filesystem::path p(path); + p.remove_filename(); + knitro_lib_path.append(p.string()); + break; + } + } + + if (knitro_library.LibraryIsLoaded()) { + LOG(INFO) << "Loading all Knitro functions"; + LoadKnitroFunctions(&knitro_library); + + KN_context* kn = nullptr; + if (KN_new(&kn) != 0 || kn == nullptr) { + knitro_load_status = absl::InternalError( + absl::StrFormat("Failed while trying to generate a Knitro solver object")); + } else { + knitro_load_status = absl::OkStatus(); + KN_free(&kn); + } + } else { + knitro_load_status = absl::NotFoundError( + absl::StrCat("Could not find the Knitro shared library. Looked in: [", + absl::StrJoin(canonical_paths, "', '"), + "]. Please check environment variable KNITRODIR")); + } + }); + knitropath.clear(); + knitropath.append(knitro_lib_path); + return knitro_load_status; +} + +bool KnitroIsCorrectlyInstalled() { + std::string knitro_lib_dir; // TODO : A voir si on garde + absl::Status status = LoadKnitroDynamicLibrary(knitro_lib_dir); + if (!status.ok()) { + LOG(WARNING) << status << "\n"; + return false; + } + + return true; +} + +} // namespace operations_research diff --git a/ortools/knitro/environment.h b/ortools/knitro/environment.h new file mode 100644 index 00000000000..246a8fd5dcb --- /dev/null +++ b/ortools/knitro/environment.h @@ -0,0 +1,1776 @@ +// INSERT HEADER + +#ifndef OR_TOOLS_KNITRO_ENVIRONMENT_H_ +#define OR_TOOLS_KNITRO_ENVIRONMENT_H_ + +#include +#include + +#include "absl/status/status.h" + +// ****************************** +// * typedef +// ****************************** +extern "C" { +typedef int KNINT; +#ifdef _WIN64 +typedef __int64 KNLONG; +#elif _WIN32 +typedef int KNLONG; +#else +typedef long long KNLONG; +#endif +typedef KNINT KNBOOL; +typedef struct KN_context KN_context, *KN_context_ptr; +typedef struct LM_context LM_context, *LM_context_ptr; +typedef struct KN_eval_request { + int type; + int threadID; + const double* x; + const double* lambda; + const double* sigma; + const double* vec; +} KN_eval_request, *KN_eval_request_ptr; +typedef struct KN_eval_result { + double* obj; + double* c; + double* objGrad; + double* jac; + double* hess; + double* hessVec; + double* rsd; + double* rsdJac; +} KN_eval_result, *KN_eval_result_ptr; +typedef struct CB_context CB_context, *CB_context_ptr; +typedef int KN_eval_callback(KN_context_ptr kc, CB_context_ptr cb, + KN_eval_request_ptr const evalRequest, + KN_eval_result_ptr const evalResult, + void* const userParams); +typedef int KN_user_callback(KN_context_ptr kc, const double* const x, + const double* const lambda, + void* const userParams); +typedef int KN_ms_initpt_callback(KN_context_ptr kc, const KNINT nSolveNumber, + double* const x, double* const lambda, + void* const userParams); +typedef int KN_puts(const char* const str, void* const userParams); +typedef struct KN_linsolver_request { + int phase; + int linsysID; + int threadID; + KNINT n; + KNINT n11; + const double* rhs; + const double* values; + const KNINT* indexRows; + const KNLONG* ptrCols; +} KN_linsolver_request, *KN_linsolver_request_ptr; +typedef struct KN_linsolver_result { + double* solution; + KNINT negeig; + KNINT poseig; + KNINT rank; +} KN_linsolver_result, *KN_linsolver_result_ptr; +typedef int KN_linsolver_callback( + KN_context_ptr kc, KN_linsolver_request_ptr const linsolverRequest, + KN_linsolver_result_ptr const linsolverResult, void* const userParams); +} + +namespace operations_research { + +// environment functions +bool KnitroIsCorrectlyInstalled(); +absl::Status LoadKnitroDynamicLibrary(std::string& knitropath); + +// ****************************** +// * misc +// ****************************** +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#include +#include +#ifdef _WIN32 +#ifdef MAKE_KNITRO_DLL +#define KNITRO_API __declspec(dllexport) __stdcall +#else +#define KNITRO_API __stdcall +#endif +#else +#if (__GNUC__ >= 4) || (__INTEL_COMPILER) +#define KNITRO_API __attribute__((visibility("default"))) +#else +#define KNITRO_API +#endif +#endif +#define KNTRUE 1 +#define KNFALSE 0 +#define KN_LINSOLVER_PHASE_INIT 0 +#define KN_LINSOLVER_PHASE_ANALYZE 1 +#define KN_LINSOLVER_PHASE_FACTOR 2 +#define KN_LINSOLVER_PHASE_SOLVE 3 +#define KN_LINSOLVER_PHASE_FREE 4 +#define KN_INFINITY DBL_MAX +#define KN_PARAMTYPE_INTEGER 0 +#define KN_PARAMTYPE_FLOAT 1 +#define KN_PARAMTYPE_STRING 2 +#define KN_COMPONENT_VAR 1 +#define KN_COMPONENT_OBJ 2 +#define KN_COMPONENT_CON 3 +#define KN_COMPONENT_RSD 4 +#define KN_OBJGOAL_MINIMIZE 0 +#define KN_OBJGOAL_MAXIMIZE 1 +#define KN_OBJTYPE_CONSTANT -1 +#define KN_OBJTYPE_GENERAL 0 +#define KN_OBJTYPE_LINEAR 1 +#define KN_OBJTYPE_QUADRATIC 2 +#define KN_CONTYPE_CONSTANT -1 +#define KN_CONTYPE_GENERAL 0 +#define KN_CONTYPE_LINEAR 1 +#define KN_CONTYPE_QUADRATIC 2 +#define KN_CONTYPE_CONIC 3 +#define KN_RSDTYPE_CONSTANT -1 +#define KN_RSDTYPE_GENERAL 0 +#define KN_RSDTYPE_LINEAR 1 +#define KN_CCTYPE_VARVAR 0 +#define KN_CCTYPE_VARCON 1 +#define KN_CCTYPE_CONCON 2 +#define KN_VARTYPE_CONTINUOUS 0 +#define KN_VARTYPE_INTEGER 1 +#define KN_VARTYPE_BINARY 2 +#define KN_VAR_LINEAR 1 +#define KN_OBJ_CONVEX 1 +#define KN_OBJ_CONCAVE 2 +#define KN_OBJ_CONTINUOUS 4 +#define KN_OBJ_DIFFERENTIABLE 8 +#define KN_OBJ_TWICE_DIFFERENTIABLE 16 +#define KN_OBJ_NOISY 32 +#define KN_OBJ_NONDETERMINISTIC 64 +#define KN_CON_CONVEX 1 +#define KN_CON_CONCAVE 2 +#define KN_CON_CONTINUOUS 4 +#define KN_CON_DIFFERENTIABLE 8 +#define KN_CON_TWICE_DIFFERENTIABLE 16 +#define KN_CON_NOISY 32 +#define KN_CON_NONDETERMINISTIC 64 +#define KN_DENSE -1 +#define KN_DENSE_ROWMAJOR -2 +#define KN_DENSE_COLMAJOR -3 +#define KN_RC_EVALFC 1 +#define KN_RC_EVALGA 2 +#define KN_RC_EVALH 3 +#define KN_RC_EVALHV 7 +#define KN_RC_EVALH_NO_F 8 +#define KN_RC_EVALHV_NO_F 9 +#define KN_RC_EVALR 10 +#define KN_RC_EVALRJ 11 +#define KN_RC_EVALFCGA 12 +#define KN_RC_OPTIMAL_OR_SATISFACTORY 0 +#define KN_RC_OPTIMAL 0 +#define KN_RC_NEAR_OPT -100 +#define KN_RC_FEAS_XTOL -101 +#define KN_RC_FEAS_NO_IMPROVE -102 +#define KN_RC_FEAS_FTOL -103 +#define KN_RC_INFEASIBLE -200 +#define KN_RC_INFEAS_XTOL -201 +#define KN_RC_INFEAS_NO_IMPROVE -202 +#define KN_RC_INFEAS_MULTISTART -203 +#define KN_RC_INFEAS_CON_BOUNDS -204 +#define KN_RC_INFEAS_VAR_BOUNDS -205 +#define KN_RC_UNBOUNDED -300 +#define KN_RC_UNBOUNDED_OR_INFEAS -301 +#define KN_RC_ITER_LIMIT_FEAS -400 +#define KN_RC_TIME_LIMIT_FEAS -401 +#define KN_RC_FEVAL_LIMIT_FEAS -402 +#define KN_RC_MIP_EXH_FEAS -403 +#define KN_RC_MIP_TERM_FEAS -404 +#define KN_RC_MIP_SOLVE_LIMIT_FEAS -405 +#define KN_RC_MIP_NODE_LIMIT_FEAS -406 +#define KN_RC_ITER_LIMIT_INFEAS -410 +#define KN_RC_TIME_LIMIT_INFEAS -411 +#define KN_RC_FEVAL_LIMIT_INFEAS -412 +#define KN_RC_MIP_EXH_INFEAS -413 +#define KN_RC_MIP_SOLVE_LIMIT_INFEAS -415 +#define KN_RC_MIP_NODE_LIMIT_INFEAS -416 +#define KN_RC_CALLBACK_ERR -500 +#define KN_RC_LP_SOLVER_ERR -501 +#define KN_RC_EVAL_ERR -502 +#define KN_RC_OUT_OF_MEMORY -503 +#define KN_RC_USER_TERMINATION -504 +#define KN_RC_OPEN_FILE_ERR -505 +#define KN_RC_BAD_N_OR_F -506 +#define KN_RC_BAD_CONSTRAINT -507 +#define KN_RC_BAD_JACOBIAN -508 +#define KN_RC_BAD_HESSIAN -509 +#define KN_RC_BAD_CON_INDEX -510 +#define KN_RC_BAD_JAC_INDEX -511 +#define KN_RC_BAD_HESS_INDEX -512 +#define KN_RC_BAD_CON_BOUNDS -513 +#define KN_RC_BAD_VAR_BOUNDS -514 +#define KN_RC_ILLEGAL_CALL -515 +#define KN_RC_BAD_KCPTR -516 +#define KN_RC_NULL_POINTER -517 +#define KN_RC_BAD_INIT_VALUE -518 +#define KN_RC_LICENSE_ERROR -520 +#define KN_RC_BAD_PARAMINPUT -521 +#define KN_RC_LINEAR_SOLVER_ERR -522 +#define KN_RC_DERIV_CHECK_FAILED -523 +#define KN_RC_DERIV_CHECK_TERMINATE -524 +#define KN_RC_OVERFLOW_ERR -525 +#define KN_RC_BAD_SIZE -526 +#define KN_RC_BAD_VARIABLE -527 +#define KN_RC_BAD_VAR_INDEX -528 +#define KN_RC_BAD_OBJECTIVE -529 +#define KN_RC_BAD_OBJ_INDEX -530 +#define KN_RC_BAD_RESIDUAL -531 +#define KN_RC_BAD_RSD_INDEX -532 +#define KN_RC_INTERNAL_ERROR -600 +#define KN_PARAM_NEWPOINT 1001 +#define KN_NEWPOINT_NONE 0 +#define KN_NEWPOINT_SAVEONE 1 +#define KN_NEWPOINT_SAVEALL 2 +#define KN_PARAM_HONORBNDS 1002 +#define KN_HONORBNDS_AUTO -1 +#define KN_HONORBNDS_NO 0 +#define KN_HONORBNDS_ALWAYS 1 +#define KN_HONORBNDS_INITPT 2 +#define KN_PARAM_ALGORITHM 1003 +#define KN_PARAM_ALG 1003 +#define KN_ALG_AUTOMATIC 0 +#define KN_ALG_AUTO 0 +#define KN_ALG_BAR_DIRECT 1 +#define KN_ALG_BAR_CG 2 +#define KN_ALG_ACT_CG 3 +#define KN_ALG_ACT_SQP 4 +#define KN_ALG_MULTI 5 +#define KN_PARAM_BAR_MURULE 1004 +#define KN_BAR_MURULE_AUTOMATIC 0 +#define KN_BAR_MURULE_AUTO 0 +#define KN_BAR_MURULE_MONOTONE 1 +#define KN_BAR_MURULE_ADAPTIVE 2 +#define KN_BAR_MURULE_PROBING 3 +#define KN_BAR_MURULE_DAMPMPC 4 +#define KN_BAR_MURULE_FULLMPC 5 +#define KN_BAR_MURULE_QUALITY 6 +#define KN_PARAM_BAR_FEASIBLE 1006 +#define KN_BAR_FEASIBLE_NO 0 +#define KN_BAR_FEASIBLE_STAY 1 +#define KN_BAR_FEASIBLE_GET 2 +#define KN_BAR_FEASIBLE_GET_STAY 3 +#define KN_PARAM_GRADOPT 1007 +#define KN_GRADOPT_EXACT 1 +#define KN_GRADOPT_FORWARD 2 +#define KN_GRADOPT_CENTRAL 3 +#define KN_GRADOPT_USER_FORWARD 4 +#define KN_GRADOPT_USER_CENTRAL 5 +#define KN_PARAM_HESSOPT 1008 +#define KN_HESSOPT_AUTO 0 +#define KN_HESSOPT_EXACT 1 +#define KN_HESSOPT_BFGS 2 +#define KN_HESSOPT_SR1 3 +#define KN_HESSOPT_PRODUCT_FINDIFF 4 +#define KN_HESSOPT_PRODUCT 5 +#define KN_HESSOPT_LBFGS 6 +#define KN_HESSOPT_GAUSS_NEWTON 7 +#define KN_PARAM_BAR_INITPT 1009 +#define KN_BAR_INITPT_AUTO 0 +#define KN_BAR_INITPT_CONVEX 1 +#define KN_BAR_INITPT_NEARBND 2 +#define KN_BAR_INITPT_CENTRAL 3 +#define KN_PARAM_ACT_LPSOLVER 1012 +#define KN_ACT_LPSOLVER_INTERNAL 1 +#define KN_ACT_LPSOLVER_CPLEX 2 +#define KN_ACT_LPSOLVER_XPRESS 3 +#define KN_PARAM_CG_MAXIT 1013 +#define KN_PARAM_MAXIT 1014 +#define KN_PARAM_OUTLEV 1015 +#define KN_OUTLEV_NONE 0 +#define KN_OUTLEV_SUMMARY 1 +#define KN_OUTLEV_ITER_10 2 +#define KN_OUTLEV_ITER 3 +#define KN_OUTLEV_ITER_VERBOSE 4 +#define KN_OUTLEV_ITER_X 5 +#define KN_OUTLEV_ALL 6 +#define KN_PARAM_OUTMODE 1016 +#define KN_OUTMODE_SCREEN 0 +#define KN_OUTMODE_FILE 1 +#define KN_OUTMODE_BOTH 2 +#define KN_PARAM_SCALE 1017 +#define KN_SCALE_NEVER 0 +#define KN_SCALE_NO 0 +#define KN_SCALE_USER_INTERNAL 1 +#define KN_SCALE_USER_NONE 2 +#define KN_SCALE_INTERNAL 3 +#define KN_PARAM_SOC 1019 +#define KN_SOC_NO 0 +#define KN_SOC_MAYBE 1 +#define KN_SOC_YES 2 +#define KN_PARAM_DELTA 1020 +#define KN_PARAM_BAR_FEASMODETOL 1021 +#define KN_PARAM_FEASTOL 1022 +#define KN_PARAM_FEASTOLABS 1023 +#define KN_PARAM_MAXTIMECPU 1024 +#define KN_PARAM_BAR_INITMU 1025 +#define KN_PARAM_OBJRANGE 1026 +#define KN_PARAM_OPTTOL 1027 +#define KN_PARAM_OPTTOLABS 1028 +#define KN_PARAM_LINSOLVER_PIVOTTOL 1029 +#define KN_PARAM_XTOL 1030 +#define KN_PARAM_DEBUG 1031 +#define KN_DEBUG_NONE 0 +#define KN_DEBUG_PROBLEM 1 +#define KN_DEBUG_EXECUTION 2 +#define KN_PARAM_MULTISTART 1033 +#define KN_PARAM_MSENABLE 1033 +#define KN_PARAM_MS_ENABLE 1033 +#define KN_MULTISTART_NO 0 +#define KN_MS_ENABLE_NO 0 +#define KN_MULTISTART_YES 1 +#define KN_MS_ENABLE_YES 1 +#define KN_PARAM_MSMAXSOLVES 1034 +#define KN_PARAM_MS_MAXSOLVES 1034 +#define KN_PARAM_MSMAXBNDRANGE 1035 +#define KN_PARAM_MS_MAXBNDRANGE 1035 +#define KN_PARAM_MSMAXTIMECPU 1036 +#define KN_PARAM_MS_MAXTIMECPU 1036 +#define KN_PARAM_MSMAXTIMEREAL 1037 +#define KN_PARAM_MS_MAXTIMEREAL 1037 +#define KN_PARAM_LMSIZE 1038 +#define KN_PARAM_BAR_MAXCROSSIT 1039 +#define KN_PARAM_MAXTIMEREAL 1040 +#define KN_PARAM_CG_PRECOND 1041 +#define KN_CG_PRECOND_NONE 0 +#define KN_CG_PRECOND_CHOL 1 +#define KN_PARAM_BLASOPTION 1042 +#define KN_BLASOPTION_AUTO -1 +#define KN_BLASOPTION_KNITRO 0 +#define KN_BLASOPTION_INTEL 1 +#define KN_BLASOPTION_DYNAMIC 2 +#define KN_BLASOPTION_BLIS 3 +#define KN_BLASOPTION_APPLE 4 +#define KN_PARAM_BAR_MAXREFACTOR 1043 +#define KN_PARAM_LINESEARCH_MAXTRIALS 1044 +#define KN_PARAM_BLASOPTIONLIB 1045 +#define KN_PARAM_OUTAPPEND 1046 +#define KN_OUTAPPEND_NO 0 +#define KN_OUTAPPEND_YES 1 +#define KN_PARAM_OUTDIR 1047 +#define KN_PARAM_CPLEXLIB 1048 +#define KN_PARAM_BAR_PENRULE 1049 +#define KN_BAR_PENRULE_AUTO 0 +#define KN_BAR_PENRULE_SINGLE 1 +#define KN_BAR_PENRULE_FLEX 2 +#define KN_PARAM_BAR_PENCONS 1050 +#define KN_BAR_PENCONS_AUTO -1 +#define KN_BAR_PENCONS_NONE 0 +#define KN_BAR_PENCONS_ALL 2 +#define KN_BAR_PENCONS_EQUALITIES 3 +#define KN_BAR_PENCONS_INFEAS 4 +#define KN_PARAM_MSNUMTOSAVE 1051 +#define KN_PARAM_MS_NUMTOSAVE 1051 +#define KN_PARAM_MSSAVETOL 1052 +#define KN_PARAM_MS_SAVETOL 1052 +#define KN_PARAM_PRESOLVEDEBUG 1053 +#define KN_PRESOLVEDBG_NONE 0 +#define KN_PRESOLVEDBG_BASIC 1 +#define KN_PRESOLVEDBG_VERBOSE 2 +#define KN_PRESOLVEDBG_DETAIL 3 +#define KN_PARAM_MSTERMINATE 1054 +#define KN_PARAM_MS_TERMINATE 1054 +#define KN_MSTERMINATE_MAXSOLVES 0 +#define KN_MS_TERMINATE_MAXSOLVES 0 +#define KN_MSTERMINATE_OPTIMAL 1 +#define KN_MS_TERMINATE_OPTIMAL 1 +#define KN_MSTERMINATE_FEASIBLE 2 +#define KN_MS_TERMINATE_FEASIBLE 2 +#define KN_MSTERMINATE_ANY 3 +#define KN_MS_TERMINATE_ANY 3 +#define KN_MSTERMINATE_RULEBASED 4 +#define KN_MS_TERMINATE_RULEBASED 4 +#define KN_PARAM_MSSTARTPTRANGE 1055 +#define KN_PARAM_MS_STARTPTRANGE 1055 +#define KN_PARAM_INFEASTOL 1056 +#define KN_PARAM_LINSOLVER 1057 +#define KN_LINSOLVER_AUTO 0 +#define KN_LINSOLVER_INTERNAL 1 +#define KN_LINSOLVER_HYBRID 2 +#define KN_LINSOLVER_DENSEQR 3 +#define KN_LINSOLVER_MA27 4 +#define KN_LINSOLVER_MA57 5 +#define KN_LINSOLVER_MKLPARDISO 6 +#define KN_LINSOLVER_MA97 7 +#define KN_LINSOLVER_MA86 8 +#define KN_PARAM_BAR_DIRECTINTERVAL 1058 +#define KN_PARAM_PRESOLVE 1059 +#define KN_PRESOLVE_NO 0 +#define KN_PRESOLVE_NONE 0 +#define KN_PRESOLVE_YES 1 +#define KN_PRESOLVE_BASIC 1 +#define KN_PRESOLVE_ADVANCED 2 +#define KN_PARAM_PRESOLVE_TOL 1060 +#define KN_PARAM_BAR_SWITCHRULE 1061 +#define KN_BAR_SWITCHRULE_AUTO -1 +#define KN_BAR_SWITCHRULE_NEVER 0 +#define KN_BAR_SWITCHRULE_MODERATE 2 +#define KN_BAR_SWITCHRULE_AGGRESSIVE 3 +#define KN_PARAM_HESSIAN_NO_F 1062 +#define KN_HESSIAN_NO_F_FORBID 0 +#define KN_HESSIAN_NO_F_ALLOW 1 +#define KN_PARAM_MA_TERMINATE 1063 +#define KN_MA_TERMINATE_ALL 0 +#define KN_MA_TERMINATE_OPTIMAL 1 +#define KN_MA_TERMINATE_FEASIBLE 2 +#define KN_MA_TERMINATE_ANY 3 +#define KN_PARAM_MA_MAXTIMECPU 1064 +#define KN_PARAM_MA_MAXTIMEREAL 1065 +#define KN_PARAM_MSSEED 1066 +#define KN_PARAM_MS_SEED 1066 +#define KN_PARAM_MA_OUTSUB 1067 +#define KN_MA_OUTSUB_NONE 0 +#define KN_MA_OUTSUB_YES 1 +#define KN_PARAM_MS_OUTSUB 1068 +#define KN_MS_OUTSUB_NONE 0 +#define KN_MS_OUTSUB_YES 1 +#define KN_PARAM_XPRESSLIB 1069 +#define KN_PARAM_TUNER 1070 +#define KN_TUNER_OFF 0 +#define KN_TUNER_ON 1 +#define KN_PARAM_TUNER_OPTIONSFILE 1071 +#define KN_PARAM_TUNER_MAXTIMECPU 1072 +#define KN_PARAM_TUNER_MAXTIMEREAL 1073 +#define KN_PARAM_TUNER_OUTSUB 1074 +#define KN_TUNER_OUTSUB_NONE 0 +#define KN_TUNER_OUTSUB_SUMMARY 1 +#define KN_TUNER_OUTSUB_ALL 2 +#define KN_PARAM_TUNER_TERMINATE 1075 +#define KN_TUNER_TERMINATE_ALL 0 +#define KN_TUNER_TERMINATE_OPTIMAL 1 +#define KN_TUNER_TERMINATE_FEASIBLE 2 +#define KN_TUNER_TERMINATE_ANY 3 +#define KN_PARAM_LINSOLVER_OOC 1076 +#define KN_LINSOLVER_OOC_NO 0 +#define KN_LINSOLVER_OOC_MAYBE 1 +#define KN_LINSOLVER_OOC_YES 2 +#define KN_PARAM_BAR_RELAXCONS 1077 +#define KN_BAR_RELAXCONS_NONE 0 +#define KN_BAR_RELAXCONS_EQS 1 +#define KN_BAR_RELAXCONS_INEQS 2 +#define KN_BAR_RELAXCONS_ALL 3 +#define KN_PARAM_MSDETERMINISTIC 1078 +#define KN_PARAM_MS_DETERMINISTIC 1078 +#define KN_MSDETERMINISTIC_NO 0 +#define KN_MS_DETERMINISTIC_NO 0 +#define KN_MSDETERMINISTIC_YES 1 +#define KN_MS_DETERMINISTIC_YES 1 +#define KN_PARAM_BAR_REFINEMENT 1079 +#define KN_BAR_REFINEMENT_NO 0 +#define KN_BAR_REFINEMENT_YES 1 +#define KN_PARAM_DERIVCHECK 1080 +#define KN_DERIVCHECK_NONE 0 +#define KN_DERIVCHECK_FIRST 1 +#define KN_DERIVCHECK_SECOND 2 +#define KN_DERIVCHECK_ALL 3 +#define KN_PARAM_DERIVCHECK_TYPE 1081 +#define KN_DERIVCHECK_FORWARD 1 +#define KN_DERIVCHECK_CENTRAL 2 +#define KN_PARAM_DERIVCHECK_TOL 1082 +#define KN_PARAM_LINSOLVER_INEXACT 1083 +#define KN_LINSOLVER_INEXACT_NO 0 +#define KN_LINSOLVER_INEXACT_YES 1 +#define KN_PARAM_LINSOLVER_INEXACTTOL 1084 +#define KN_PARAM_MAXFEVALS 1085 +#define KN_PARAM_FSTOPVAL 1086 +#define KN_PARAM_DATACHECK 1087 +#define KN_DATACHECK_NO 0 +#define KN_DATACHECK_YES 1 +#define KN_PARAM_DERIVCHECK_TERMINATE 1088 +#define KN_DERIVCHECK_STOPERROR 1 +#define KN_DERIVCHECK_STOPALWAYS 2 +#define KN_PARAM_BAR_WATCHDOG 1089 +#define KN_BAR_WATCHDOG_NO 0 +#define KN_BAR_WATCHDOG_YES 1 +#define KN_PARAM_FTOL 1090 +#define KN_PARAM_FTOL_ITERS 1091 +#define KN_PARAM_ACT_QPALG 1092 +#define KN_ACT_QPALG_AUTO 0 +#define KN_ACT_QPALG_BAR_DIRECT 1 +#define KN_ACT_QPALG_BAR_CG 2 +#define KN_ACT_QPALG_ACT_CG 3 +#define KN_PARAM_BAR_INITPI_MPEC 1093 +#define KN_PARAM_XTOL_ITERS 1094 +#define KN_PARAM_LINESEARCH 1095 +#define KN_LINESEARCH_AUTO 0 +#define KN_LINESEARCH_BACKTRACK 1 +#define KN_LINESEARCH_INTERPOLATE 2 +#define KN_LINESEARCH_WEAKWOLFE 3 +#define KN_PARAM_OUT_CSVINFO 1096 +#define KN_OUT_CSVINFO_NO 0 +#define KN_OUT_CSVINFO_YES 1 +#define KN_PARAM_INITPENALTY 1097 +#define KN_PARAM_ACT_LPFEASTOL 1098 +#define KN_PARAM_CG_STOPTOL 1099 +#define KN_PARAM_RESTARTS 1100 +#define KN_PARAM_RESTARTS_MAXIT 1101 +#define KN_PARAM_BAR_SLACKBOUNDPUSH 1102 +#define KN_PARAM_CG_PMEM 1103 +#define KN_PARAM_BAR_SWITCHOBJ 1104 +#define KN_BAR_SWITCHOBJ_NONE 0 +#define KN_BAR_SWITCHOBJ_SCALARPROX 1 +#define KN_BAR_SWITCHOBJ_DIAGPROX 2 +#define KN_PARAM_OUTNAME 1105 +#define KN_PARAM_OUT_CSVNAME 1106 +#define KN_PARAM_ACT_PARAMETRIC 1107 +#define KN_ACT_PARAMETRIC_NO 0 +#define KN_ACT_PARAMETRIC_MAYBE 1 +#define KN_ACT_PARAMETRIC_YES 2 +#define KN_PARAM_ACT_LPDUMPMPS 1108 +#define KN_ACT_LPDUMPMPS_NO 0 +#define KN_ACT_LPDUMPMPS_YES 1 +#define KN_PARAM_ACT_LPALG 1109 +#define KN_ACT_LPALG_DEFAULT 0 +#define KN_ACT_LPALG_PRIMAL 1 +#define KN_ACT_LPALG_DUAL 2 +#define KN_ACT_LPALG_BARRIER 3 +#define KN_PARAM_ACT_LPPRESOLVE 1110 +#define KN_ACT_LPPRESOLVE_OFF 0 +#define KN_ACT_LPPRESOLVE_ON 1 +#define KN_PARAM_ACT_LPPENALTY 1111 +#define KN_ACT_LPPENALTY_ALL 1 +#define KN_ACT_LPPENALTY_NONLINEAR 2 +#define KN_ACT_LPPENALTY_DYNAMIC 3 +#define KN_PARAM_BNDRANGE 1112 +#define KN_PARAM_BAR_CONIC_ENABLE 1113 +#define KN_BAR_CONIC_ENABLE_AUTO -1 +#define KN_BAR_CONIC_ENABLE_NONE 0 +#define KN_BAR_CONIC_ENABLE_SOC 1 +#define KN_PARAM_CONVEX 1114 +#define KN_CONVEX_AUTO -1 +#define KN_CONVEX_NO 0 +#define KN_CONVEX_YES 1 +#define KN_PARAM_OUT_HINTS 1115 +#define KN_OUT_HINTS_NO 0 +#define KN_OUT_HINTS_YES 1 +#define KN_PARAM_EVAL_FCGA 1116 +#define KN_EVAL_FCGA_NO 0 +#define KN_EVAL_FCGA_YES 1 +#define KN_PARAM_BAR_MAXCORRECTORS 1117 +#define KN_PARAM_STRAT_WARM_START 1118 +#define KN_STRAT_WARM_START_NO 0 +#define KN_STRAT_WARM_START_YES 1 +#define KN_PARAM_FINDIFF_TERMINATE 1119 +#define KN_FINDIFF_TERMINATE_NONE 0 +#define KN_FINDIFF_TERMINATE_ERREST 1 +#define KN_PARAM_CPUPLATFORM 1120 +#define KN_CPUPLATFORM_AUTO -1 +#define KN_CPUPLATFORM_COMPATIBLE 1 +#define KN_CPUPLATFORM_SSE2 2 +#define KN_CPUPLATFORM_AVX 3 +#define KN_CPUPLATFORM_AVX2 4 +#define KN_CPUPLATFORM_AVX512 5 +#define KN_PARAM_PRESOLVE_PASSES 1121 +#define KN_PARAM_PRESOLVE_LEVEL 1122 +#define KN_PRESOLVE_LEVEL_AUTO -1 +#define KN_PRESOLVE_LEVEL_1 1 +#define KN_PRESOLVE_LEVEL_2 2 +#define KN_PARAM_FINDIFF_RELSTEPSIZE 1123 +#define KN_PARAM_INFEASTOL_ITERS 1124 +#define KN_PARAM_PRESOLVEOP_TIGHTEN 1125 +#define KN_PRESOLVEOP_TIGHTEN_AUTO -1 +#define KN_PRESOLVEOP_TIGHTEN_NONE 0 +#define KN_PRESOLVEOP_TIGHTEN_VARBND 1 +#define KN_PRESOLVEOP_TIGHTEN_COEF 2 +#define KN_PRESOLVEOP_TIGHTEN_ALL 3 +#define KN_PARAM_BAR_LINSYS 1126 +#define KN_BAR_LINSYS_AUTO -1 +#define KN_BAR_LINSYS_FULL 0 +#define KN_BAR_LINSYS_COMPACT1 1 +#define KN_BAR_LINSYS_ELIMINATE_SLACKS 1 +#define KN_BAR_LINSYS_COMPACT2 2 +#define KN_BAR_LINSYS_ELIMINATE_BOUNDS 2 +#define KN_BAR_LINSYS_ELIMINATE_INEQS 3 +#define KN_PARAM_PRESOLVE_INITPT 1127 +#define KN_PRESOLVE_INITPT_AUTO -1 +#define KN_PRESOLVE_INITPT_NOSHIFT 0 +#define KN_PRESOLVE_INITPT_LINSHIFT 1 +#define KN_PRESOLVE_INITPT_ANYSHIFT 2 +#define KN_PARAM_ACT_QPPENALTY 1128 +#define KN_ACT_QPPENALTY_AUTO -1 +#define KN_ACT_QPPENALTY_NONE 0 +#define KN_ACT_QPPENALTY_ALL 1 +#define KN_PARAM_BAR_LINSYS_STORAGE 1129 +#define KN_BAR_LINSYS_STORAGE_AUTO -1 +#define KN_BAR_LINSYS_STORAGE_LOWMEM 1 +#define KN_BAR_LINSYS_STORAGE_NORMAL 2 +#define KN_PARAM_LINSOLVER_MAXITREF 1130 +#define KN_PARAM_BFGS_SCALING 1131 +#define KN_BFGS_SCALING_DYNAMIC 0 +#define KN_BFGS_SCALING_INVHESS 1 +#define KN_BFGS_SCALING_HESS 2 +#define KN_PARAM_BAR_INITSHIFTTOL 1132 +#define KN_PARAM_NUMTHREADS 1133 +#define KN_PARAM_CONCURRENT_EVALS 1134 +#define KN_CONCURRENT_EVALS_NO 0 +#define KN_CONCURRENT_EVALS_YES 1 +#define KN_PARAM_BLAS_NUMTHREADS 1135 +#define KN_PARAM_LINSOLVER_NUMTHREADS 1136 +#define KN_PARAM_MS_NUMTHREADS 1137 +#define KN_PARAM_CONIC_NUMTHREADS 1138 +#define KN_PARAM_NCVX_QCQP_INIT 1139 +#define KN_NCVX_QCQP_INIT_AUTO -1 +#define KN_NCVX_QCQP_INIT_NONE 0 +#define KN_NCVX_QCQP_INIT_LINEAR 1 +#define KN_NCVX_QCQP_INIT_HYBRID 2 +#define KN_NCVX_QCQP_INIT_PENALTY 3 +#define KN_NCVX_QCQP_INIT_CVXQUAD 4 +#define KN_PARAM_FINDIFF_ESTNOISE 1140 +#define KN_FINDIFF_ESTNOISE_NO 0 +#define KN_FINDIFF_ESTNOISE_YES 1 +#define KN_FINDIFF_ESTNOISE_WITHCURV 2 +#define KN_PARAM_FINDIFF_NUMTHREADS 1141 +#define KN_PARAM_BAR_MPEC_HEURISTIC 1142 +#define KN_BAR_MPEC_HEURISTIC_NO 0 +#define KN_BAR_MPEC_HEURISTIC_YES 1 +#define KN_PARAM_PRESOLVEOP_REDUNDANT 1143 +#define KN_PRESOLVEOP_REDUNDANT_NONE 0 +#define KN_PRESOLVEOP_REDUNDANT_DUPCON 1 +#define KN_PRESOLVEOP_REDUNDANT_DEPCON 2 +#define KN_PARAM_LINSOLVER_ORDERING 1144 +#define KN_LINSOLVER_ORDERING_AUTO -1 +#define KN_LINSOLVER_ORDERING_BEST 0 +#define KN_LINSOLVER_ORDERING_AMD 1 +#define KN_LINSOLVER_ORDERING_METIS 2 +#define KN_PARAM_LINSOLVER_NODEAMALG 1145 +#define KN_PARAM_PRESOLVEOP_SUBSTITUTION 1146 +#define KN_PRESOLVEOP_SUBSTITUTION_AUTO -1 +#define KN_PRESOLVEOP_SUBSTITUTION_NONE 0 +#define KN_PRESOLVEOP_SUBSTITUTION_SIMPLE 1 +#define KN_PRESOLVEOP_SUBSTITUTION_ALL 2 +#define KN_PARAM_PRESOLVEOP_SUBSTITUTION_TOL 1147 +#define KN_PARAM_MS_INITPT_CLUSTER 1149 +#define KN_MS_INITPT_CLUSTER_NONE 0 +#define KN_MS_INITPT_CLUSTER_SL 1 +#define KN_PARAM_SCALE_VARS 1153 +#define KN_SCALE_VARS_NONE 0 +#define KN_SCALE_VARS_BNDS 1 +#define KN_PARAM_BAR_MAXMU 1154 +#define KN_PARAM_BAR_GLOBALIZE 1155 +#define KN_BAR_GLOBALIZE_NONE 0 +#define KN_BAR_GLOBALIZE_KKT 1 +#define KN_BAR_GLOBALIZE_FILTER 2 +#define KN_PARAM_LINSOLVER_SCALING 1156 +#define KN_LINSOLVER_SCALING_NONE 0 +#define KN_LINSOLVER_SCALING_ALWAYS 1 +#define KN_PARAM_MIP_METHOD 2001 +#define KN_MIP_METHOD_AUTO 0 +#define KN_MIP_METHOD_BB 1 +#define KN_MIP_METHOD_HQG 2 +#define KN_MIP_METHOD_MISQP 3 +#define KN_PARAM_MIP_BRANCHRULE 2002 +#define KN_MIP_BRANCH_AUTO 0 +#define KN_MIP_BRANCH_MOSTFRAC 1 +#define KN_MIP_BRANCH_PSEUDOCOST 2 +#define KN_MIP_BRANCH_STRONG 3 +#define KN_PARAM_MIP_SELECTRULE 2003 +#define KN_MIP_SEL_AUTO 0 +#define KN_MIP_SEL_DEPTHFIRST 1 +#define KN_MIP_SEL_BESTBOUND 2 +#define KN_MIP_SEL_COMBO_1 3 +#define KN_PARAM_MIP_INTGAPABS 2004 +#define KN_PARAM_MIP_OPTGAPABS 2004 +#define KN_PARAM_MIP_INTGAPREL 2005 +#define KN_PARAM_MIP_OPTGAPREL 2005 +#define KN_PARAM_MIP_MAXTIMECPU 2006 +#define KN_PARAM_MIP_MAXTIMEREAL 2007 +#define KN_PARAM_MIP_MAXSOLVES 2008 +#define KN_PARAM_MIP_INTEGERTOL 2009 +#define KN_PARAM_MIP_OUTLEVEL 2010 +#define KN_MIP_OUTLEVEL_NONE 0 +#define KN_MIP_OUTLEVEL_ITERS 1 +#define KN_MIP_OUTLEVEL_ITERSTIME 2 +#define KN_MIP_OUTLEVEL_ROOT 3 +#define KN_PARAM_MIP_OUTINTERVAL 2011 +#define KN_PARAM_MIP_OUTSUB 2012 +#define KN_MIP_OUTSUB_NONE 0 +#define KN_MIP_OUTSUB_YES 1 +#define KN_MIP_OUTSUB_YESPROB 2 +#define KN_PARAM_MIP_DEBUG 2013 +#define KN_MIP_DEBUG_NONE 0 +#define KN_MIP_DEBUG_ALL 1 +#define KN_PARAM_MIP_IMPLICATNS 2014 +#define KN_PARAM_MIP_IMPLICATIONS 2014 +#define KN_MIP_IMPLICATNS_NO 0 +#define KN_MIP_IMPLICATIONS_NO 0 +#define KN_MIP_IMPLICATNS_YES 1 +#define KN_MIP_IMPLICATIONS_YES 1 +#define KN_PARAM_MIP_GUB_BRANCH 2015 +#define KN_MIP_GUB_BRANCH_NO 0 +#define KN_MIP_GUB_BRANCH_YES 1 +#define KN_PARAM_MIP_KNAPSACK 2016 +#define KN_MIP_KNAPSACK_AUTO -1 +#define KN_MIP_KNAPSACK_NO 0 +#define KN_MIP_KNAPSACK_NONE 0 +#define KN_MIP_KNAPSACK_ROOT 1 +#define KN_MIP_KNAPSACK_TREE 2 +#define KN_MIP_KNAPSACK_INEQ 1 +#define KN_MIP_KNAPSACK_LIFTED 2 +#define KN_MIP_KNAPSACK_ALL 3 +#define KN_PARAM_MIP_ROUNDING 2017 +#define KN_MIP_ROUND_AUTO -1 +#define KN_MIP_ROUND_NONE 0 +#define KN_MIP_ROUND_HEURISTIC 2 +#define KN_MIP_ROUND_NLP_SOME 3 +#define KN_MIP_ROUND_NLP_ALWAYS 4 +#define KN_PARAM_MIP_ROOTALG 2018 +#define KN_MIP_ROOTALG_AUTO 0 +#define KN_MIP_ROOTALG_BAR_DIRECT 1 +#define KN_MIP_ROOTALG_BAR_CG 2 +#define KN_MIP_ROOTALG_ACT_CG 3 +#define KN_MIP_ROOTALG_ACT_SQP 4 +#define KN_MIP_ROOTALG_MULTI 5 +#define KN_PARAM_MIP_LPALG 2019 +#define KN_MIP_LPALG_AUTO 0 +#define KN_MIP_LPALG_BAR_DIRECT 1 +#define KN_MIP_LPALG_BAR_CG 2 +#define KN_MIP_LPALG_ACT_CG 3 +#define KN_PARAM_MIP_TERMINATE 2020 +#define KN_MIP_TERMINATE_OPTIMAL 0 +#define KN_MIP_TERMINATE_FEASIBLE 1 +#define KN_PARAM_MIP_MAXNODES 2021 +#define KN_PARAM_MIP_HEURISTIC 2022 +#define KN_MIP_HEURISTIC_AUTO -1 +#define KN_MIP_HEURISTIC_NONE 0 +#define KN_MIP_HEURISTIC_FEASPUMP 2 +#define KN_MIP_HEURISTIC_MPEC 3 +#define KN_MIP_HEURISTIC_DIVING 4 +#define KN_PARAM_MIP_HEUR_MAXIT 2023 +#define KN_PARAM_MIP_HEUR_MAXTIMECPU 2024 +#define KN_PARAM_MIP_HEUR_MAXTIMEREAL 2025 +#define KN_PARAM_MIP_PSEUDOINIT 2026 +#define KN_MIP_PSEUDOINIT_AUTO 0 +#define KN_MIP_PSEUDOINIT_AVE 1 +#define KN_MIP_PSEUDOINIT_STRONG 2 +#define KN_PARAM_MIP_STRONG_MAXIT 2027 +#define KN_PARAM_MIP_STRONG_CANDLIM 2028 +#define KN_PARAM_MIP_STRONG_LEVEL 2029 +#define KN_PARAM_MIP_INTVAR_STRATEGY 2030 +#define KN_MIP_INTVAR_STRATEGY_NONE 0 +#define KN_MIP_INTVAR_STRATEGY_RELAX 1 +#define KN_MIP_INTVAR_STRATEGY_MPEC 2 +#define KN_PARAM_MIP_RELAXABLE 2031 +#define KN_MIP_RELAXABLE_NONE 0 +#define KN_MIP_RELAXABLE_ALL 1 +#define KN_PARAM_MIP_NODEALG 2032 +#define KN_MIP_NODEALG_AUTO 0 +#define KN_MIP_NODEALG_BAR_DIRECT 1 +#define KN_MIP_NODEALG_BAR_CG 2 +#define KN_MIP_NODEALG_ACT_CG 3 +#define KN_MIP_NODEALG_ACT_SQP 4 +#define KN_MIP_NODEALG_MULTI 5 +#define KN_PARAM_MIP_HEUR_TERMINATE 2033 +#define KN_MIP_HEUR_TERMINATE_FEASIBLE 1 +#define KN_MIP_HEUR_TERMINATE_LIMIT 2 +#define KN_PARAM_MIP_SELECTDIR 2034 +#define KN_MIP_SELECTDIR_DOWN 0 +#define KN_MIP_SELECTDIR_UP 1 +#define KN_PARAM_MIP_CUTFACTOR 2035 +#define KN_PARAM_MIP_ZEROHALF 2036 +#define KN_MIP_ZEROHALF_AUTO -1 +#define KN_MIP_ZEROHALF_NONE 0 +#define KN_MIP_ZEROHALF_ROOT 1 +#define KN_MIP_ZEROHALF_TREE 2 +#define KN_MIP_ZEROHALF_ALL 3 +#define KN_PARAM_MIP_MIR 2037 +#define KN_MIP_MIR_AUTO -1 +#define KN_MIP_MIR_NONE 0 +#define KN_MIP_MIR_ROOT 1 +#define KN_MIP_MIR_TREE 2 +#define KN_MIP_MIR_NLP 2 +#define KN_PARAM_MIP_CLIQUE 2038 +#define KN_MIP_CLIQUE_AUTO -1 +#define KN_MIP_CLIQUE_NONE 0 +#define KN_MIP_CLIQUE_ROOT 1 +#define KN_MIP_CLIQUE_TREE 2 +#define KN_MIP_CLIQUE_ALL 3 +#define KN_PARAM_MIP_HEUR_STRATEGY 2039 +#define KN_MIP_HEUR_STRATEGY_AUTO -1 +#define KN_MIP_HEUR_STRATEGY_NONE 0 +#define KN_MIP_HEUR_STRATEGY_BASIC 1 +#define KN_MIP_HEUR_STRATEGY_ADVANCED 2 +#define KN_MIP_HEUR_STRATEGY_EXTENSIVE 3 +#define KN_PARAM_MIP_HEUR_FEASPUMP 2040 +#define KN_MIP_HEUR_FEASPUMP_AUTO -1 +#define KN_MIP_HEUR_FEASPUMP_OFF 0 +#define KN_MIP_HEUR_FEASPUMP_ON 1 +#define KN_PARAM_MIP_HEUR_MPEC 2041 +#define KN_MIP_HEUR_MPEC_AUTO -1 +#define KN_MIP_HEUR_MPEC_OFF 0 +#define KN_MIP_HEUR_MPEC_ON 1 +#define KN_PARAM_MIP_HEUR_DIVING 2042 +#define KN_PARAM_MIP_CUTTINGPLANE 2043 +#define KN_MIP_CUTTINGPLANE_NONE 0 +#define KN_MIP_CUTTINGPLANE_ROOT 1 +#define KN_PARAM_MIP_CUTOFF 2044 +#define KN_PARAM_MIP_HEUR_LNS 2045 +#define KN_PARAM_MIP_MULTISTART 2046 +#define KN_MIP_MULTISTART_OFF 0 +#define KN_MIP_MULTISTART_ON 1 +#define KN_PARAM_MIP_LIFTPROJECT 2047 +#define KN_MIP_LIFTPROJECT_AUTO -1 +#define KN_MIP_LIFTPROJECT_NONE 0 +#define KN_MIP_LIFTPROJECT_ROOT 1 +#define KN_PARAM_MIP_NUMTHREADS 2048 +#define KN_PARAM_MIP_HEUR_MISQP 2049 +#define KN_MIP_HEUR_MISQP_AUTO -1 +#define KN_MIP_HEUR_MISQP_OFF 0 +#define KN_MIP_HEUR_MISQP_ON 1 +#define KN_PARAM_MIP_RESTART 2050 +#define KN_MIP_RESTART_OFF 0 +#define KN_MIP_RESTART_ON 1 +#define KN_PARAM_MIP_GOMORY 2051 +#define KN_MIP_GOMORY_AUTO -1 +#define KN_MIP_GOMORY_NONE 0 +#define KN_MIP_GOMORY_ROOT 1 +#define KN_MIP_GOMORY_TREE 2 +#define KN_PARAM_MIP_CUT_PROBING 2052 +#define KN_MIP_CUT_PROBING_AUTO -1 +#define KN_MIP_CUT_PROBING_NONE 0 +#define KN_MIP_CUT_PROBING_ROOT 1 +#define KN_MIP_CUT_PROBING_TREE 2 +#define KN_PARAM_MIP_CUT_FLOWCOVER 2053 +#define KN_MIP_CUT_FLOWCOVER_AUTO -1 +#define KN_MIP_CUT_FLOWCOVER_NONE 0 +#define KN_MIP_CUT_FLOWCOVER_ROOT 1 +#define KN_MIP_CUT_FLOWCOVER_TREE 2 +#define KN_PARAM_MIP_HEUR_LOCALSEARCH 2054 +#define KN_MIP_HEUR_LOCALSEARCH_AUTO -1 +#define KN_MIP_HEUR_LOCALSEARCH_OFF 0 +#define KN_MIP_HEUR_LOCALSEARCH_ON 1 +#define KN_PARAM_PAR_NUMTHREADS 3001 +#define KN_PARAM_PAR_CONCURRENT_EVALS 3002 +#define KN_PAR_CONCURRENT_EVALS_NO 0 +#define KN_PAR_CONCURRENT_EVALS_YES 1 +#define KN_PARAM_PAR_BLASNUMTHREADS 3003 +#define KN_PARAM_PAR_LSNUMTHREADS 3004 +#define KN_PARAM_PAR_MSNUMTHREADS 3005 +#define KN_PAR_MSNUMTHREADS_AUTO 0 +#define KN_PARAM_PAR_CONICNUMTHREADS 3006 + +// ****************************** +// * functions +// ****************************** +extern std::function + KN_get_release; +extern std::function KN_new; +extern std::function KN_free; +extern std::function KN_checkout_license; +extern std::function + KN_new_lm; +extern std::function KN_release_license; +extern std::function + KN_reset_params_to_defaults; +extern std::function + KN_load_param_file; +extern std::function + KN_load_tuner_file; +extern std::function + KN_save_param_file; +extern std::function + KN_set_int_param_by_name; +extern std::function + KN_set_char_param_by_name; +extern std::function + KN_set_double_param_by_name; +extern std::function + KN_set_param_by_name; +extern std::function + KN_set_int_param; +extern std::function + KN_set_char_param; +extern std::function + KN_set_double_param; +extern std::function + KN_get_int_param_by_name; +extern std::function + KN_get_double_param_by_name; +extern std::function + KN_get_int_param; +extern std::function + KN_get_double_param; +extern std::function + KN_get_param_name; +extern std::function + KN_get_param_doc; +extern std::function + KN_get_param_type; +extern std::function + KN_get_num_param_values; +extern std::function + KN_get_param_value_doc; +extern std::function + KN_get_param_id; +extern std::function + KN_add_vars; +extern std::function + KN_add_var; +extern std::function + KN_add_cons; +extern std::function + KN_add_con; +extern std::function + KN_add_rsds; +extern std::function + KN_add_rsd; +extern std::function + KN_set_var_lobnds; +extern std::function + KN_set_var_lobnds_all; +extern std::function + KN_set_var_lobnd; +extern std::function + KN_set_var_upbnds; +extern std::function + KN_set_var_upbnds_all; +extern std::function + KN_set_var_upbnd; +extern std::function + KN_set_var_fxbnds; +extern std::function + KN_set_var_fxbnds_all; +extern std::function + KN_set_var_fxbnd; +extern std::function + KN_get_var_lobnds; +extern std::function + KN_get_var_lobnds_all; +extern std::function + KN_get_var_lobnd; +extern std::function + KN_get_var_upbnds; +extern std::function + KN_get_var_upbnds_all; +extern std::function + KN_get_var_upbnd; +extern std::function + KN_get_var_fxbnds; +extern std::function + KN_get_var_fxbnds_all; +extern std::function + KN_get_var_fxbnd; +extern std::function + KN_set_var_types; +extern std::function + KN_set_var_types_all; +extern std::function + KN_set_var_type; +extern std::function + KN_get_var_types; +extern std::function + KN_get_var_types_all; +extern std::function + KN_get_var_type; +extern std::function + KN_set_var_properties; +extern std::function + KN_set_var_properties_all; +extern std::function + KN_set_var_property; +extern std::function + KN_set_con_lobnds; +extern std::function + KN_set_con_lobnds_all; +extern std::function + KN_set_con_lobnd; +extern std::function + KN_set_con_upbnds; +extern std::function + KN_set_con_upbnds_all; +extern std::function + KN_set_con_upbnd; +extern std::function + KN_set_con_eqbnds; +extern std::function + KN_set_con_eqbnds_all; +extern std::function + KN_set_con_eqbnd; +extern std::function + KN_get_con_lobnds; +extern std::function + KN_get_con_lobnds_all; +extern std::function + KN_get_con_lobnd; +extern std::function + KN_get_con_upbnds; +extern std::function + KN_get_con_upbnds_all; +extern std::function + KN_get_con_upbnd; +extern std::function + KN_get_con_eqbnds; +extern std::function + KN_get_con_eqbnds_all; +extern std::function + KN_get_con_eqbnd; +extern std::function + KN_set_obj_property; +extern std::function + KN_set_con_properties; +extern std::function + KN_set_con_properties_all; +extern std::function + KN_set_con_property; +extern std::function + KN_set_obj_goal; +extern std::function + KN_set_var_primal_init_values; +extern std::function + KN_set_var_primal_init_values_all; +extern std::function + KN_set_var_primal_init_value; +extern std::function + KN_set_var_dual_init_values; +extern std::function + KN_set_var_dual_init_values_all; +extern std::function + KN_set_var_dual_init_value; +extern std::function + KN_set_con_dual_init_values; +extern std::function + KN_set_con_dual_init_values_all; +extern std::function + KN_set_con_dual_init_value; +extern std::function + KN_add_obj_constant; +extern std::function KN_del_obj_constant; +extern std::function + KN_chg_obj_constant; +extern std::function + KN_add_con_constants; +extern std::function + KN_add_con_constants_all; +extern std::function + KN_add_con_constant; +extern std::function + KN_del_con_constants; +extern std::function + KN_del_con_constants_all; +extern std::function + KN_del_con_constant; +extern std::function + KN_chg_con_constants; +extern std::function + KN_chg_con_constants_all; +extern std::function + KN_chg_con_constant; +extern std::function + KN_add_rsd_constants; +extern std::function + KN_add_rsd_constants_all; +extern std::function + KN_add_rsd_constant; +extern std::function + KN_add_obj_linear_struct; +extern std::function + KN_add_obj_linear_term; +extern std::function + KN_del_obj_linear_struct; +extern std::function + KN_del_obj_linear_term; +extern std::function + KN_chg_obj_linear_struct; +extern std::function + KN_chg_obj_linear_term; +extern std::function + KN_add_con_linear_struct; +extern std::function + KN_add_con_linear_struct_one; +extern std::function + KN_add_con_linear_term; +extern std::function + KN_del_con_linear_struct; +extern std::function + KN_del_con_linear_struct_one; +extern std::function + KN_del_con_linear_term; +extern std::function + KN_chg_con_linear_struct; +extern std::function + KN_chg_con_linear_struct_one; +extern std::function + KN_chg_con_linear_term; +extern std::function + KN_add_rsd_linear_struct; +extern std::function + KN_add_rsd_linear_struct_one; +extern std::function + KN_add_rsd_linear_term; +extern std::function + KN_add_obj_quadratic_struct; +extern std::function + KN_add_obj_quadratic_term; +extern std::function + KN_add_con_quadratic_struct; +extern std::function + KN_add_con_quadratic_struct_one; +extern std::function + KN_add_con_quadratic_term; +extern std::function + KN_add_con_L2norm; +extern std::function + KN_set_compcons; +extern std::function + KN_load_mps_file; +extern std::function + KN_write_mps_file; +extern std::function + KN_add_eval_callback; +extern std::function + KN_add_eval_callback_all; +extern std::function + KN_add_eval_callback_one; +extern std::function + KN_add_lsq_eval_callback; +extern std::function + KN_add_lsq_eval_callback_all; +extern std::function + KN_add_lsq_eval_callback_one; +extern std::function + KN_set_cb_grad; +extern std::function + KN_set_cb_hess; +extern std::function + KN_set_cb_rsd_jac; +extern std::function + KN_set_cb_user_params; +extern std::function + KN_set_cb_gradopt; +extern std::function + KN_set_cb_relstepsizes; +extern std::function + KN_set_cb_relstepsizes_all; +extern std::function + KN_set_cb_relstepsize; +extern std::function + KN_get_cb_number_cons; +extern std::function + KN_get_cb_number_rsds; +extern std::function + KN_get_cb_objgrad_nnz; +extern std::function + KN_get_cb_jacobian_nnz; +extern std::function + KN_get_cb_rsd_jacobian_nnz; +extern std::function + KN_get_cb_hessian_nnz; +extern std::function + KN_set_newpt_callback; +extern std::function + KN_set_mip_node_callback; +extern std::function + KN_set_mip_usercuts_callback; +extern std::function + KN_set_mip_lazyconstraints_callback; +extern std::function + KN_set_ms_process_callback; +extern std::function + KN_set_ms_initpt_callback; +extern std::function + KN_set_puts_callback; +extern std::function + KN_set_linsolver_callback; +extern std::function + KN_load_lp; +extern std::function + KN_load_qp; +extern std::function + KN_load_qcqp; +extern std::function + KN_set_var_feastols; +extern std::function + KN_set_var_feastols_all; +extern std::function + KN_set_var_feastol; +extern std::function + KN_set_con_feastols; +extern std::function + KN_set_con_feastols_all; +extern std::function + KN_set_con_feastol; +extern std::function + KN_set_compcon_feastols; +extern std::function + KN_set_compcon_feastols_all; +extern std::function + KN_set_compcon_feastol; +extern std::function + KN_set_var_scalings; +extern std::function + KN_set_var_scalings_all; +extern std::function + KN_set_var_scaling; +extern std::function + KN_set_con_scalings; +extern std::function + KN_set_con_scalings_all; +extern std::function + KN_set_con_scaling; +extern std::function + KN_set_compcon_scalings; +extern std::function + KN_set_compcon_scalings_all; +extern std::function + KN_set_compcon_scaling; +extern std::function + KN_set_obj_scaling; +extern std::function + KN_set_var_names; +extern std::function + KN_set_var_names_all; +extern std::function + KN_set_var_name; +extern std::function + KN_set_con_names; +extern std::function + KN_set_con_names_all; +extern std::function + KN_set_con_name; +extern std::function + KN_set_compcon_names; +extern std::function + KN_set_compcon_names_all; +extern std::function + KN_set_compcon_name; +extern std::function + KN_set_obj_name; +extern std::function + KN_get_var_names; +extern std::function + KN_get_var_names_all; +extern std::function + KN_get_var_name; +extern std::function + KN_get_con_names; +extern std::function + KN_get_con_names_all; +extern std::function + KN_get_con_name; +extern std::function + KN_set_var_honorbnds; +extern std::function + KN_set_var_honorbnds_all; +extern std::function + KN_set_var_honorbnd; +extern std::function + KN_set_con_honorbnds; +extern std::function + KN_set_con_honorbnds_all; +extern std::function + KN_set_con_honorbnd; +extern std::function + KN_set_mip_var_primal_init_values; +extern std::function + KN_set_mip_var_primal_init_values_all; +extern std::function + KN_set_mip_var_primal_init_value; +extern std::function + KN_set_mip_branching_priorities; +extern std::function + KN_set_mip_branching_priorities_all; +extern std::function + KN_set_mip_branching_priority; +extern std::function + KN_set_mip_intvar_strategies; +extern std::function + KN_set_mip_intvar_strategies_all; +extern std::function + KN_set_mip_intvar_strategy; +extern std::function KN_solve; +extern std::function KN_update; +extern std::function + KN_get_number_vars; +extern std::function + KN_get_number_cons; +extern std::function + KN_get_number_compcons; +extern std::function + KN_get_number_rsds; +extern std::function + KN_get_number_FC_evals; +extern std::function + KN_get_number_GA_evals; +extern std::function + KN_get_number_H_evals; +extern std::function + KN_get_number_HV_evals; +extern std::function + KN_get_solve_time_cpu; +extern std::function + KN_get_solve_time_real; +extern std::function + KN_get_solution; +extern std::function + KN_get_obj_value; +extern std::function + KN_get_obj_type; +extern std::function + KN_get_var_primal_values; +extern std::function + KN_get_var_primal_values_all; +extern std::function + KN_get_var_primal_value; +extern std::function + KN_get_var_dual_values; +extern std::function + KN_get_var_dual_values_all; +extern std::function + KN_get_var_dual_value; +extern std::function + KN_get_con_dual_values; +extern std::function + KN_get_con_dual_values_all; +extern std::function + KN_get_con_dual_value; +extern std::function + KN_get_con_values; +extern std::function + KN_get_con_values_all; +extern std::function + KN_get_con_value; +extern std::function + KN_get_con_types; +extern std::function + KN_get_con_types_all; +extern std::function + KN_get_con_type; +extern std::function + KN_get_rsd_values; +extern std::function + KN_get_rsd_values_all; +extern std::function + KN_get_rsd_value; +extern std::function + KN_get_var_viols; +extern std::function + KN_get_var_viols_all; +extern std::function + KN_get_var_viol; +extern std::function + KN_get_con_viols; +extern std::function + KN_get_con_viols_all; +extern std::function + KN_get_con_viol; +extern std::function + KN_get_presolve_error; +extern std::function + KN_get_number_iters; +extern std::function + KN_get_number_cg_iters; +extern std::function + KN_get_abs_feas_error; +extern std::function + KN_get_rel_feas_error; +extern std::function + KN_get_abs_opt_error; +extern std::function + KN_get_rel_opt_error; +extern std::function + KN_get_objgrad_nnz; +extern std::function + KN_get_objgrad_values; +extern std::function + KN_get_objgrad_values_all; +extern std::function + KN_get_jacobian_nnz; +extern std::function + KN_get_jacobian_values; +extern std::function + KN_get_jacobian_nnz_one; +extern std::function + KN_get_jacobian_values_one; +extern std::function + KN_get_rsd_jacobian_nnz; +extern std::function + KN_get_rsd_jacobian_values; +extern std::function + KN_get_hessian_nnz; +extern std::function + KN_get_hessian_values; +extern std::function + KN_get_mip_number_nodes; +extern std::function + KN_get_mip_number_solves; +extern std::function + KN_get_mip_abs_gap; +extern std::function + KN_get_mip_rel_gap; +extern std::function + KN_get_mip_incumbent_obj; +extern std::function + KN_get_mip_relaxation_bnd; +extern std::function + KN_get_mip_lastnode_obj; +extern std::function + KN_get_mip_incumbent_x; + +} // namespace operations_research + +#endif // OR_TOOLS_KNITRO_ENVIRONMENT_H_ diff --git a/ortools/knitro/resources/bayg29.tsp b/ortools/knitro/resources/bayg29.tsp new file mode 100644 index 00000000000..3e57758ae79 --- /dev/null +++ b/ortools/knitro/resources/bayg29.tsp @@ -0,0 +1,30 @@ +29 + +97 +205 129 +139 103 219 +86 71 125 167 +60 105 175 182 51 +220 258 386 180 296 279 +65 154 269 162 150 114 178 +111 112 134 208 42 56 328 169 +115 65 184 39 131 150 206 151 172 +227 204 313 102 268 278 147 227 309 140 +95 150 201 227 88 46 308 133 68 195 320 +82 87 215 60 131 133 172 104 169 51 146 174 +225 176 267 86 245 266 203 242 286 117 64 311 144 +168 137 248 34 201 214 165 182 242 72 68 258 86 61 +103 142 271 96 175 162 121 84 208 104 143 196 57 165 106 +266 204 274 129 275 302 251 290 315 153 106 347 189 51 110 215 +205 148 236 69 218 242 216 230 259 93 88 288 128 32 56 159 61 +149 148 272 58 202 203 122 146 240 88 81 243 71 105 49 64 155 105 +120 49 160 60 119 146 231 165 160 25 159 192 71 127 91 126 157 100 113 +58 41 151 120 50 67 249 121 90 85 219 113 82 201 153 128 235 176 152 79 +257 211 300 119 281 300 209 270 322 152 63 345 176 36 91 190 47 66 127 163 236 +152 226 350 192 238 205 111 91 260 200 216 222 150 254 197 98 305 253 150 220 201 273 +52 116 239 114 131 111 169 48 160 104 187 144 56 196 136 53 243 183 106 119 90 226 112 +180 197 322 110 244 238 72 158 281 139 88 274 114 136 94 78 186 146 52 164 195 148 130 130 +136 89 78 192 51 98 338 200 57 154 293 124 168 260 225 218 282 231 235 135 90 296 286 178 281 +82 153 276 136 166 139 144 39 192 134 191 165 83 212 151 48 261 203 112 152 127 238 74 38 120 213 +34 124 220 173 95 52 237 64 107 149 258 71 115 258 201 127 300 239 179 153 84 291 155 75 205 145 94 +145 74 60 173 69 120 331 210 90 135 272 153 160 234 205 214 252 204 221 114 91 269 291 180 270 36 217 162 diff --git a/ortools/linear_solver/BUILD.bazel b/ortools/linear_solver/BUILD.bazel index 618e1921a6c..beb4317cec1 100644 --- a/ortools/linear_solver/BUILD.bazel +++ b/ortools/linear_solver/BUILD.bazel @@ -175,6 +175,7 @@ cc_library( "linear_solver_callback.cc", "sat_interface.cc", "xpress_interface.cc", + "knitro_interface.cc", ] + select({ ":use_bop": ["bop_interface.cc"], "//conditions:default": [], @@ -277,6 +278,7 @@ cc_library( "//ortools/util:fp_utils", "//ortools/util:lazy_mutable_copy", "//ortools/xpress:environment", + "//ortools/knitro:environment", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", diff --git a/ortools/linear_solver/CMakeLists.txt b/ortools/linear_solver/CMakeLists.txt index 74d20df48bc..f11a8e9a2d4 100644 --- a/ortools/linear_solver/CMakeLists.txt +++ b/ortools/linear_solver/CMakeLists.txt @@ -88,5 +88,18 @@ if(BUILD_TESTING) target_link_libraries(test_xprs_interface PRIVATE ortools::ortools GTest::gtest_main) add_test(NAME cxx_unittests_xpress_interface COMMAND test_xprs_interface) + + if(USE_KNITRO) + add_executable(test_knitro_interface knitro_interface_test.cc) + target_compile_features(test_knitro_interface PRIVATE cxx_std_17) + target_link_libraries(test_knitro_interface PRIVATE ortools::ortools GTest::gtest_main) + + add_test(NAME cxx_unittests_knitro_interface COMMAND test_knitro_interface) + + add_executable(test_knitro_interface_parallel knitro_interface_parallel_test.cc) + target_compile_features(test_knitro_interface_parallel PRIVATE cxx_std_17) + target_link_libraries(test_knitro_interface_parallel PRIVATE ortools::ortools GTest::gtest_main) + + # add_test(NAME cxx_unittests_knitro_interface COMMAND test_knitro_interface_parallel) endif() endif () diff --git a/ortools/linear_solver/csharp/linear_solver.i b/ortools/linear_solver/csharp/linear_solver.i index 58d621e0107..c7438c92d1d 100644 --- a/ortools/linear_solver/csharp/linear_solver.i +++ b/ortools/linear_solver/csharp/linear_solver.i @@ -97,6 +97,8 @@ CONVERT_VECTOR(operations_research::MPVariable, MPVariable) %unignore operations_research::MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING; %unignore operations_research::MPSolver::BOP_INTEGER_PROGRAMMING; %unignore operations_research::MPSolver::SAT_INTEGER_PROGRAMMING; +%unignore operations_research::MPSolver::KNITRO_LINEAR_PROGRAMMING; +%unignore operations_research::MPSolver::KNITRO_MIXED_INTEGER_PROGRAMMING; // Expose the MPSolver::ResultStatus enum. %unignore operations_research::MPSolver::ResultStatus; diff --git a/ortools/linear_solver/java/linear_solver.i b/ortools/linear_solver/java/linear_solver.i index cfd1c1add8b..5cfbdad63d6 100644 --- a/ortools/linear_solver/java/linear_solver.i +++ b/ortools/linear_solver/java/linear_solver.i @@ -339,6 +339,8 @@ PROTO2_RETURN( %unignore operations_research::MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING; %unignore operations_research::MPSolver::XPRESS_LINEAR_PROGRAMMING; %unignore operations_research::MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING; +%unignore operations_research::MPSolver::KNITRO_LINEAR_PROGRAMMING; +%unignore operations_research::MPSolver::KNITRO_MIXED_INTEGER_PROGRAMMING; // Expose the MPSolver::ResultStatus enum. %unignore operations_research::MPSolver::ResultStatus; diff --git a/ortools/linear_solver/knitro_interface.cc b/ortools/linear_solver/knitro_interface.cc new file mode 100644 index 00000000000..a12176f339d --- /dev/null +++ b/ortools/linear_solver/knitro_interface.cc @@ -0,0 +1,1164 @@ +// ADD HEADER + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/str_format.h" +#include "ortools/base/logging.h" +#include "ortools/base/timer.h" +#include "ortools/knitro/environment.h" +#include "ortools/linear_solver/linear_solver.h" + +#define CHECK_STATUS(s) \ + do { \ + int const status_ = s; \ + CHECK_EQ(0, status_); \ + } while (0) + +namespace operations_research { + +/** + * Knitro does not support inf values + * so it is mandatory to convert them into + * KN_INFINITY + * @param value the evaluated value + * @return KN_INFINITY if the value is inf otherwise value + */ +inline double redefine_infinity_double(double value) { + if (std::isinf(value)) { + return value > 0 ? KN_INFINITY : -KN_INFINITY; + } + return value; +} + +static std::map& getMapParam() { + static std::map mapControls = { + {"KN_PARAM_NEWPOINT", KN_PARAM_NEWPOINT}, + {"KN_PARAM_HONORBNDS", KN_PARAM_HONORBNDS}, + {"KN_PARAM_ALGORITHM", KN_PARAM_ALGORITHM}, + {"KN_PARAM_ALG", KN_PARAM_ALG}, + {"KN_PARAM_BAR_MURULE", KN_PARAM_BAR_MURULE}, + {"KN_PARAM_BAR_FEASIBLE", KN_PARAM_BAR_FEASIBLE}, + {"KN_PARAM_GRADOPT", KN_PARAM_GRADOPT}, + {"KN_PARAM_HESSOPT", KN_PARAM_HESSOPT}, + {"KN_PARAM_BAR_INITPT", KN_PARAM_BAR_INITPT}, + {"KN_PARAM_ACT_LPSOLVER", KN_PARAM_ACT_LPSOLVER}, + {"KN_PARAM_CG_MAXIT", KN_PARAM_CG_MAXIT}, + {"KN_PARAM_MAXIT", KN_PARAM_MAXIT}, + {"KN_PARAM_OUTLEV", KN_PARAM_OUTLEV}, + {"KN_PARAM_OUTMODE", KN_PARAM_OUTMODE}, + {"KN_PARAM_SCALE", KN_PARAM_SCALE}, + {"KN_PARAM_SOC", KN_PARAM_SOC}, + {"KN_PARAM_DELTA", KN_PARAM_DELTA}, + {"KN_PARAM_BAR_FEASMODETOL", KN_PARAM_BAR_FEASMODETOL}, + {"KN_PARAM_FEASTOL", KN_PARAM_FEASTOL}, + {"KN_PARAM_FEASTOLABS", KN_PARAM_FEASTOLABS}, + {"KN_PARAM_MAXTIMECPU", KN_PARAM_MAXTIMECPU}, + {"KN_PARAM_BAR_INITMU", KN_PARAM_BAR_INITMU}, + {"KN_PARAM_OBJRANGE", KN_PARAM_OBJRANGE}, + {"KN_PARAM_OPTTOL", KN_PARAM_OPTTOL}, + {"KN_PARAM_OPTTOLABS", KN_PARAM_OPTTOLABS}, + {"KN_PARAM_LINSOLVER_PIVOTTOL", KN_PARAM_LINSOLVER_PIVOTTOL}, + {"KN_PARAM_XTOL", KN_PARAM_XTOL}, + {"KN_PARAM_DEBUG", KN_PARAM_DEBUG}, + {"KN_PARAM_MULTISTART", KN_PARAM_MULTISTART}, + {"KN_PARAM_MSENABLE", KN_PARAM_MSENABLE}, + {"KN_PARAM_MS_ENABLE", KN_PARAM_MS_ENABLE}, + {"KN_PARAM_MSMAXSOLVES", KN_PARAM_MSMAXSOLVES}, + {"KN_PARAM_MS_MAXSOLVES", KN_PARAM_MS_MAXSOLVES}, + {"KN_PARAM_MSMAXBNDRANGE", KN_PARAM_MSMAXBNDRANGE}, + {"KN_PARAM_MS_MAXBNDRANGE", KN_PARAM_MS_MAXBNDRANGE}, + {"KN_PARAM_MSMAXTIMECPU", KN_PARAM_MSMAXTIMECPU}, + {"KN_PARAM_MS_MAXTIMECPU", KN_PARAM_MS_MAXTIMECPU}, + {"KN_PARAM_MSMAXTIMEREAL", KN_PARAM_MSMAXTIMEREAL}, + {"KN_PARAM_MS_MAXTIMEREAL", KN_PARAM_MS_MAXTIMEREAL}, + {"KN_PARAM_LMSIZE", KN_PARAM_LMSIZE}, + {"KN_PARAM_BAR_MAXCROSSIT", KN_PARAM_BAR_MAXCROSSIT}, + {"KN_PARAM_MAXTIMEREAL", KN_PARAM_MAXTIMEREAL}, + {"KN_PARAM_CG_PRECOND", KN_PARAM_CG_PRECOND}, + {"KN_PARAM_BLASOPTION", KN_PARAM_BLASOPTION}, + {"KN_PARAM_BAR_MAXREFACTOR", KN_PARAM_BAR_MAXREFACTOR}, + {"KN_PARAM_LINESEARCH_MAXTRIALS", KN_PARAM_LINESEARCH_MAXTRIALS}, + {"KN_PARAM_BLASOPTIONLIB", KN_PARAM_BLASOPTIONLIB}, + {"KN_PARAM_OUTAPPEND", KN_PARAM_OUTAPPEND}, + {"KN_PARAM_OUTDIR", KN_PARAM_OUTDIR}, + {"KN_PARAM_CPLEXLIB", KN_PARAM_CPLEXLIB}, + {"KN_PARAM_BAR_PENRULE", KN_PARAM_BAR_PENRULE}, + {"KN_PARAM_BAR_PENCONS", KN_PARAM_BAR_PENCONS}, + {"KN_PARAM_MSNUMTOSAVE", KN_PARAM_MSNUMTOSAVE}, + {"KN_PARAM_MS_NUMTOSAVE", KN_PARAM_MS_NUMTOSAVE}, + {"KN_PARAM_MSSAVETOL", KN_PARAM_MSSAVETOL}, + {"KN_PARAM_MS_SAVETOL", KN_PARAM_MS_SAVETOL}, + {"KN_PARAM_PRESOLVEDEBUG", KN_PARAM_PRESOLVEDEBUG}, + {"KN_PARAM_MSTERMINATE", KN_PARAM_MSTERMINATE}, + {"KN_PARAM_MS_TERMINATE", KN_PARAM_MS_TERMINATE}, + {"KN_PARAM_MSSTARTPTRANGE", KN_PARAM_MSSTARTPTRANGE}, + {"KN_PARAM_MS_STARTPTRANGE", KN_PARAM_MS_STARTPTRANGE}, + {"KN_PARAM_INFEASTOL", KN_PARAM_INFEASTOL}, + {"KN_PARAM_LINSOLVER", KN_PARAM_LINSOLVER}, + {"KN_PARAM_BAR_DIRECTINTERVAL", KN_PARAM_BAR_DIRECTINTERVAL}, + {"KN_PARAM_PRESOLVE", KN_PARAM_PRESOLVE}, + {"KN_PARAM_PRESOLVE_TOL", KN_PARAM_PRESOLVE_TOL}, + {"KN_PARAM_BAR_SWITCHRULE", KN_PARAM_BAR_SWITCHRULE}, + {"KN_PARAM_HESSIAN_NO_F", KN_PARAM_HESSIAN_NO_F}, + {"KN_PARAM_MA_TERMINATE", KN_PARAM_MA_TERMINATE}, + {"KN_PARAM_MA_MAXTIMECPU", KN_PARAM_MA_MAXTIMECPU}, + {"KN_PARAM_MA_MAXTIMEREAL", KN_PARAM_MA_MAXTIMEREAL}, + {"KN_PARAM_MSSEED", KN_PARAM_MSSEED}, + {"KN_PARAM_MS_SEED", KN_PARAM_MS_SEED}, + {"KN_PARAM_MA_OUTSUB", KN_PARAM_MA_OUTSUB}, + {"KN_PARAM_MS_OUTSUB", KN_PARAM_MS_OUTSUB}, + {"KN_PARAM_XPRESSLIB", KN_PARAM_XPRESSLIB}, + {"KN_PARAM_TUNER", KN_PARAM_TUNER}, + {"KN_PARAM_TUNER_OPTIONSFILE", KN_PARAM_TUNER_OPTIONSFILE}, + {"KN_PARAM_TUNER_MAXTIMECPU", KN_PARAM_TUNER_MAXTIMECPU}, + {"KN_PARAM_TUNER_MAXTIMEREAL", KN_PARAM_TUNER_MAXTIMEREAL}, + {"KN_PARAM_TUNER_OUTSUB", KN_PARAM_TUNER_OUTSUB}, + {"KN_PARAM_TUNER_TERMINATE", KN_PARAM_TUNER_TERMINATE}, + {"KN_PARAM_LINSOLVER_OOC", KN_PARAM_LINSOLVER_OOC}, + {"KN_PARAM_BAR_RELAXCONS", KN_PARAM_BAR_RELAXCONS}, + {"KN_PARAM_MSDETERMINISTIC", KN_PARAM_MSDETERMINISTIC}, + {"KN_PARAM_MS_DETERMINISTIC", KN_PARAM_MS_DETERMINISTIC}, + {"KN_PARAM_BAR_REFINEMENT", KN_PARAM_BAR_REFINEMENT}, + {"KN_PARAM_DERIVCHECK", KN_PARAM_DERIVCHECK}, + {"KN_PARAM_DERIVCHECK_TYPE", KN_PARAM_DERIVCHECK_TYPE}, + {"KN_PARAM_DERIVCHECK_TOL", KN_PARAM_DERIVCHECK_TOL}, + {"KN_PARAM_LINSOLVER_INEXACT", KN_PARAM_LINSOLVER_INEXACT}, + {"KN_PARAM_LINSOLVER_INEXACTTOL", KN_PARAM_LINSOLVER_INEXACTTOL}, + {"KN_PARAM_MAXFEVALS", KN_PARAM_MAXFEVALS}, + {"KN_PARAM_FSTOPVAL", KN_PARAM_FSTOPVAL}, + {"KN_PARAM_DATACHECK", KN_PARAM_DATACHECK}, + {"KN_PARAM_DERIVCHECK_TERMINATE", KN_PARAM_DERIVCHECK_TERMINATE}, + {"KN_PARAM_BAR_WATCHDOG", KN_PARAM_BAR_WATCHDOG}, + {"KN_PARAM_FTOL", KN_PARAM_FTOL}, + {"KN_PARAM_FTOL_ITERS", KN_PARAM_FTOL_ITERS}, + {"KN_PARAM_ACT_QPALG", KN_PARAM_ACT_QPALG}, + {"KN_PARAM_BAR_INITPI_MPEC", KN_PARAM_BAR_INITPI_MPEC}, + {"KN_PARAM_XTOL_ITERS", KN_PARAM_XTOL_ITERS}, + {"KN_PARAM_LINESEARCH", KN_PARAM_LINESEARCH}, + {"KN_PARAM_OUT_CSVINFO", KN_PARAM_OUT_CSVINFO}, + {"KN_PARAM_INITPENALTY", KN_PARAM_INITPENALTY}, + {"KN_PARAM_ACT_LPFEASTOL", KN_PARAM_ACT_LPFEASTOL}, + {"KN_PARAM_CG_STOPTOL", KN_PARAM_CG_STOPTOL}, + {"KN_PARAM_RESTARTS", KN_PARAM_RESTARTS}, + {"KN_PARAM_RESTARTS_MAXIT", KN_PARAM_RESTARTS_MAXIT}, + {"KN_PARAM_BAR_SLACKBOUNDPUSH", KN_PARAM_BAR_SLACKBOUNDPUSH}, + {"KN_PARAM_CG_PMEM", KN_PARAM_CG_PMEM}, + {"KN_PARAM_BAR_SWITCHOBJ", KN_PARAM_BAR_SWITCHOBJ}, + {"KN_PARAM_OUTNAME", KN_PARAM_OUTNAME}, + {"KN_PARAM_OUT_CSVNAME", KN_PARAM_OUT_CSVNAME}, + {"KN_PARAM_ACT_PARAMETRIC", KN_PARAM_ACT_PARAMETRIC}, + {"KN_PARAM_ACT_LPDUMPMPS", KN_PARAM_ACT_LPDUMPMPS}, + {"KN_PARAM_ACT_LPALG", KN_PARAM_ACT_LPALG}, + {"KN_PARAM_ACT_LPPRESOLVE", KN_PARAM_ACT_LPPRESOLVE}, + {"KN_PARAM_ACT_LPPENALTY", KN_PARAM_ACT_LPPENALTY}, + {"KN_PARAM_BNDRANGE", KN_PARAM_BNDRANGE}, + {"KN_PARAM_BAR_CONIC_ENABLE", KN_PARAM_BAR_CONIC_ENABLE}, + {"KN_PARAM_CONVEX", KN_PARAM_CONVEX}, + {"KN_PARAM_OUT_HINTS", KN_PARAM_OUT_HINTS}, + {"KN_PARAM_EVAL_FCGA", KN_PARAM_EVAL_FCGA}, + {"KN_PARAM_BAR_MAXCORRECTORS", KN_PARAM_BAR_MAXCORRECTORS}, + {"KN_PARAM_STRAT_WARM_START", KN_PARAM_STRAT_WARM_START}, + {"KN_PARAM_FINDIFF_TERMINATE", KN_PARAM_FINDIFF_TERMINATE}, + {"KN_PARAM_CPUPLATFORM", KN_PARAM_CPUPLATFORM}, + {"KN_PARAM_PRESOLVE_PASSES", KN_PARAM_PRESOLVE_PASSES}, + {"KN_PARAM_PRESOLVE_LEVEL", KN_PARAM_PRESOLVE_LEVEL}, + {"KN_PARAM_FINDIFF_RELSTEPSIZE", KN_PARAM_FINDIFF_RELSTEPSIZE}, + {"KN_PARAM_INFEASTOL_ITERS", KN_PARAM_INFEASTOL_ITERS}, + {"KN_PARAM_PRESOLVEOP_TIGHTEN", KN_PARAM_PRESOLVEOP_TIGHTEN}, + {"KN_PARAM_BAR_LINSYS", KN_PARAM_BAR_LINSYS}, + {"KN_PARAM_PRESOLVE_INITPT", KN_PARAM_PRESOLVE_INITPT}, + {"KN_PARAM_ACT_QPPENALTY", KN_PARAM_ACT_QPPENALTY}, + {"KN_PARAM_BAR_LINSYS_STORAGE", KN_PARAM_BAR_LINSYS_STORAGE}, + {"KN_PARAM_LINSOLVER_MAXITREF", KN_PARAM_LINSOLVER_MAXITREF}, + {"KN_PARAM_BFGS_SCALING", KN_PARAM_BFGS_SCALING}, + {"KN_PARAM_BAR_INITSHIFTTOL", KN_PARAM_BAR_INITSHIFTTOL}, + {"KN_PARAM_NUMTHREADS", KN_PARAM_NUMTHREADS}, + {"KN_PARAM_CONCURRENT_EVALS", KN_PARAM_CONCURRENT_EVALS}, + {"KN_PARAM_BLAS_NUMTHREADS", KN_PARAM_BLAS_NUMTHREADS}, + {"KN_PARAM_LINSOLVER_NUMTHREADS", KN_PARAM_LINSOLVER_NUMTHREADS}, + {"KN_PARAM_MS_NUMTHREADS", KN_PARAM_MS_NUMTHREADS}, + {"KN_PARAM_CONIC_NUMTHREADS", KN_PARAM_CONIC_NUMTHREADS}, + {"KN_PARAM_NCVX_QCQP_INIT", KN_PARAM_NCVX_QCQP_INIT}, + {"KN_PARAM_FINDIFF_ESTNOISE", KN_PARAM_FINDIFF_ESTNOISE}, + {"KN_PARAM_FINDIFF_NUMTHREADS", KN_PARAM_FINDIFF_NUMTHREADS}, + {"KN_PARAM_BAR_MPEC_HEURISTIC", KN_PARAM_BAR_MPEC_HEURISTIC}, + {"KN_PARAM_PRESOLVEOP_REDUNDANT", KN_PARAM_PRESOLVEOP_REDUNDANT}, + {"KN_PARAM_LINSOLVER_ORDERING", KN_PARAM_LINSOLVER_ORDERING}, + {"KN_PARAM_LINSOLVER_NODEAMALG", KN_PARAM_LINSOLVER_NODEAMALG}, + {"KN_PARAM_PRESOLVEOP_SUBSTITUTION", KN_PARAM_PRESOLVEOP_SUBSTITUTION}, + {"KN_PARAM_PRESOLVEOP_SUBSTITUTION_TOL", + KN_PARAM_PRESOLVEOP_SUBSTITUTION_TOL}, + {"KN_PARAM_MS_INITPT_CLUSTER", KN_PARAM_MS_INITPT_CLUSTER}, + {"KN_PARAM_SCALE_VARS", KN_PARAM_SCALE_VARS}, + {"KN_PARAM_BAR_MAXMU", KN_PARAM_BAR_MAXMU}, + {"KN_PARAM_BAR_GLOBALIZE", KN_PARAM_BAR_GLOBALIZE}, + {"KN_PARAM_LINSOLVER_SCALING", KN_PARAM_LINSOLVER_SCALING}, + {"KN_PARAM_MIP_METHOD", KN_PARAM_MIP_METHOD}, + {"KN_PARAM_MIP_BRANCHRULE", KN_PARAM_MIP_BRANCHRULE}, + {"KN_PARAM_MIP_SELECTRULE", KN_PARAM_MIP_SELECTRULE}, + {"KN_PARAM_MIP_INTGAPABS", KN_PARAM_MIP_INTGAPABS}, + {"KN_PARAM_MIP_OPTGAPABS", KN_PARAM_MIP_OPTGAPABS}, + {"KN_PARAM_MIP_INTGAPREL", KN_PARAM_MIP_INTGAPREL}, + {"KN_PARAM_MIP_OPTGAPREL", KN_PARAM_MIP_OPTGAPREL}, + {"KN_PARAM_MIP_MAXTIMECPU", KN_PARAM_MIP_MAXTIMECPU}, + {"KN_PARAM_MIP_MAXTIMEREAL", KN_PARAM_MIP_MAXTIMEREAL}, + {"KN_PARAM_MIP_MAXSOLVES", KN_PARAM_MIP_MAXSOLVES}, + {"KN_PARAM_MIP_INTEGERTOL", KN_PARAM_MIP_INTEGERTOL}, + {"KN_PARAM_MIP_OUTLEVEL", KN_PARAM_MIP_OUTLEVEL}, + {"KN_PARAM_MIP_OUTINTERVAL", KN_PARAM_MIP_OUTINTERVAL}, + {"KN_PARAM_MIP_OUTSUB", KN_PARAM_MIP_OUTSUB}, + {"KN_PARAM_MIP_DEBUG", KN_PARAM_MIP_DEBUG}, + {"KN_PARAM_MIP_IMPLICATNS", KN_PARAM_MIP_IMPLICATNS}, + {"KN_PARAM_MIP_IMPLICATIONS", KN_PARAM_MIP_IMPLICATIONS}, + {"KN_PARAM_MIP_GUB_BRANCH", KN_PARAM_MIP_GUB_BRANCH}, + {"KN_PARAM_MIP_KNAPSACK", KN_PARAM_MIP_KNAPSACK}, + {"KN_PARAM_MIP_ROUNDING", KN_PARAM_MIP_ROUNDING}, + {"KN_PARAM_MIP_ROOTALG", KN_PARAM_MIP_ROOTALG}, + {"KN_PARAM_MIP_LPALG", KN_PARAM_MIP_LPALG}, + {"KN_PARAM_MIP_TERMINATE", KN_PARAM_MIP_TERMINATE}, + {"KN_PARAM_MIP_MAXNODES", KN_PARAM_MIP_MAXNODES}, + {"KN_PARAM_MIP_HEURISTIC", KN_PARAM_MIP_HEURISTIC}, + {"KN_PARAM_MIP_HEUR_MAXIT", KN_PARAM_MIP_HEUR_MAXIT}, + {"KN_PARAM_MIP_HEUR_MAXTIMECPU", KN_PARAM_MIP_HEUR_MAXTIMECPU}, + {"KN_PARAM_MIP_HEUR_MAXTIMEREAL", KN_PARAM_MIP_HEUR_MAXTIMEREAL}, + {"KN_PARAM_MIP_PSEUDOINIT", KN_PARAM_MIP_PSEUDOINIT}, + {"KN_PARAM_MIP_STRONG_MAXIT", KN_PARAM_MIP_STRONG_MAXIT}, + {"KN_PARAM_MIP_STRONG_CANDLIM", KN_PARAM_MIP_STRONG_CANDLIM}, + {"KN_PARAM_MIP_STRONG_LEVEL", KN_PARAM_MIP_STRONG_LEVEL}, + {"KN_PARAM_MIP_INTVAR_STRATEGY", KN_PARAM_MIP_INTVAR_STRATEGY}, + {"KN_PARAM_MIP_RELAXABLE", KN_PARAM_MIP_RELAXABLE}, + {"KN_PARAM_MIP_NODEALG", KN_PARAM_MIP_NODEALG}, + {"KN_PARAM_MIP_HEUR_TERMINATE", KN_PARAM_MIP_HEUR_TERMINATE}, + {"KN_PARAM_MIP_SELECTDIR", KN_PARAM_MIP_SELECTDIR}, + {"KN_PARAM_MIP_CUTFACTOR", KN_PARAM_MIP_CUTFACTOR}, + {"KN_PARAM_MIP_ZEROHALF", KN_PARAM_MIP_ZEROHALF}, + {"KN_PARAM_MIP_MIR", KN_PARAM_MIP_MIR}, + {"KN_PARAM_MIP_CLIQUE", KN_PARAM_MIP_CLIQUE}, + {"KN_PARAM_MIP_HEUR_STRATEGY", KN_PARAM_MIP_HEUR_STRATEGY}, + {"KN_PARAM_MIP_HEUR_FEASPUMP", KN_PARAM_MIP_HEUR_FEASPUMP}, + {"KN_PARAM_MIP_HEUR_MPEC", KN_PARAM_MIP_HEUR_MPEC}, + {"KN_PARAM_MIP_HEUR_DIVING", KN_PARAM_MIP_HEUR_DIVING}, + {"KN_PARAM_MIP_CUTTINGPLANE", KN_PARAM_MIP_CUTTINGPLANE}, + {"KN_PARAM_MIP_CUTOFF", KN_PARAM_MIP_CUTOFF}, + {"KN_PARAM_MIP_HEUR_LNS", KN_PARAM_MIP_HEUR_LNS}, + {"KN_PARAM_MIP_MULTISTART", KN_PARAM_MIP_MULTISTART}, + {"KN_PARAM_MIP_LIFTPROJECT", KN_PARAM_MIP_LIFTPROJECT}, + {"KN_PARAM_MIP_NUMTHREADS", KN_PARAM_MIP_NUMTHREADS}, + {"KN_PARAM_MIP_HEUR_MISQP", KN_PARAM_MIP_HEUR_MISQP}, + {"KN_PARAM_MIP_RESTART", KN_PARAM_MIP_RESTART}, + {"KN_PARAM_MIP_GOMORY", KN_PARAM_MIP_GOMORY}, + {"KN_PARAM_MIP_CUT_PROBING", KN_PARAM_MIP_CUT_PROBING}, + {"KN_PARAM_MIP_CUT_FLOWCOVER", KN_PARAM_MIP_CUT_FLOWCOVER}, + {"KN_PARAM_MIP_HEUR_LOCALSEARCH", KN_PARAM_MIP_HEUR_LOCALSEARCH}, + {"KN_PARAM_PAR_NUMTHREADS", KN_PARAM_PAR_NUMTHREADS}, + {"KN_PARAM_PAR_CONCURRENT_EVALS", KN_PARAM_PAR_CONCURRENT_EVALS}, + {"KN_PARAM_PAR_BLASNUMTHREADS", KN_PARAM_PAR_BLASNUMTHREADS}, + {"KN_PARAM_PAR_LSNUMTHREADS", KN_PARAM_PAR_LSNUMTHREADS}, + {"KN_PARAM_PAR_MSNUMTHREADS", KN_PARAM_PAR_MSNUMTHREADS}, + {"KN_PARAM_PAR_CONICNUMTHREADS", KN_PARAM_PAR_CONICNUMTHREADS}, + }; + return mapControls; +} + +/*------------KnitroInterface Definition------------*/ + +class KnitroInterface : public MPSolverInterface { + public: + explicit KnitroInterface(MPSolver* solver, bool mip); + ~KnitroInterface() override; + + MPSolver::ResultStatus Solve(const MPSolverParameters& param) override; + + void Write(const std::string& filename) override; + void Reset() override; + + double infinity() override { return KN_INFINITY; }; + + void SetOptimizationDirection(bool maximize) override; + void SetVariableBounds(int var_index, double lb, double ub) override; + void SetVariableInteger(int var_index, bool integer) override; + void SetConstraintBounds(int row_index, double lb, double ub) override; + + void AddRowConstraint(MPConstraint* ct) override; + void AddVariable(MPVariable* var) override; + void SetCoefficient(MPConstraint* constraint, const MPVariable* variable, + double new_value, double old_value) override; + void ClearConstraint(MPConstraint* constraint) override; + void SetObjectiveCoefficient(const MPVariable* variable, + double coefficient) override; + void SetObjectiveOffset(double value) override; + void ClearObjective() override; + void BranchingPriorityChangedForVariable(int var_index) override; + + int64_t iterations() const override; + int64_t nodes() const override; + + MPSolver::BasisStatus row_status(int constraint_index) const override { + LOG(DFATAL) << "Not Supported by Knitro ! "; + return MPSolver::FREE; + } + MPSolver::BasisStatus column_status(int variable_index) const override { + LOG(DFATAL) << "Not Supported by Knitro ! "; + return MPSolver::FREE; + } + + bool IsContinuous() const override { return !mip_; } + bool IsLP() const override { return !mip_; } + bool IsMIP() const override { return mip_; } + + void ExtractNewVariables() override; + void ExtractNewConstraints() override; + void ExtractObjective() override; + + std::string SolverVersion() const override; + + void* underlying_solver() override { return reinterpret_cast(kc_); } + + virtual double ComputeExactConditionNumber() const override { + LOG(DFATAL) << "ComputeExactConditionNumber not implemented for" + << " Knitro Programming"; + return 0.0; + }; + + void SetCallback(MPCallback* mp_callback) override; + bool SupportsCallbacks() const override { return true; } + + private: + void SetParameters(const MPSolverParameters& param) override; + void SetRelativeMipGap(double value) override; + void SetPrimalTolerance(double value) override; + void SetDualTolerance(double value) override; + void SetPresolveMode(int presolve) override; + void SetScalingMode(int scaling) override; + void SetLpAlgorithm(int lp_algorithm) override; + + absl::Status SetNumThreads(int num_threads) override; + + bool SetSolverSpecificParametersAsString( + const std::string& parameters) override; + + void AddSolutionHintToOptimizer(); + void SetSolution(); + + KN_context* kc_; + bool mip_; + bool no_obj_; + MPCallback* callback_ = nullptr; + std::map param_map_; +}; + +/*------------Knitro CallBack Context------------*/ + +/** + * Knitro's MPCallbackContext derived class + * + * Stores the values x and lambda provided by Knitro MIP Callback functions + * eventhough lambda can't be used with the current MPCallbackContext definition + * + * Return code from Knitro solver's cuts can't be retrieved neither + */ +class KnitroMPCallbackContext : public MPCallbackContext { + friend class KnitroInterface; + + public: + KnitroMPCallbackContext(KN_context_ptr* kc, MPCallbackEvent event, + const double* const x, const double* const lambda) + : kc_ptr_(kc), event_(event), var_val(x), lambda(lambda){}; + + // Implementation of the interface. + MPCallbackEvent Event() override { return event_; }; + bool CanQueryVariableValues() override; + double VariableValue(const MPVariable* variable) override; + + // Knitro supports cuts and lazy constraints only + void AddCut(const LinearRange& cutting_plane) override; + void AddLazyConstraint(const LinearRange& lazy_constraint) override; + double SuggestSolution( + const absl::flat_hash_map& solution) override { + LOG(WARNING) << "SuggestSolution is not implemented in Knitro interface"; + return NAN; + } + + int64_t NumExploredNodes() override; + + private: + KN_context_ptr* kc_ptr_; + MPCallbackEvent event_; + const double* const var_val; + // lambda is not used + const double* const lambda; +}; + +bool KnitroMPCallbackContext::CanQueryVariableValues() { + switch (event_) { + case MPCallbackEvent::kMipSolution: + case MPCallbackEvent::kMipNode: + return true; + default: + return false; + } +} + +double KnitroMPCallbackContext::VariableValue(const MPVariable* variable) { + return var_val[variable->index()]; +} + +int64_t KnitroMPCallbackContext::NumExploredNodes() { + int num_nodes; + CHECK_STATUS(KN_get_mip_number_nodes(*kc_ptr_, &num_nodes)); + return num_nodes; +} + +/** + * Constraint generator for callback methods. + * Add new linear constraint to Knitro model as Knitro + * generate cuts from lazy constraints using the same method. + * @param kn the Knitro model + * @param linear_range the constraint + */ +void GenerateConstraint(KN_context* kc, const LinearRange& linear_range) { + const int num_terms = linear_range.linear_expr().terms().size(); + std::unique_ptr var_indexes(new int[num_terms]); + std::unique_ptr var_coefficients(new double[num_terms]); + int term_index = 0; + for (const auto& var_coef_pair : linear_range.linear_expr().terms()) { + var_indexes[term_index] = var_coef_pair.first->index(); + var_coefficients[term_index] = var_coef_pair.second; + ++term_index; + } + int cb_con; + CHECK_STATUS(KN_add_con(kc, &cb_con)); + CHECK_STATUS(KN_set_con_lobnd( + kc, cb_con, redefine_infinity_double(linear_range.lower_bound()))); + CHECK_STATUS(KN_set_con_upbnd( + kc, cb_con, redefine_infinity_double(linear_range.upper_bound()))); + CHECK_STATUS(KN_add_con_linear_struct_one(kc, num_terms, cb_con, + var_indexes.get(), + var_coefficients.get())); +} + +void KnitroMPCallbackContext::AddCut(const LinearRange& cutting_plane) { + CHECK(event_ == MPCallbackEvent::kMipNode); + GenerateConstraint(*kc_ptr_, cutting_plane); +} + +void KnitroMPCallbackContext::AddLazyConstraint( + const LinearRange& lazy_constraint) { + CHECK(event_ == MPCallbackEvent::kMipNode || + event_ == MPCallbackEvent::kMipSolution); + GenerateConstraint(*kc_ptr_, lazy_constraint); +} + +struct MPCallBackWithEvent { + MPCallbackEvent event; + MPCallback* callback; +}; + +/** + * Call-back called by Knitro that needs this type signature. + */ +int KNITRO_API CallBackFn(KN_context_ptr kc, const double* const x, + const double* const lambda, void* const userParams) { + MPCallBackWithEvent* const callback_with_event = + static_cast(userParams); + CHECK(callback_with_event != nullptr); + std::unique_ptr cb_context; + cb_context = std::make_unique( + &kc, callback_with_event->event, x, lambda); + callback_with_event->callback->RunCallback(cb_context.get()); + return 0; +} + +/*------------Knitro Interface Implem ------------*/ + +KnitroInterface::KnitroInterface(MPSolver* solver, bool mip) + : MPSolverInterface(solver), + kc_(nullptr), + mip_(mip), + no_obj_(true), + param_map_(getMapParam()) { + KnitroIsCorrectlyInstalled(); + CHECK_STATUS(KN_new(&kc_)); +} + +/** + * Cleans the Knitro problem using Knitro free method. + */ +KnitroInterface::~KnitroInterface() { CHECK_STATUS(KN_free(&kc_)); } + +// ------ Model modifications and extraction ----- + +void KnitroInterface::Reset() { + // Instead of explicitly clearing all model objects we + // just delete the problem object and allocate a new one. + CHECK_STATUS(KN_free(&kc_)); + no_obj_ = true; + int status; + status = KN_new(&kc_); + CHECK_STATUS(status); + DCHECK(kc_ != nullptr); // should not be NULL if status=0 + ResetExtractionInformation(); +} + +void KnitroInterface::Write(const std::string& filename) { + ExtractModel(); + VLOG(1) << "Writing Knitro MPS \"" << filename << "\"."; + const int status = KN_write_mps_file(kc_, filename.c_str()); + if (status) { + LOG(ERROR) << "Knitro: Failed to write MPS!"; + } +} + +void KnitroInterface::SetOptimizationDirection(bool maximize) { + InvalidateSolutionSynchronization(); + CHECK_STATUS(KN_set_obj_goal( + kc_, (maximize) ? KN_OBJGOAL_MAXIMIZE : KN_OBJGOAL_MINIMIZE)); +} + +void KnitroInterface::SetVariableBounds(int var_index, double lb, double ub) { + InvalidateSolutionSynchronization(); + if (variable_is_extracted(var_index)) { + // Not cached if the variable has been extracted. + DCHECK_LT(var_index, last_variable_index_); + CHECK_STATUS( + KN_set_var_lobnd(kc_, var_index, redefine_infinity_double(lb))); + CHECK_STATUS( + KN_set_var_upbnd(kc_, var_index, redefine_infinity_double(ub))); + } else { + sync_status_ = MUST_RELOAD; + } +} + +void KnitroInterface::SetVariableInteger(int var_index, bool integer) { + InvalidateSolutionSynchronization(); + if (mip_) { + if (variable_is_extracted(var_index)) { + DCHECK_LT(var_index, last_variable_index_); + CHECK_STATUS(KN_set_var_type( + kc_, var_index, + integer ? KN_VARTYPE_INTEGER : KN_VARTYPE_CONTINUOUS)); + } else { + sync_status_ = MUST_RELOAD; + } + } else { + LOG(DFATAL) << "Attempt to change variable to integer in non-MIP problem!"; + } +} + +void KnitroInterface::SetConstraintBounds(int row_index, double lb, double ub) { + InvalidateSolutionSynchronization(); + if (constraint_is_extracted(row_index)) { + DCHECK_LT(row_index, last_constraint_index_); + CHECK_STATUS( + KN_set_con_lobnd(kc_, row_index, redefine_infinity_double(lb))); + CHECK_STATUS( + KN_set_con_upbnd(kc_, row_index, redefine_infinity_double(ub))); + } else { + sync_status_ = MUST_RELOAD; + } +} + +void KnitroInterface::SetCoefficient(MPConstraint* constraint, + const MPVariable* variable, + double new_value, double old_value) { + InvalidateSolutionSynchronization(); + int var_index = variable->index(), row_index = constraint->index(); + if (variable_is_extracted(var_index) && constraint_is_extracted(row_index)) { + DCHECK_LT(row_index, last_constraint_index_); + DCHECK_LT(var_index, last_variable_index_); + CHECK_STATUS(KN_chg_con_linear_term(kc_, row_index, var_index, new_value)); + CHECK_STATUS(KN_update(kc_)); + } else { + sync_status_ = MUST_RELOAD; + } +} + +void KnitroInterface::ClearConstraint(MPConstraint* constraint) { + InvalidateSolutionSynchronization(); + + int const row = constraint->index(); + + if (!constraint_is_extracted(row)) return; + + int const len = constraint->coefficients_.size(); + std::unique_ptr var_ind(new int[len]); + int j = 0; + const auto& coeffs = constraint->coefficients_; + for (auto coeff : coeffs) { + int const col = coeff.first->index(); + // if the variable has been extracted then its linear coefficient exists + if (variable_is_extracted(col)) { + var_ind[j] = col; + ++j; + } + } + if (j > 0) { + // delete all coefficients of constraint's linear structure + CHECK_STATUS(KN_del_con_linear_struct_one(kc_, j, row, var_ind.get())); + CHECK_STATUS(KN_update(kc_)); + } +} + +void KnitroInterface::SetObjectiveCoefficient(const MPVariable* variable, + double coefficient) { + sync_status_ = MUST_RELOAD; +} + +void KnitroInterface::SetObjectiveOffset(double value) { + sync_status_ = MUST_RELOAD; +} + +void KnitroInterface::ClearObjective() { + // if the model does not have objective, return + if (no_obj_) return; + if (solver_->Objective().offset()) CHECK_STATUS(KN_del_obj_constant(kc_)); + InvalidateSolutionSynchronization(); + int const cols = solver_->objective_->coefficients_.size(); + std::unique_ptr ind(new int[cols]); + int j = 0; + const auto& coeffs = solver_->objective_->coefficients_; + for (auto coeff : coeffs) { + int const idx = coeff.first->index(); + // We only need to reset variables that have been extracted. + if (variable_is_extracted(idx)) { + DCHECK_LT(idx, cols); + ind[j] = idx; + ++j; + } + } + if (j > 0) { + CHECK_STATUS(KN_del_obj_linear_struct(kc_, j, ind.get())); + CHECK_STATUS(KN_update(kc_)); + } + no_obj_ = true; +} + +void KnitroInterface::BranchingPriorityChangedForVariable(int var_index) { + InvalidateSolutionSynchronization(); + if (mip_) { + if (variable_is_extracted(var_index)) { + DCHECK_LT(var_index, last_variable_index_); + int const priority = solver_->variables_[var_index]->branching_priority(); + CHECK_STATUS(KN_set_mip_branching_priority(kc_, var_index, priority)); + } else { + sync_status_ = MUST_RELOAD; + } + } else { + LOG(DFATAL) << "Attempt to change branching priority of variable in " + "non-MIP problem!"; + } +} + +void KnitroInterface::AddRowConstraint(MPConstraint* ct) { + sync_status_ = MUST_RELOAD; +} + +void KnitroInterface::AddVariable(MPVariable* var) { + sync_status_ = MUST_RELOAD; +} + +void KnitroInterface::ExtractNewVariables() { + int const total_num_vars = solver_->variables_.size(); + if (total_num_vars > last_variable_index_) { + int const number_added_vars = total_num_vars - last_variable_index_; + + std::unique_ptr idx_vars(new int[number_added_vars]); + std::unique_ptr lb(new double[number_added_vars]); + std::unique_ptr ub(new double[number_added_vars]); + std::unique_ptr types(new int[number_added_vars]); + // for priority properties + std::unique_ptr priority(new int[number_added_vars]); + std::unique_ptr priority_idx(new int[number_added_vars]); + int num_priority_vars = 0; + + // Create new variables + CHECK_STATUS(KN_add_vars(kc_, number_added_vars, NULL)); + for (int var_index = last_variable_index_; var_index < total_num_vars; + ++var_index) { + MPVariable* const var = solver_->variables_[var_index]; + DCHECK(!variable_is_extracted(var_index)); + set_variable_as_extracted(var_index, true); + + // Define the bounds and type of var + idx_vars[var_index - last_variable_index_] = var_index; + lb[var_index - last_variable_index_] = redefine_infinity_double(var->lb()); + ub[var_index - last_variable_index_] = redefine_infinity_double(var->ub()); + types[var_index - last_variable_index_] = ((mip_ && var->integer()) + ? KN_VARTYPE_INTEGER + : KN_VARTYPE_CONTINUOUS); + + // Name the var + CHECK_STATUS(KN_set_var_name(kc_, var_index, (char*)var->name().c_str())); + + // Branching priority + if (var->integer() && (var->branching_priority() != 0)) { + priority_idx[num_priority_vars] = var_index; + priority[num_priority_vars] = var->branching_priority(); + num_priority_vars++; + } + } + + CHECK_STATUS(KN_set_var_lobnds(kc_, number_added_vars, idx_vars.get(), lb.get())); + CHECK_STATUS(KN_set_var_upbnds(kc_, number_added_vars, idx_vars.get(), ub.get())); + CHECK_STATUS(KN_set_var_types(kc_, number_added_vars, idx_vars.get(), types.get())); + CHECK_STATUS(KN_set_mip_branching_priorities(kc_, num_priority_vars, priority_idx.get(), + priority.get())); + + // Adds new variables to existing constraints. + for (int i = 0; i < last_constraint_index_; i++) { + MPConstraint* const ct = solver_->constraints_[i]; + for (const auto& entry : ct->coefficients_) { + const int var_index = entry.first->index(); + DCHECK(variable_is_extracted(var_index)); + if (var_index >= last_variable_index_) { + // The variable is new, so we know the previous coefficient + // value was 0 and we can directly add the coefficient. + CHECK_STATUS(KN_add_con_linear_term(kc_, i, var_index, entry.second)); + } + } + } + } +} + +void KnitroInterface::ExtractNewConstraints() { + int const total_num_cons = solver_->constraints_.size(); + int const total_num_vars = solver_->variables_.size(); + if (total_num_cons > last_constraint_index_) { + int const number_added_constraints = total_num_cons - last_constraint_index_; + // Create new constraints + CHECK_STATUS(KN_add_cons(kc_, number_added_constraints, NULL)); + // Counts the number of non zero linear term in case of update Knitro model + int number_linear_terms = 0; + + // Add all constraints as a block + std::unique_ptr con_indexes(new int[total_num_vars * number_added_constraints]); + std::unique_ptr var_indexes(new int[total_num_vars * number_added_constraints]); + std::unique_ptr var_coefficients(new double[total_num_vars * number_added_constraints]); + + std::unique_ptr idx_cons(new int[number_added_constraints]); + std::unique_ptr lb(new double[number_added_constraints]); + std::unique_ptr ub(new double[number_added_constraints]); + + for (int con_index = last_constraint_index_; con_index < total_num_cons; ++con_index) { + MPConstraint* const ct = solver_->constraints_[con_index]; + DCHECK(!constraint_is_extracted(con_index)); + set_constraint_as_extracted(con_index, true); + + // Name the constraint + CHECK_STATUS(KN_set_con_name(kc_, con_index, (char*)ct->name().c_str())); + + const auto& coeffs = ct->coefficients_; + for (auto coeff : coeffs) { + con_indexes[number_linear_terms] = con_index; + var_indexes[number_linear_terms] = coeff.first->index(); + var_coefficients[number_linear_terms] = coeff.second; + ++number_linear_terms;; + } + + idx_cons[con_index - last_constraint_index_] = con_index; + lb[con_index - last_constraint_index_] = redefine_infinity_double(ct->lb()); + ub[con_index - last_constraint_index_] = redefine_infinity_double(ct->ub()); + } + + CHECK_STATUS(KN_set_con_lobnds(kc_, number_added_constraints, idx_cons.get(), lb.get())); + CHECK_STATUS(KN_set_con_upbnds(kc_, number_added_constraints, idx_cons.get(), ub.get())); + + if (number_linear_terms) { + CHECK_STATUS(KN_add_con_linear_struct(kc_, number_linear_terms, + con_indexes.get(), var_indexes.get(), var_coefficients.get())); + } + + // if a new linear term is added, the Knitro model must be updated + if (number_linear_terms) CHECK_STATUS(KN_update(kc_)); + } +} + +void KnitroInterface::ExtractObjective() { + int const len = solver_->variables_.size(); + + if (len) { + std::unique_ptr ind(new int[len]); + std::unique_ptr val(new double[len]); + for (int j = 0; j < len; ++j) { + ind[j] = j; + val[j] = 0.0; + } + + const auto& coeffs = solver_->objective_->coefficients_; + for (auto coeff : coeffs) { + int const idx = coeff.first->index(); + if (variable_is_extracted(idx)) { + DCHECK_LT(idx, len); + ind[idx] = idx; + val[idx] = coeff.second; + } + } + // if a init solve occured, remove prev coef to add the new ones + if (!no_obj_) { + CHECK_STATUS(KN_chg_obj_linear_struct(kc_, len, ind.get(), val.get())); + CHECK_STATUS(KN_chg_obj_constant(kc_, solver_->Objective().offset())); + } else { + CHECK_STATUS(KN_add_obj_linear_struct(kc_, len, ind.get(), val.get())); + CHECK_STATUS(KN_add_obj_constant(kc_, solver_->Objective().offset())); + } + + CHECK_STATUS(KN_update(kc_)); + no_obj_ = false; + } + + // Extra check on the optimization direction + SetOptimizationDirection(maximize_); +} + +// ------ Parameters ----- + +void KnitroInterface::SetParameters(const MPSolverParameters& param) { + SetCommonParameters(param); + SetScalingMode(param.GetIntegerParam(MPSolverParameters::SCALING)); + if (mip_) SetMIPParameters(param); +} + +// Save the existing locale, use the "C" locale to ensure that +// string -> double conversion is done ignoring the locale. +struct ScopedLocale { + ScopedLocale() { + oldLocale = std::setlocale(LC_NUMERIC, nullptr); + auto newLocale = std::setlocale(LC_NUMERIC, "C"); + CHECK_EQ(std::string(newLocale), "C"); + } + ~ScopedLocale() { std::setlocale(LC_NUMERIC, oldLocale); } + + private: + const char* oldLocale; +}; + +bool KnitroInterface::SetSolverSpecificParametersAsString( + const std::string& parameters) { + if (parameters.empty()) { + return true; + } + + std::vector > paramAndValuePairList; + + std::stringstream ss(parameters); + std::string paramName; + while (std::getline(ss, paramName, ' ')) { + std::string paramValue; + if (std::getline(ss, paramValue, ' ')) { + paramAndValuePairList.push_back(std::make_pair(paramName, paramValue)); + } else { + LOG(ERROR) << "No value for parameter " << paramName << " : function " + << __FUNCTION__ << std::endl; + return false; + } + } + + ScopedLocale locale; + for (auto& paramAndValuePair : paramAndValuePairList) { + auto matchingParamIter = param_map_.find(paramAndValuePair.first); + if (matchingParamIter != param_map_.end()) { + int param_id = param_map_[paramAndValuePair.first], param_type = 0; + KN_get_param_type(kc_, param_id, ¶m_type); + switch (param_type) { + case KN_PARAMTYPE_INTEGER: + KN_set_int_param(kc_, param_id, std::stoi(paramAndValuePair.second)); + break; + case KN_PARAMTYPE_FLOAT: + KN_set_double_param(kc_, param_id, + std::stod(paramAndValuePair.second)); + break; + case KN_PARAMTYPE_STRING: + KN_set_char_param(kc_, param_id, paramAndValuePair.second.c_str()); + break; + } + continue; + } + LOG(ERROR) << "Unknown parameter " << paramName << " : function " + << __FUNCTION__ << std::endl; + return false; + } + return true; +} + +void KnitroInterface::SetRelativeMipGap(double value) { + /** + * This method should be called by SetMIPParameters() only + * so there is no mip_ check here + */ + CHECK_STATUS(KN_set_double_param(kc_, KN_PARAM_MIP_OPTGAPREL, value)); +} + +void KnitroInterface::SetPrimalTolerance(double value) { + CHECK_STATUS(KN_set_double_param(kc_, KN_PARAM_FEASTOL, value)); +} + +void KnitroInterface::SetDualTolerance(double value) { + CHECK_STATUS(KN_set_double_param(kc_, KN_PARAM_OPTTOL, value)); +} + +void KnitroInterface::SetPresolveMode(int value) { + auto const presolve = static_cast(value); + + switch (presolve) { + case MPSolverParameters::PRESOLVE_OFF: + CHECK_STATUS(KN_set_int_param(kc_, KN_PARAM_PRESOLVE, KN_PRESOLVE_NO)); + return; + case MPSolverParameters::PRESOLVE_ON: + CHECK_STATUS(KN_set_int_param(kc_, KN_PARAM_PRESOLVE, KN_PRESOLVE_YES)); + return; + default: + SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, value); + return; + } +} + +void KnitroInterface::SetScalingMode(int value) { + auto const scaling = static_cast(value); + + switch (scaling) { + case MPSolverParameters::SCALING_OFF: + CHECK_STATUS(KN_set_int_param(kc_, KN_PARAM_LINSOLVER_SCALING, + KN_LINSOLVER_SCALING_NONE)); + break; + case MPSolverParameters::SCALING_ON: + CHECK_STATUS(KN_set_int_param(kc_, KN_PARAM_LINSOLVER_SCALING, + KN_LINSOLVER_SCALING_ALWAYS)); + break; + } +} + +void KnitroInterface::SetLpAlgorithm(int value) { + auto const algorithm = + static_cast(value); + switch (algorithm) { + case MPSolverParameters::PRIMAL: + CHECK_STATUS( + KN_set_int_param(kc_, KN_PARAM_ACT_LPALG, KN_ACT_LPALG_PRIMAL)); + break; + case MPSolverParameters::DUAL: + CHECK_STATUS( + KN_set_int_param(kc_, KN_PARAM_ACT_LPALG, KN_ACT_LPALG_DUAL)); + break; + case MPSolverParameters::BARRIER: + CHECK_STATUS( + KN_set_int_param(kc_, KN_PARAM_ACT_LPALG, KN_ACT_LPALG_BARRIER)); + break; + default: + CHECK_STATUS( + KN_set_int_param(kc_, KN_PARAM_ACT_LPALG, KN_ACT_LPALG_DEFAULT)); + break; + } +} + +void KnitroInterface::SetCallback(MPCallback* mp_callback) { + callback_ = mp_callback; +} + +absl::Status KnitroInterface::SetNumThreads(int num_threads) { + CHECK_STATUS(KN_set_int_param(kc_, KN_PARAM_NUMTHREADS, num_threads)); + return absl::OkStatus(); +} + +// ------ Solve ----- + +MPSolver::ResultStatus KnitroInterface::Solve(MPSolverParameters const& param) { + WallTimer timer; + timer.Start(); + + if (param.GetIntegerParam(MPSolverParameters::INCREMENTALITY) == + MPSolverParameters::INCREMENTALITY_OFF) { + Reset(); + } + + ExtractModel(); + VLOG(1) << absl::StrFormat("Model build in %.3f seconds.", timer.Get()); + + if (quiet_) { + // Silent the screen output + CHECK_STATUS(KN_set_int_param(kc_, KN_PARAM_OUTLEV, KN_OUTLEV_NONE)); + } + + // Set parameters. + SetParameters(param); + solver_->SetSolverSpecificParametersAsString( + solver_->solver_specific_parameter_string_); + if (solver_->time_limit()) { + VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms."; + CHECK_STATUS(KN_set_double_param(kc_, KN_PARAM_MAXTIMECPU, + solver_->time_limit_in_secs())); + } + + // Set the hint (if any) + this->AddSolutionHintToOptimizer(); + + if (callback_ != nullptr) { + if (callback_->might_add_lazy_constraints()) { + MPCallBackWithEvent cbe; + cbe.callback = callback_; + cbe.event = MPCallbackEvent::kMipSolution; + CHECK_STATUS(KN_set_mip_lazyconstraints_callback( + kc_, CallBackFn, static_cast(&cbe))); + } + if (callback_->might_add_cuts()) { + MPCallBackWithEvent cbe; + cbe.callback = callback_; + cbe.event = MPCallbackEvent::kMipNode; + CHECK_STATUS(KN_set_mip_usercuts_callback(kc_, CallBackFn, + static_cast(&cbe))); + } + } + + // Special case for empty model (no var) + // Infeasible Constraint should have been checked + // by MPSolver upstream + if (!solver_->NumVariables()) { + objective_value_ = solver_->Objective().offset(); + if (mip_) best_objective_bound_ = 0; + result_status_ = MPSolver::OPTIMAL; + sync_status_ = SOLUTION_SYNCHRONIZED; + return result_status_; + } + + // Solve. + timer.Restart(); + int status; + status = -KN_solve(kc_); + + if (status == 0) { + // the final solution is optimal to specified tolerances; + result_status_ = MPSolver::OPTIMAL; + + } else if ((status < 110 && 100 <= status) || + (status < 410 && 400 <= status)) { + // a feasible solution was found (but not verified optimal) + // OR + // a feasible point was found before reaching the limit + result_status_ = MPSolver::FEASIBLE; + + } else if ((status < 210 && 200 <= status) || + (status < 420 && 410 <= status)) { + // Knitro terminated at an infeasible point; + // OR + // no feasible point was found before reaching the limit + result_status_ = MPSolver::INFEASIBLE; + + } else if (status < 302 && 300 <= status) { + // the problem was determined to be unbounded; + result_status_ = MPSolver::UNBOUNDED; + + } else { + // Knitro terminated with an input error or some non-standard error or else. + result_status_ = MPSolver::ABNORMAL; + } + + if (result_status_ == MPSolver::OPTIMAL || + result_status_ == MPSolver::FEASIBLE) { + // If optimal or feasible solution is found. + SetSolution(); + } else { + VLOG(1) << "No feasible solution found."; + } + + sync_status_ = SOLUTION_SYNCHRONIZED; + + return result_status_; +} + +void KnitroInterface::SetSolution() { + int status; + int const nb_vars = solver_->variables_.size(); + int const nb_cons = solver_->constraints_.size(); + if (nb_vars) { + std::unique_ptr values(new double[nb_vars]); + std::unique_ptr reduced_costs(new double[nb_vars]); + CHECK_STATUS( + KN_get_solution(kc_, &status, &objective_value_, values.get(), NULL)); + CHECK_STATUS(KN_get_var_dual_values_all(kc_, reduced_costs.get())); + for (int j = 0; j < nb_vars; ++j) { + MPVariable* var = solver_->variables_[j]; + var->set_solution_value(values[j]); + if (!mip_) var->set_reduced_cost(-reduced_costs[j]); + } + } + if (nb_cons) { + std::unique_ptr duals_cons(new double[nb_cons]); + CHECK_STATUS(KN_get_con_dual_values_all(kc_, duals_cons.get())); + if (!mip_) { + for (int j = 0; j < nb_cons; ++j) { + MPConstraint* ct = solver_->constraints_[j]; + ct->set_dual_value(-duals_cons[j]); + } + } + } + if (mip_) { + double rel_gap; + CHECK_STATUS(KN_get_mip_rel_gap(kc_, &rel_gap)); + best_objective_bound_ = objective_value_ + rel_gap; + } +} + +void KnitroInterface::AddSolutionHintToOptimizer() { + const std::size_t len = solver_->solution_hint_.size(); + if (len == 0) { + // hint is empty, nothing to do + return; + } + std::unique_ptr col_ind(new int[len]); + std::unique_ptr val(new double[len]); + + for (std::size_t i = 0; i < len; ++i) { + col_ind[i] = solver_->solution_hint_[i].first->index(); + val[i] = solver_->solution_hint_[i].second; + } + CHECK_STATUS( + KN_set_var_primal_init_values(kc_, len, col_ind.get(), val.get())); +} + +// ------ Query statistics on the solution and the solve ------ + +int64_t KnitroInterface::iterations() const { + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfIterations; + int numIters; + CHECK_STATUS(KN_get_number_iters(kc_, &numIters)); + return static_cast(numIters); +} + +int64_t KnitroInterface::nodes() const { + if (mip_) { + if (!CheckSolutionIsSynchronized()) return kUnknownNumberOfNodes; + int numNodes; + CHECK_STATUS(KN_get_mip_number_nodes(kc_, &numNodes)); + return static_cast(numNodes); + } else { + LOG(DFATAL) << "Number of nodes only available for discrete problems"; + return kUnknownNumberOfNodes; + } +} + +// ----- Misc ----- + +std::string KnitroInterface::SolverVersion() const { + int const length = 15; // should contain the string termination character, + char release[length + 1]; // checked but there is trouble if not allocated + // with an additional char + + CHECK_STATUS(KN_get_release(length, release)); + + return absl::StrFormat("Knitro library version %s", release); +} + +MPSolverInterface* BuildKnitroInterface(bool mip, MPSolver* const solver) { + return new KnitroInterface(solver, mip); +} + +} // namespace operations_research \ No newline at end of file diff --git a/ortools/linear_solver/knitro_interface_parallel_test.cc b/ortools/linear_solver/knitro_interface_parallel_test.cc new file mode 100644 index 00000000000..1857fb7c309 --- /dev/null +++ b/ortools/linear_solver/knitro_interface_parallel_test.cc @@ -0,0 +1,287 @@ +// ADD HEADER +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "ortools/base/init_google.h" +#include "ortools/knitro/environment.h" +#include "ortools/linear_solver/linear_solver.h" + +namespace operations_research { + +#define ERROR_RATE 1e-6 + +#define EXPECT_STATUS(s) \ + do { \ + int const status_ = s; \ + EXPECT_EQ(0, status_) << "Nonzero return status"; \ + } while (0) + +inline bool file_exists(const std::string& name) { + if (FILE* file = fopen(name.c_str(), "r")) { + fclose(file); + return true; + } else { + return false; + } +} + +class KnitroGetter { + public: + KnitroGetter(MPSolver* solver) : solver_(solver) {} + + // Var getters + void Num_Var(int* NV) { EXPECT_STATUS(KN_get_number_vars(kc(), NV)); } + + void Var_Lb(MPVariable* x, double* lb) { + CHECK(solver_->OwnsVariable(x)); + EXPECT_STATUS(KN_get_var_lobnd(kc(), x->index(), lb)); + } + + void Var_Ub(MPVariable* x, double* ub) { + CHECK(solver_->OwnsVariable(x)); + EXPECT_STATUS(KN_get_var_upbnd(kc(), x->index(), ub)); + } + + void Var_Name(MPVariable* x, char* name, int buffersize) { + CHECK(solver_->OwnsVariable(x)); + EXPECT_STATUS(KN_get_var_name(kc(), x->index(), buffersize, name)); + } + + // Cons getters + void Num_Cons(int* NC) { EXPECT_STATUS(KN_get_number_cons(kc(), NC)); } + + void Con_Lb(MPConstraint* ct, double* lb) { + EXPECT_STATUS(KN_get_con_lobnd(kc(), ct->index(), lb)); + } + + void Con_Ub(MPConstraint* ct, double* ub) { + EXPECT_STATUS(KN_get_con_upbnd(kc(), ct->index(), ub)); + } + + void Con_Name(MPConstraint* ct, char* name, int buffersize) { + EXPECT_STATUS(KN_get_con_name(kc(), ct->index(), buffersize, name)); + } + + void Con_nnz(MPConstraint* ct, int* nnz) { + EXPECT_STATUS(KN_get_jacobian_nnz_one(kc(), ct->index(), nnz)); + } + + void Con_coef(MPConstraint* ct, int* idx_vars, double* coef) { + EXPECT_STATUS( + KN_get_jacobian_values_one(kc(), ct->index(), idx_vars, coef)); + } + + void Con_tot_nnz(KNLONG* nnz) { + EXPECT_STATUS(KN_get_jacobian_nnz(kc(), nnz)); + } + + void Con_all_coef(int* idx_cons, int* idx_vars, double* coefs) { + EXPECT_STATUS(KN_get_jacobian_values(kc(), idx_cons, idx_vars, coefs)); + } + + // Obj getters + void Obj_nb_coef(int* nnz) { EXPECT_STATUS(KN_get_objgrad_nnz(kc(), nnz)); } + + void Obj_all_coef(int* idx_vars, double* coefs) { + EXPECT_STATUS(KN_get_objgrad_values(kc(), idx_vars, coefs)); + } + + // Param getters + void Int_Param(int param_id, int* value) { + EXPECT_STATUS(KN_get_int_param(kc(), param_id, value)); + } + + void Double_Param(int param_id, double* value) { + EXPECT_STATUS(KN_get_double_param(kc(), param_id, value)); + } + + private: + MPSolver* solver_; + KN_context_ptr kc() { return (KN_context_ptr)solver_->underlying_solver(); } +}; + +#define MOCK_MIP() \ + MPSolver solver("KNITRO_MIP", MPSolver::KNITRO_MIXED_INTEGER_PROGRAMMING); \ + KnitroGetter getter(&solver) +#define MOCK_LP() \ + MPSolver solver("KNITRO_LP", MPSolver::KNITRO_LINEAR_PROGRAMMING); \ + KnitroGetter getter(&solver) + +inline void set_problem(MPSolver& solver, bool mip) { + double infinity = solver.infinity(); + MPVariable* const x = + (mip) ? solver.MakeIntVar(0, 7, "x") : solver.MakeNumVar(0, 7, "x"); + MPVariable* const y = + (mip) ? solver.MakeIntVar(0, 6, "y") : solver.MakeNumVar(0, 6, "y"); + MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 9, "c1"); + c1->SetCoefficient(x, 1); + c1->SetCoefficient(y, 1); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 18, "c2"); + c2->SetCoefficient(x, 3); + c2->SetCoefficient(y, 1); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 3); + obj->SetCoefficient(y, 2); + obj->SetMaximization(); +} + +#define CHECK_MIP() \ + EXPECT_EQ(solver.variable(0)->solution_value(), 4); \ + EXPECT_EQ(solver.variable(1)->solution_value(), 5); \ + EXPECT_EQ(solver.MutableObjective()->Value(), 22); + + +#define CHECK_LP() \ + EXPECT_NEAR(solver.variable(0)->solution_value(), 4.5, ERROR_RATE); \ + EXPECT_NEAR(solver.variable(1)->solution_value(), 4.5, ERROR_RATE); \ + EXPECT_NEAR(solver.MutableObjective()->Value(), 22.5, ERROR_RATE); + + +// -------------------- Parallel Misc Test -------------------- + +/** Unit Test of the method SetNumThreads()*/ +TEST(KnitroInterface, SetNumThreads) { + MOCK_MIP(); + set_problem(solver, true); + auto status = solver.SetNumThreads(4); + solver.Solve(); + CHECK_MIP(); + int value; + getter.Int_Param(KN_PARAM_NUMTHREADS, &value); + EXPECT_EQ(value, 4); +} + +/** Unit Test to check the Parallel BLAS*/ +TEST(KnitroInterface, PBLAS) { + MOCK_MIP(); + set_problem(solver, true); + solver.SetSolverSpecificParametersAsString("KN_PARAM_BLASOPTION 1 KN_PARAM_BLAS_NUMTHREADS 4"); + solver.Solve(); + CHECK_MIP(); + int value; + getter.Int_Param(KN_PARAM_BLASOPTION, &value); + EXPECT_EQ(value, 1); + getter.Int_Param(KN_PARAM_BLAS_NUMTHREADS, &value); + EXPECT_EQ(value, 4); +} + +// TODO : KN_PARAM_CONCURRENT_EVALS -> Callback +// TODO : KN_PARAM_CONIC_NUMTHREADS (not used) +// TODO : KN_PARAM_FINDIFF_NUMTHREADS (not used?) + +/** Unit Test to modify linsolver_numthreads*/ +TEST(KnitroInterface, linsolver_numthreads) { + MOCK_MIP(); + set_problem(solver, true); + solver.SetSolverSpecificParametersAsString("KN_PARAM_LINSOLVER 6 KN_PARAM_LINSOLVER_NUMTHREADS 4"); + solver.Solve(); + CHECK_MIP(); + int value; + getter.Int_Param(KN_PARAM_LINSOLVER, &value); + EXPECT_EQ(value, 6); + getter.Int_Param(KN_PARAM_LINSOLVER_NUMTHREADS, &value); + EXPECT_EQ(value, 4); +} + +/** Unit Test to modify mip_numthreads*/ +TEST(KnitroInterface, mip_numthreads) { + MOCK_MIP(); + set_problem(solver, true); + solver.SetSolverSpecificParametersAsString("KN_PARAM_MIP_METHOD 1 KN_PARAM_MIP_NUMTHREADS 4"); + solver.Solve(); + CHECK_MIP(); + int value; + getter.Int_Param(KN_PARAM_MIP_METHOD, &value); + EXPECT_EQ(value, 1); + getter.Int_Param(KN_PARAM_MIP_NUMTHREADS, &value); + EXPECT_EQ(value, 4); +} + +// -------------------- Multi-start -------------------- + +/** + * Functionnal Test for multi-start + * Just test some of the different parameters + * of multi-start option in Knitro + */ +TEST(KnitroInterface, multistart) { + MOCK_LP(); + double infinity = solver.infinity(); + MPVariable* const x = solver.MakeNumVar(0, 7, "x"); + MPVariable* const y = solver.MakeNumVar(0, 6, "y"); + MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 9, "c1"); + c1->SetCoefficient(x, 1); + c1->SetCoefficient(y, 1); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 18, "c2"); + c2->SetCoefficient(x, 3); + c2->SetCoefficient(y, 1); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 3); + obj->SetCoefficient(y, 1); + obj->SetMaximization(); + solver.SetSolverSpecificParametersAsString("KN_PARAM_OUTLEV 1 KN_PARAM_MS_ENABLE 1 KN_PARAM_MS_MAXSOLVES 16 KN_PARAM_MS_NUMTOSAVE 20 KN_PARAM_MS_MAXTIMECPU 1e6 KN_PARAM_MS_MAXTIMEREAL 1e6 KN_PARAM_MS_SAVETOL 1e-9 KN_PARAM_MS_NUMTHREADS 4"); + solver.Solve(); + EXPECT_NEAR(obj->Value(), 18, ERROR_RATE); + int value; + getter.Int_Param(KN_PARAM_MS_ENABLE, &value); + EXPECT_EQ(value, 1); + getter.Int_Param(KN_PARAM_MS_MAXSOLVES, &value); + EXPECT_EQ(value, 16); + getter.Int_Param(KN_PARAM_MS_NUMTOSAVE, &value); + EXPECT_EQ(value, 20); + getter.Int_Param(KN_PARAM_MS_NUMTHREADS, &value); + EXPECT_EQ(value, 4); + double value2; + getter.Double_Param(KN_PARAM_MS_MAXTIMEREAL, &value2); + EXPECT_EQ(value2, 1e6); + getter.Double_Param(KN_PARAM_MS_MAXTIMECPU, &value2); + EXPECT_EQ(value2, 1e6); + getter.Double_Param(KN_PARAM_MS_SAVETOL, &value2); + EXPECT_EQ(value2, 1e-9); +} + +// -------------------- Tuner -------------------- + +/** + * Functionnal Test for Knitro-tuner + * Just test some of the different parameters + * of tuner option in Knitro + */ +TEST(KnitroInterface, KnitroTuner) { + MOCK_LP(); + set_problem(solver, false); + std::ofstream tuner_file; + tuner_file.open("knitro_interface_tuner_settings.opt"); + tuner_file << "KN_PARAM_ALG\n"; + tuner_file << "KN_PARAM_FEASTOL 1e-8 1e-10`\n"; + tuner_file.close(); + + solver.SetSolverSpecificParametersAsString("KN_PARAM_OUTLEV 1 KN_PARAM_TUNER 1 KN_PARAM_TUNER_OPTIONSFILE knitro_interface_tuner_settings.opt KN_PARAM_TUNER_OUTSUB 1"); + solver.Solve(); + CHECK_LP(); + remove("knitro_interface_tuner_settings.opt"); +} + +} // namespace operations_research + +int main(int argc, char** argv) { + absl::SetFlag(&FLAGS_stderrthreshold, 1); + testing::InitGoogleTest(&argc, argv); + if (!operations_research::KnitroIsCorrectlyInstalled()) { + LOG(ERROR) << "Knitro solver is not available"; + return EXIT_SUCCESS; + } else { + if (!RUN_ALL_TESTS()) { + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } +} diff --git a/ortools/linear_solver/knitro_interface_test.cc b/ortools/linear_solver/knitro_interface_test.cc new file mode 100644 index 00000000000..cdff1682f3e --- /dev/null +++ b/ortools/linear_solver/knitro_interface_test.cc @@ -0,0 +1,1923 @@ +// ADD HEADER +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "ortools/base/init_google.h" +#include "ortools/knitro/environment.h" +#include "ortools/linear_solver/linear_solver.h" + +namespace operations_research { + +#define ERROR_RATE 1e-6 + +#define EXPECT_STATUS(s) \ + do { \ + int const status_ = s; \ + EXPECT_EQ(0, status_) << "Nonzero return status"; \ + } while (0) + +inline bool file_exists(const std::string& name) { + if (FILE* file = fopen(name.c_str(), "r")) { + fclose(file); + return true; + } else { + return false; + } +} + +class KnitroGetter { + public: + KnitroGetter(MPSolver* solver) : solver_(solver) {} + + // Var getters + void Num_Var(int* NV) { EXPECT_STATUS(KN_get_number_vars(kc(), NV)); } + + void Var_Lb(MPVariable* x, double* lb) { + CHECK(solver_->OwnsVariable(x)); + EXPECT_STATUS(KN_get_var_lobnd(kc(), x->index(), lb)); + } + + void Var_Ub(MPVariable* x, double* ub) { + CHECK(solver_->OwnsVariable(x)); + EXPECT_STATUS(KN_get_var_upbnd(kc(), x->index(), ub)); + } + + void Var_Name(MPVariable* x, char* name, int buffersize) { + CHECK(solver_->OwnsVariable(x)); + EXPECT_STATUS(KN_get_var_name(kc(), x->index(), buffersize, name)); + } + + void Var_Type(MPVariable* x, int* type) { + CHECK(solver_->OwnsVariable(x)); + EXPECT_STATUS(KN_get_var_type(kc(), x->index(), type)); + } + + // Cons getters + void Num_Cons(int* NC) { EXPECT_STATUS(KN_get_number_cons(kc(), NC)); } + + void Con_Lb(MPConstraint* ct, double* lb) { + EXPECT_STATUS(KN_get_con_lobnd(kc(), ct->index(), lb)); + } + + void Con_Ub(MPConstraint* ct, double* ub) { + EXPECT_STATUS(KN_get_con_upbnd(kc(), ct->index(), ub)); + } + + void Con_Name(MPConstraint* ct, char* name, int buffersize) { + EXPECT_STATUS(KN_get_con_name(kc(), ct->index(), buffersize, name)); + } + + void Con_nnz(MPConstraint* ct, int* nnz) { + EXPECT_STATUS(KN_get_jacobian_nnz_one(kc(), ct->index(), nnz)); + } + + void Con_coef(MPConstraint* ct, int* idx_vars, double* coef) { + EXPECT_STATUS( + KN_get_jacobian_values_one(kc(), ct->index(), idx_vars, coef)); + } + + void Con_tot_nnz(KNLONG* nnz) { + EXPECT_STATUS(KN_get_jacobian_nnz(kc(), nnz)); + } + + void Con_all_coef(int* idx_cons, int* idx_vars, double* coefs) { + EXPECT_STATUS(KN_get_jacobian_values(kc(), idx_cons, idx_vars, coefs)); + } + + // Obj getters + void Obj_nb_coef(int* nnz) { EXPECT_STATUS(KN_get_objgrad_nnz(kc(), nnz)); } + + void Obj_all_coef(int* idx_vars, double* coefs) { + EXPECT_STATUS(KN_get_objgrad_values(kc(), idx_vars, coefs)); + } + + // Param getters + void Int_Param(int param_id, int* value) { + EXPECT_STATUS(KN_get_int_param(kc(), param_id, value)); + } + + void Double_Param(int param_id, double* value) { + EXPECT_STATUS(KN_get_double_param(kc(), param_id, value)); + } + + private: + MPSolver* solver_; + KN_context_ptr kc() { return (KN_context_ptr)solver_->underlying_solver(); } +}; + +#define UNITTEST_INIT_MIP() \ + MPSolver solver("KNITRO_MIP", MPSolver::KNITRO_MIXED_INTEGER_PROGRAMMING); \ + KnitroGetter getter(&solver) +#define UNITTEST_INIT_LP() \ + MPSolver solver("KNITRO_LP", MPSolver::KNITRO_LINEAR_PROGRAMMING); \ + KnitroGetter getter(&solver) + +/*-------------------- TU --------------------*/ + +// ----- Empty model + +/** Unit Test to solve an empty LP */ +TEST(KnitroInterface, SolveEmptyLP) { + UNITTEST_INIT_LP(); + solver.Solve(); + EXPECT_EQ(solver.MutableObjective()->Value(), 0); +} + +/** Unit Test to solve an empty MIP */ +TEST(KnitroInterface, SolveEmptyMIP) { + UNITTEST_INIT_MIP(); + solver.Solve(); + EXPECT_EQ(solver.MutableObjective()->Value(), 0); +} + +/** Unit Test to write an empty MIP */ +TEST(KnitroInterface, WriteEmptyProblem) { + UNITTEST_INIT_MIP(); + solver.Write("knitro_interface_test_empty"); + // check the file exists + EXPECT_TRUE(file_exists("knitro_interface_test_empty")); +} + +// ----- Modeling functions + +/** Unit Test of the method infinity()*/ +TEST(KnitroInterface, GetKnitroInfinityValue) { + UNITTEST_INIT_LP(); + EXPECT_EQ(solver.solver_infinity(), KN_INFINITY); +} + +/** Unit Test of the method AddVariable()*/ +TEST(KnitroInterface, AddVariableIntoProblem) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 10, "x"); + solver.Solve(); + double lb, ub; + char name[20]; + getter.Var_Lb(x, &lb); + getter.Var_Ub(x, &ub); + getter.Var_Name(x, name, 20); + EXPECT_EQ(lb, 0); + EXPECT_EQ(ub, 10); + EXPECT_STREQ(name, "x"); +} + +/** Unit Test of the method AddRowConstraint()*/ +TEST(KnitroInterface, AddRowConstraintIntoProblem) { + UNITTEST_INIT_LP(); + MPConstraint* const ct = solver.MakeRowConstraint(0, 10, "ct"); + solver.Solve(); + double lb, ub; + char name[20]; + getter.Con_Lb(ct, &lb); + getter.Con_Ub(ct, &ub); + getter.Con_Name(ct, name, 20); + EXPECT_EQ(lb, 0); + EXPECT_EQ(ub, 10); + EXPECT_STREQ(name, "ct"); +} + +/** Unit Test of the method SetCoefficient()*/ +TEST(KnitroInterface, SetCoefficientInConstraint) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 10, "x"); + MPConstraint* const ct = solver.MakeRowConstraint(0, 10, "ct"); + ct->SetCoefficient(x, 2); + solver.Solve(); + int idx_con, idx_var; + double coef; + getter.Con_all_coef(&idx_con, &idx_var, &coef); + EXPECT_EQ(x->index(), idx_var); + EXPECT_EQ(ct->index(), idx_con); + EXPECT_EQ(coef, 2); + ct->SetCoefficient(x, 1); + getter.Con_all_coef(&idx_con, &idx_var, &coef); + EXPECT_EQ(x->index(), idx_var); + EXPECT_EQ(ct->index(), idx_con); + EXPECT_EQ(coef, 1); +} + +/** Unit Test to check variable type in Knitro model*/ +TEST(KnitroInterface, CheckVarType) { + UNITTEST_INIT_MIP(); + MPVariable* const x = solver.MakeNumVar(0, 10, "x"); + MPVariable* const y = solver.MakeIntVar(0, 10, "y"); + MPVariable* const z = solver.MakeBoolVar("z"); + solver.Solve(); + int value; + getter.Var_Type(x, &value); + EXPECT_EQ(value, KN_VARTYPE_CONTINUOUS); + getter.Var_Type(y, &value); + EXPECT_EQ(value, KN_VARTYPE_INTEGER); + getter.Var_Type(z, &value); + EXPECT_EQ(value, KN_VARTYPE_BINARY); +} + +/** Unit Test to change variable type from continuous to integer*/ +TEST(KnitroInterface, ChangeVarTypeIntoInteger) { + UNITTEST_INIT_MIP(); + MPVariable* const x = solver.MakeNumVar(0, 10, "x"); + MPVariable* const y = solver.MakeIntVar(0, 10, "y"); + solver.Solve(); + int value; + getter.Var_Type(x, &value); + EXPECT_EQ(value, KN_VARTYPE_CONTINUOUS); + getter.Var_Type(y, &value); + EXPECT_EQ(value, KN_VARTYPE_INTEGER); + x->SetInteger(true); + y->SetInteger(false); + solver.Solve(); + getter.Var_Type(x, &value); + EXPECT_EQ(value, KN_VARTYPE_INTEGER); + getter.Var_Type(y, &value); + EXPECT_EQ(value, KN_VARTYPE_CONTINUOUS); +} + +/** Unit Test to change variable type from continuous to integer in LP*/ +TEST(KnitroInterface, ChangeVarTypeIntoIntegerInLP) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 10, "x"); + MPVariable* const y = solver.MakeNumVar(0, 10, "y"); + x->SetInteger(true); + solver.Solve(); + int value; + getter.Var_Type(x, &value); + EXPECT_EQ(value, KN_VARTYPE_CONTINUOUS); + getter.Var_Type(y, &value); + EXPECT_EQ(value, KN_VARTYPE_CONTINUOUS); + x->SetInteger(true); + y->SetInteger(true); + getter.Var_Type(x, &value); + EXPECT_EQ(value, KN_VARTYPE_CONTINUOUS); + getter.Var_Type(y, &value); + EXPECT_EQ(value, KN_VARTYPE_CONTINUOUS); + solver.Solve(); + getter.Var_Type(x, &value); + EXPECT_EQ(value, KN_VARTYPE_CONTINUOUS); + getter.Var_Type(y, &value); + EXPECT_EQ(value, KN_VARTYPE_CONTINUOUS); +} + +/** Unit Test of the method SetVariableBounds()*/ +TEST(KnitroInterface, ChangeVariableBounds) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 1, "x"); + x->SetBounds(-10, 10); + solver.Solve(); + double lb, ub; + getter.Var_Lb(x, &lb); + getter.Var_Ub(x, &ub); + EXPECT_EQ(lb, -10); + EXPECT_EQ(ub, 10); + x->SetBounds(-1, 1); + getter.Var_Lb(x, &lb); + getter.Var_Ub(x, &ub); + EXPECT_EQ(lb, -1); + EXPECT_EQ(ub, 1); +} + +/** Unit Test of the method ClearConstraint()*/ +TEST(KnitroInterface, ClearAConstraint) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 10, "x"); + MPConstraint* const ct = solver.MakeRowConstraint(0, 10, "ct"); + ct->SetCoefficient(x, 2); + KNLONG nnz; + getter.Con_tot_nnz(&nnz); + // The Constraint has not been extracted yet + EXPECT_EQ(nnz, 0); + solver.Solve(); + getter.Con_tot_nnz(&nnz); + EXPECT_EQ(nnz, 1); + ct->Clear(); + getter.Con_tot_nnz(&nnz); + EXPECT_EQ(nnz, 0); +} + +/** Unit Test of the method SetObjectiveCoefficient()*/ +TEST(KnitroInterface, AddObjectiveCoefficient) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 10, "x"); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + solver.Solve(); + int idx_var; + double coef; + getter.Obj_all_coef(&idx_var, &coef); + EXPECT_EQ(x->index(), idx_var); + EXPECT_EQ(coef, 1); +} + +/** Unit Test of the method SetOptimizationDirection()*/ +TEST(KnitroInterface, ChangeOptimizationDirection) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 1, "x"); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetMaximization(); + solver.Solve(); + EXPECT_EQ(obj->Value(), 1); + obj->SetMinimization(); + solver.Solve(); + EXPECT_EQ(obj->Value(), 0); +} + +/** Unit Test of the method SetObjectiveOffset()*/ +TEST(KnitroInterface, AddOffsetToObjective) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 10, "x"); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + solver.Solve(); + EXPECT_EQ(obj->Value(), 0); + obj->SetOffset(1); + solver.Solve(); + EXPECT_EQ(obj->Value(), 1); +} + +/** Unit Test of the method ClearObjective()*/ +TEST(KnitroInterface, ClearObjective) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 1, "x"); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + int nnz; + getter.Obj_nb_coef(&nnz); + // The objective coefficient has not been extracted yet + EXPECT_EQ(nnz, 0); + solver.Solve(); + getter.Obj_nb_coef(&nnz); + EXPECT_EQ(nnz, 1); + obj->Clear(); + getter.Obj_nb_coef(&nnz); + EXPECT_EQ(nnz, 0); +} + +/** Unit Test of the method Reset()*/ +TEST(KnitroInterface, ResetAProblem) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 1, "x"); + MPVariable* const y = solver.MakeNumVar(0, 1, "y"); + MPConstraint* const c1 = solver.MakeRowConstraint(0, 3, "c1"); + c1->SetCoefficient(x, .5); + c1->SetCoefficient(y, 1); + MPConstraint* const c2 = solver.MakeRowConstraint(0, 3, "c2"); + c2->SetCoefficient(x, 1); + c2->SetCoefficient(y, 1); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, -1); + + solver.Solve(); // to extract the model + int nb_vars, nb_cons, nnz; + getter.Num_Var(&nb_vars); + getter.Num_Cons(&nb_cons); + getter.Obj_nb_coef(&nnz); + EXPECT_EQ(nb_vars, 2); + EXPECT_EQ(nb_cons, 2); + EXPECT_EQ(nnz, 2); + + solver.Reset(); + getter.Num_Var(&nb_vars); + getter.Num_Cons(&nb_cons); + getter.Obj_nb_coef(&nnz); + EXPECT_EQ(nb_vars, 0); + EXPECT_EQ(nb_cons, 0); + EXPECT_EQ(nnz, 0); +} + +// ----- Test Param + +/** Unit Test of the method SetScaling()*/ +TEST(KnitroInterface, SetScalingParam) { + UNITTEST_INIT_MIP(); + MPSolverParameters params; + params.SetIntegerParam(MPSolverParameters::SCALING, + MPSolverParameters::SCALING_OFF); + solver.Solve(params); + int value; + getter.Int_Param(KN_PARAM_LINSOLVER_SCALING, &value); + EXPECT_EQ(value, KN_LINSOLVER_SCALING_NONE); + params.SetIntegerParam(MPSolverParameters::SCALING, + MPSolverParameters::SCALING_ON); + solver.Solve(params); + getter.Int_Param(KN_PARAM_LINSOLVER_SCALING, &value); + EXPECT_EQ(value, KN_LINSOLVER_SCALING_ALWAYS); +} + +/** Unit Test of the method SetRelativeMipGap()*/ +TEST(KnitroInterface, ChangeRelativeMipGapinMIP) { + UNITTEST_INIT_MIP(); + MPSolverParameters params; + params.SetDoubleParam(MPSolverParameters::RELATIVE_MIP_GAP, 0.5); + solver.Solve(params); + double value; + getter.Double_Param(KN_PARAM_MIP_OPTGAPREL, &value); + EXPECT_EQ(value, .5); + params.SetDoubleParam(MPSolverParameters::RELATIVE_MIP_GAP, 1e-8); + solver.Solve(params); + getter.Double_Param(KN_PARAM_MIP_OPTGAPREL, &value); + EXPECT_EQ(value, 1e-8); +} + +/** Unit Test of the method SetRelativeMipGap()*/ +TEST(KnitroInterface, ChangeRelativeMipGapinLP) { + UNITTEST_INIT_LP(); + MPSolverParameters params; + params.SetDoubleParam(MPSolverParameters::RELATIVE_MIP_GAP, 0.5); + solver.Solve(params); + double value; + getter.Double_Param(KN_PARAM_MIP_OPTGAPREL, &value); + EXPECT_EQ(value, 1e-4); +} + +/** Unit Test of the method SetPresolveMode()*/ +TEST(KnitroInterface, SetPresolveModeParam) { + UNITTEST_INIT_MIP(); + MPSolverParameters params; + // Try with invalid value + params.SetIntegerParam(MPSolverParameters::PRESOLVE, 2); + solver.Solve(params); + int value; + getter.Int_Param(KN_PARAM_PRESOLVE, &value); + // expect the default value + EXPECT_EQ(value, KN_PRESOLVE_YES); + // Try with presolve off + params.SetIntegerParam(MPSolverParameters::PRESOLVE, + MPSolverParameters::PRESOLVE_OFF); + solver.Solve(params); + getter.Int_Param(KN_PARAM_PRESOLVE, &value); + EXPECT_EQ(value, KN_PRESOLVE_NO); + // Try with presolve on + params.SetIntegerParam(MPSolverParameters::PRESOLVE, + MPSolverParameters::PRESOLVE_ON); + solver.Solve(params); + getter.Int_Param(KN_PARAM_PRESOLVE, &value); + EXPECT_EQ(value, KN_PRESOLVE_YES); +} + +/** Unit Test of the method AddSolutionHintToOptimizer()*/ +TEST(KnitroInterface, AddSolutionHintToOptimizer) { + UNITTEST_INIT_LP(); + double infinity = solver.infinity(); + MPVariable* const x = solver.MakeNumVar(0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0, infinity, "y"); + MPConstraint* const c1 = solver.MakeRowConstraint(0, 1, "c1"); + c1->SetCoefficient(x, 1); + c1->SetCoefficient(y, 1); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetMaximization(); + std::vector > hint; + hint.push_back(std::make_pair(x, 1.)); + hint.push_back(std::make_pair(y, 0.)); + solver.SetHint(hint); + solver.Solve(); + EXPECT_NEAR(obj->Value(), 1, ERROR_RATE); + EXPECT_NEAR(x->solution_value(), 1, ERROR_RATE); + EXPECT_NEAR(y->solution_value(), 0, ERROR_RATE); +} + +/** Unit Test of the method SetSolverSpecificParametersAsString()*/ +TEST(KnitroInterface, SetSolverSpecificParametersAsString) { + UNITTEST_INIT_MIP(); + EXPECT_TRUE(solver.SetSolverSpecificParametersAsString("")); + EXPECT_FALSE(solver.SetSolverSpecificParametersAsString("blabla 5 ")); + solver.SetSolverSpecificParametersAsString( + "KN_PARAM_FEASTOL 1e-8 KN_PARAM_LINSOLVER_SCALING 1 "); + solver.Solve(); + int value; + getter.Int_Param(KN_PARAM_LINSOLVER_SCALING, &value); + EXPECT_EQ(value, 1); + double value2; + getter.Double_Param(KN_PARAM_FEASTOL, &value2); + EXPECT_EQ(value2, 1e-8); +} + +/** Unit Test of the method SetLpAlgorithm()*/ +TEST(KnitroInterface, SetLpAlgorithm) { + UNITTEST_INIT_LP(); + MPSolverParameters params; + params.SetIntegerParam(MPSolverParameters::LP_ALGORITHM, + MPSolverParameters::PRIMAL); + solver.Solve(params); + int value; + getter.Int_Param(KN_PARAM_ACT_LPALG, &value); + EXPECT_EQ(value, KN_ACT_LPALG_PRIMAL); + params.SetIntegerParam(MPSolverParameters::LP_ALGORITHM, + MPSolverParameters::DUAL); + solver.Solve(params); + getter.Int_Param(KN_PARAM_ACT_LPALG, &value); + EXPECT_EQ(value, KN_ACT_LPALG_DUAL); + params.SetIntegerParam(MPSolverParameters::LP_ALGORITHM, + MPSolverParameters::BARRIER); + solver.Solve(params); + getter.Int_Param(KN_PARAM_ACT_LPALG, &value); + EXPECT_EQ(value, KN_ACT_LPALG_BARRIER); + params.SetIntegerParam(MPSolverParameters::LP_ALGORITHM, -1000); + solver.Solve(params); + getter.Int_Param(KN_PARAM_ACT_LPALG, &value); + EXPECT_EQ(value, KN_ACT_LPALG_DEFAULT); +} + +/** Unit Test of the method SetPrimalTolerance()*/ +TEST(KnitroInterface, SetPrimalToleranceParam) { + UNITTEST_INIT_LP(); + MPSolverParameters params; + params.SetDoubleParam(MPSolverParameters::PRIMAL_TOLERANCE, 0.5); + solver.Solve(params); + double value; + getter.Double_Param(KN_PARAM_FEASTOL, &value); + EXPECT_EQ(value, .5); + params.SetDoubleParam(MPSolverParameters::PRIMAL_TOLERANCE, 1e-8); + solver.Solve(params); + getter.Double_Param(KN_PARAM_FEASTOL, &value); + EXPECT_EQ(value, 1e-8); +} + +/** Unit Test of the method SetDualTolerance()*/ +TEST(KnitroInterface, SetDualToleranceParam) { + UNITTEST_INIT_LP(); + MPSolverParameters params; + params.SetDoubleParam(MPSolverParameters::DUAL_TOLERANCE, 0.5); + solver.Solve(params); + double value; + getter.Double_Param(KN_PARAM_OPTTOL, &value); + EXPECT_EQ(value, .5); + params.SetDoubleParam(MPSolverParameters::DUAL_TOLERANCE, 1e-8); + solver.Solve(params); + getter.Double_Param(KN_PARAM_OPTTOL, &value); + EXPECT_EQ(value, 1e-8); +} + +/** Unit Test of the method SetNumThreads()*/ +TEST(KnitroInterface, SetNumThreads) { + UNITTEST_INIT_MIP(); + auto status = solver.SetNumThreads(4); + solver.Solve(); + int value; + getter.Int_Param(KN_PARAM_NUMTHREADS, &value); + EXPECT_EQ(value, 4); +} + +/** Unit Test with time limit*/ +TEST(KnitroInterface, SetProblemTimeLimit) { + UNITTEST_INIT_LP(); + solver.set_time_limit(2024000); + solver.Solve(); + double value; + getter.Double_Param(KN_PARAM_MAXTIMECPU, &value); + EXPECT_EQ(value, 2024); +} + +/** + * Unit Test of the method BranchingPriorityChangedForVariable() + * for LP problem (should not work) + */ +TEST(KnitroInterface, BranchingPriorityChangedForVariableLP) { + UNITTEST_INIT_LP(); + MPVariable* const x = solver.MakeNumVar(0, 1, "x"); + x->SetBranchingPriority(10); + // The variable priority changed in the OR-Tools model but not in the Knitro + // model + EXPECT_EQ(x->branching_priority(), 10); +} + +/** Unit Test of the method underlying_solver()*/ +TEST(KnitroInterface, GetUnderlyingSolverPtr) { + UNITTEST_INIT_LP(); + auto ptr = solver.underlying_solver(); + EXPECT_NE(ptr, nullptr); +} + +// ----- Getting post-solve informations + +/** Unit Test of the method nodes() in MIP*/ +TEST(KnitroInterface, GetNbNodesInMIP) { + UNITTEST_INIT_MIP(); + EXPECT_EQ(solver.nodes(), MPSolverInterface::kUnknownNumberOfNodes); + solver.Solve(); + EXPECT_NE(solver.nodes(), MPSolverInterface::kUnknownNumberOfNodes); +} + +/** Unit Test of the method nodes() in LP*/ +TEST(KnitroInterface, GetNbNodesInLP) { + UNITTEST_INIT_LP(); + EXPECT_EQ(solver.nodes(), MPSolverInterface::kUnknownNumberOfNodes); + solver.Solve(); + EXPECT_EQ(solver.nodes(), MPSolverInterface::kUnknownNumberOfNodes); +} + +/** Unit Test of the method iterations()*/ +TEST(KnitroInterface, GetNbIter) { + UNITTEST_INIT_MIP(); + EXPECT_EQ(solver.iterations(), MPSolverInterface::kUnknownNumberOfIterations); + solver.Solve(); + EXPECT_NE(solver.iterations(), MPSolverInterface::kUnknownNumberOfIterations); +} + +/*-------------------- TF --------------------*/ + +/** + * Writes the following linear problem + * using KnitroInterface Write function + * max x + 2y + * st. 3x - 4y >= 10 + * 2x + 3y <= 18 + * x, y \in R+ + * + * Then loads it in a Knitro model and solves it + * + * TODO : For next version of Knitro : Add Ranges, + * Constants and different bounds for variables to + * be written in mps file + */ +TEST(KnitroInterface, WriteAndLoadModel) { + // Write model using OR-Tools + UNITTEST_INIT_LP(); + std::string version = solver.SolverVersion(); + version.resize(30); + EXPECT_STREQ(version.c_str(), "Knitro library version Knitro "); + const double infinity = solver.solver_infinity(); + + MPVariable* const x = solver.MakeNumVar(0.0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0.0, infinity, "y"); + + MPConstraint* const c1 = solver.MakeRowConstraint(10.0, infinity, "c1"); + c1->SetCoefficient(x, 3); + c1->SetCoefficient(y, -4); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 18.0, "c2"); + c2->SetCoefficient(x, 2); + c2->SetCoefficient(y, 3); + + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, 2); + obj->SetMaximization(); + + solver.Write("knitro_interface_test_LP_model"); + EXPECT_TRUE(file_exists("knitro_interface_test_LP_model")); + + // Check variable x + double lb, ub; + char name[20]; + getter.Var_Lb(x, &lb); + getter.Var_Ub(x, &ub); + getter.Var_Name(x, name, 20); + EXPECT_EQ(lb, 0.0); + EXPECT_EQ(ub, infinity); + EXPECT_STREQ(name, "x"); + + // Check constraint c1 + getter.Con_Lb(c1, &lb); + getter.Con_Ub(c1, &ub); + getter.Con_Name(c1, name, 20); + EXPECT_EQ(lb, 10.0); + EXPECT_EQ(ub, infinity); + EXPECT_STREQ(name, "c1"); + + // Load directly from Knitro model + KN_context* kc; + KN_new(&kc); + KN_load_mps_file(kc, "knitro_interface_test_LP_model"); + KN_set_int_param(kc, KN_PARAM_OUTLEV, KN_OUTLEV_NONE); + // Check variables + double kc_lb[2], kc_ub[2]; + KN_get_var_lobnds_all(kc, kc_lb); + KN_get_var_upbnds_all(kc, kc_ub); + EXPECT_EQ(kc_lb[0], 0); + EXPECT_EQ(kc_lb[1], 0); + EXPECT_EQ(kc_ub[0], KN_INFINITY); + EXPECT_EQ(kc_ub[1], KN_INFINITY); + char* names[2]; + names[0] = new char[20]; + names[1] = new char[20]; + KN_get_var_names_all(kc, 20, names); + EXPECT_STREQ(names[0], "x"); + EXPECT_STREQ(names[1], "y"); + // Check constraints + KN_get_con_lobnds_all(kc, kc_lb); + KN_get_con_upbnds_all(kc, kc_ub); + EXPECT_EQ(kc_lb[0], 10); + EXPECT_EQ(kc_lb[1], -KN_INFINITY); + EXPECT_EQ(kc_ub[0], KN_INFINITY); + EXPECT_EQ(kc_ub[1], 18); + KN_get_con_names_all(kc, 20, names); + EXPECT_STREQ(names[0], "c1"); + EXPECT_STREQ(names[1], "c2"); + // Check everything else by solving the lp + double objSol; + int nStatus = KN_solve(kc); + double kc_x[2]; + KN_get_solution(kc, &nStatus, &objSol, kc_x, NULL); + EXPECT_NEAR(kc_x[0], 6, ERROR_RATE); + EXPECT_NEAR(kc_x[1], 2, ERROR_RATE); + EXPECT_NEAR(objSol, 10, ERROR_RATE); + + delete[] names[0]; + delete[] names[1]; + KN_free(&kc); +} + +/** + * Solves the following LP + * max x + 2y + 2 + * st. -x + y <= 1 + * 3x + 2y <= 12 + * 2x + 3y <= 12 + * x , y \in R+ + */ +TEST(KnitroInterface, SolveLP) { + UNITTEST_INIT_LP(); + EXPECT_FALSE(solver.IsMIP()); + double inf = solver.infinity(); + MPVariable* x = solver.MakeNumVar(0, inf, "x"); + MPVariable* y = solver.MakeNumVar(0, inf, "y"); + MPObjective* obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, 2); + obj->SetOffset(2); + obj->SetMaximization(); + MPConstraint* c1 = solver.MakeRowConstraint(-inf, 1); + c1->SetCoefficient(x, -1); + c1->SetCoefficient(y, 1); + MPConstraint* c2 = solver.MakeRowConstraint(-inf, 12); + c2->SetCoefficient(x, 3); + c2->SetCoefficient(y, 2); + MPConstraint* c3 = solver.MakeRowConstraint(-inf, 12); + c3->SetCoefficient(x, 2); + c3->SetCoefficient(y, 3); + solver.Solve(); + + EXPECT_NEAR(obj->Value(), 9.4, ERROR_RATE); + EXPECT_NEAR(x->solution_value(), 1.8, ERROR_RATE); + EXPECT_NEAR(y->solution_value(), 2.8, ERROR_RATE); + EXPECT_NEAR(x->reduced_cost(), 0, ERROR_RATE); + EXPECT_NEAR(y->reduced_cost(), 0, ERROR_RATE); + EXPECT_NEAR(c1->dual_value(), 0.2, ERROR_RATE); + EXPECT_NEAR(c2->dual_value(), 0, ERROR_RATE); + EXPECT_NEAR(c3->dual_value(), 0.6, ERROR_RATE); +} + +/** + * Solves the following MIP + * max x - y + 5z + * st. x + 2y - z <= 19.5 + * x + y + z >= 3.14 + * x <= 10 + * y + z <= 6 + * x, y, z \in R+ + */ +TEST(KnitroInterface, SolveMIP) { + UNITTEST_INIT_MIP(); + EXPECT_TRUE(solver.IsMIP()); + const double infinity = solver.infinity(); + // x and y are integer non-negative variables. + MPVariable* const x = solver.MakeNumVar(0.0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0.0, infinity, "y"); + MPVariable* const z = solver.MakeIntVar(0.0, infinity, "z"); + + // x + 2 * y - z <= 19.5 + MPConstraint* const c0 = solver.MakeRowConstraint(-infinity, 19.5, "c0"); + c0->SetCoefficient(x, 1); + c0->SetCoefficient(y, 2); + c0->SetCoefficient(z, -1); + + // x + y + z >= 3.14 + MPConstraint* const c1 = solver.MakeRowConstraint(3.14, infinity, "c1"); + c1->SetCoefficient(x, 1); + c1->SetCoefficient(y, 1); + c1->SetCoefficient(z, 1); + + // x <= 10. + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 10.0, "c2"); + c2->SetCoefficient(x, 1); + c2->SetCoefficient(y, 0); + c2->SetCoefficient(z, 0); + + // y + z <= 6. + MPConstraint* const c3 = solver.MakeRowConstraint(-infinity, 6.0, "c3"); + c3->SetCoefficient(x, 0); + c3->SetCoefficient(y, 1); + c3->SetCoefficient(z, 1); + + // Maximize x - y + 5 * z. + MPObjective* const objective = solver.MutableObjective(); + objective->SetCoefficient(x, 1); + objective->SetCoefficient(y, -1); + objective->SetCoefficient(z, 5); + objective->SetMaximization(); + + EXPECT_EQ(solver.nodes(), MPSolverInterface::kUnknownNumberOfNodes); + EXPECT_EQ(solver.iterations(), MPSolverInterface::kUnknownNumberOfIterations); + + const MPSolver::ResultStatus result_status = solver.Solve(); + EXPECT_NEAR(objective->Value(), 40, ERROR_RATE); + EXPECT_NEAR(x->solution_value(), 10, ERROR_RATE); + EXPECT_NEAR(y->solution_value(), 0, ERROR_RATE); + EXPECT_NEAR(z->solution_value(), 6, ERROR_RATE); + + // Just Check that the methods return something + + EXPECT_NE(solver.nodes(), MPSolverInterface::kUnknownNumberOfNodes); + EXPECT_NE(solver.iterations(), MPSolverInterface::kUnknownNumberOfIterations); +} + +/** + * Find a feasible solution for the following LP + * max x + 2y + * st. x >= 0 + * -x + .5y <= .5 + * -.5x + .5y <= .75 + * -.5x + y <= 2 + * y <= 3 + * -.001x + y >= -.01 + * within few iterations + */ +TEST(KnitroInterface, FeasibleSolLP) { + UNITTEST_INIT_LP(); + const double infinity = solver.infinity(); + MPVariable* const x = solver.MakeNumVar(-infinity, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(-infinity, infinity, "y"); + + MPConstraint* const c0 = solver.MakeRowConstraint(0, infinity, "c0"); + c0->SetCoefficient(x, 1); + MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, .5, "c1"); + c1->SetCoefficient(x, -1); + c1->SetCoefficient(y, .5); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, .75, "c2"); + c2->SetCoefficient(x, -.5); + c2->SetCoefficient(y, .5); + MPConstraint* const c3 = solver.MakeRowConstraint(-infinity, 2, "c3"); + c3->SetCoefficient(x, -.5); + c3->SetCoefficient(y, 1); + MPConstraint* const c4 = solver.MakeRowConstraint(-infinity, 3, "c4"); + c4->SetCoefficient(y, 1); + MPConstraint* const c5 = solver.MakeRowConstraint(-.01, infinity, "c5"); + c5->SetCoefficient(x, -.001); + c5->SetCoefficient(y, 1); + + MPObjective* const objective = solver.MutableObjective(); + objective->SetCoefficient(x, 1); + objective->SetCoefficient(y, 2); + objective->SetMaximization(); + + // setting max iter limit + solver.SetSolverSpecificParametersAsString("KN_PARAM_MAXIT 4 "); + + const MPSolver::ResultStatus result_status = solver.Solve(); + EXPECT_EQ(result_status, MPSolver::ResultStatus::FEASIBLE); +} + +/** + * Try to solve the unbounded problem + * max x + * st. x >= 0 + */ +TEST(KnitroInterface, UnboundedLP) { + UNITTEST_INIT_LP(); + const double infinity = solver.infinity(); + MPVariable* const x = solver.MakeNumVar(0, infinity, "x"); + MPObjective* const objective = solver.MutableObjective(); + objective->SetCoefficient(x, 1); + objective->SetMaximization(); + const MPSolver::ResultStatus result_status = solver.Solve(); + EXPECT_EQ(result_status, MPSolver::ResultStatus::UNBOUNDED); +} + +/** + * Try to solve the infeasible problem + * max x + * st. x >= +1 + * x <= -1 + */ +TEST(KnitroInterface, InfeasibleLP) { + UNITTEST_INIT_LP(); + const double infinity = solver.infinity(); + MPVariable* const x = solver.MakeNumVar(-infinity, infinity, "x"); + MPConstraint* const cp = solver.MakeRowConstraint(1, infinity, "cp"); + cp->SetCoefficient(x, 1); + MPConstraint* const cm = solver.MakeRowConstraint(-infinity, -1, "cm"); + cm->SetCoefficient(x, 1); + const MPSolver::ResultStatus result_status = solver.Solve(); + EXPECT_EQ(result_status, MPSolver::ResultStatus::INFEASIBLE); +} + +/** + * Checks that KnitroInterface convert correctly the infinity values + * max x + 2y + * st. x + 4y >= -8 + * x + 4y <= 17 + * -x + y >= -2 + * -x + y <= 3 + * x, y >= 0 + */ +TEST(KnitroInterface, SupportInfinity) { + UNITTEST_INIT_LP(); + double infinity = solver.infinity(); + MPVariable* const x = solver.MakeNumVar(0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0, infinity, "y"); + + MPConstraint* const c1 = solver.MakeRowConstraint(-8, 17, "c1"); + c1->SetCoefficient(x, 1); + c1->SetCoefficient(y, 4); + MPConstraint* const c2 = solver.MakeRowConstraint(-2, 3, "c2"); + c2->SetCoefficient(x, -1); + c2->SetCoefficient(y, 1); + + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, 2); + obj->SetMaximization(); + + solver.Solve(); + EXPECT_NEAR(11, obj->Value(), ERROR_RATE); + EXPECT_NEAR(5, x->solution_value(), ERROR_RATE); + EXPECT_NEAR(3, y->solution_value(), ERROR_RATE); + + // change boundaries to infinity + x->SetBounds(-infinity, infinity); + c2->SetBounds(-2, infinity); + solver.Solve(); + EXPECT_NEAR(11, obj->Value(), ERROR_RATE); + EXPECT_NEAR(5, x->solution_value(), ERROR_RATE); + EXPECT_NEAR(3, y->solution_value(), ERROR_RATE); +} + +/** + * Solves a LP without counstraints + * max x + y + z + * st. x, y, z >= 0 + * x, y, z <= 1 + */ +TEST(KnitroInterface, JustVarProb) { + UNITTEST_INIT_LP(); + std::vector x; + solver.MakeNumVarArray(3, 0, 1, "x", &x); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x[0], 1); + obj->SetCoefficient(x[1], 1); + obj->SetCoefficient(x[2], 1); + obj->SetMaximization(); + + solver.Solve(); + EXPECT_NEAR(obj->Value(), 3, ERROR_RATE); +} + +/** + * MIP without objective + * It solves the [3x3 magic square + * problem](https://en.wikipedia.org/wiki/Magic_square) by finding feasible + * solution + */ +TEST(KnitroInterface, FindFeasSol) { + // find a 3x3 non trivial magic square config + UNITTEST_INIT_MIP(); + double infinity = solver.infinity(); + std::vector x; + solver.MakeIntVarArray(9, 1, infinity, "x", &x); + + std::vector diff; + solver.MakeBoolVarArray(36, "diff", &diff); + + int debut[] = {0, 8, 15, 21, 26, 30, 33, 35}; + for (int i = 0; i < 9; i++) { + for (int j = i + 1; j < 9; j++) { + MPConstraint* const d = + solver.MakeRowConstraint(1.0, 8.0, "dl" + 10 * i + j); + d->SetCoefficient(x[i], 1); + d->SetCoefficient(x[j], -1); + d->SetCoefficient(diff[debut[i] + j - 1 - i], 9.0); + } + } + + int ref[] = {0, 1, 2}; + int comp[][3] = {{3, 4, 5}, {6, 7, 8}, {0, 3, 6}, {7, 1, 4}, + {5, 8, 2}, {0, 4, 8}, {4, 6, 2}}; + + for (auto e : comp) { + MPConstraint* const d = solver.MakeRowConstraint(0, 0, "eq"); + for (int i = 0; i < 3; i++) { + if (ref[i] != e[i]) { + d->SetCoefficient(x[ref[i]], 1); + d->SetCoefficient(x[e[i]], -1); + } + } + } + + solver.Solve(); + for (int i = 0; i < 9; i++) { + for (int j = i + 1; j < 9; j++) { + EXPECT_NE(x[i]->solution_value(), x[j]->solution_value()); + } + } + int val = x[ref[0]]->solution_value() + x[ref[1]]->solution_value() + + x[ref[2]]->solution_value(); + for (auto e : comp) { + int comp_val = x[e[0]]->solution_value() + x[e[1]]->solution_value() + + x[e[2]]->solution_value(); + EXPECT_EQ(val, comp_val); + } +} + +/** + * Test branching priority on the following mip + * max .5x + .86y + * st. 4.2x + 2y >= 33.6 + * 1.3x + 2y <= 16.2 + * x , y \in N + */ +TEST(KnitroInterface, BranchingPriorityChangedForVariable) { + UNITTEST_INIT_MIP(); + double infinity = solver.infinity(); + MPVariable* const x = solver.MakeIntVar(0, infinity, "x"); + MPVariable* const y = solver.MakeIntVar(0, infinity, "y"); + MPConstraint* const c1 = solver.MakeRowConstraint(33.6, infinity, "c1"); + c1->SetCoefficient(x, 4.2); + c1->SetCoefficient(y, 2); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 16.2, "c2"); + c2->SetCoefficient(x, 1.3); + c2->SetCoefficient(y, 2); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, .5); + obj->SetCoefficient(y, .86); + obj->SetMaximization(); + + solver.SetSolverSpecificParametersAsString("KN_PARAM_ACT_LPALG 1 KN_PARAM_MIP_LPALG 3 "); + + // Prioritize branching on x + x->SetBranchingPriority(10); + y->SetBranchingPriority(1); + solver.Solve(); + double sol1 = obj->Value(); + int nodes1 = solver.nodes(); + + // Prioritize branching on y + x->SetBranchingPriority(1); + y->SetBranchingPriority(10); + solver.Solve(); + double sol2 = obj->Value(); + int nodes2 = solver.nodes(); + + EXPECT_EQ(sol1, sol2); + EXPECT_NE(nodes1, nodes2); +} + +// ----- Change Var/Con/obj + +/** + * Solves the initial problem + * max x + * st. x + y >= 2 + * -2x + y <= 4 + * x + y <= 10 + * x - y <= 8 + * x , y >= 0 + * Then applies changes in the problem + */ +TEST(KnitroInterface, ChangePostsolve) { + UNITTEST_INIT_LP(); + const double infinity = solver.solver_infinity(); + + MPVariable* const x = solver.MakeNumVar(0.0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0.0, infinity, "y"); + + MPConstraint* const c1 = solver.MakeRowConstraint(2, infinity, "c1"); + c1->SetCoefficient(x, 1); + c1->SetCoefficient(y, 1); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 4, "c2"); + c2->SetCoefficient(x, -2); + c2->SetCoefficient(y, 1); + MPConstraint* const c3 = solver.MakeRowConstraint(-infinity, 10, "c3"); + c3->SetCoefficient(x, 1); + c3->SetCoefficient(y, 1); + MPConstraint* const c4 = solver.MakeRowConstraint(-infinity, 8, "c4"); + c4->SetCoefficient(x, 1); + c4->SetCoefficient(y, -1); + + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetMaximization(); + + solver.Solve(); + EXPECT_NEAR(obj->Value(), 9, ERROR_RATE); + + // change the objective + obj->SetCoefficient(x, 0); + obj->SetCoefficient(y, 1); + + solver.Solve(); + EXPECT_NEAR(obj->Value(), 8, ERROR_RATE); + + // change the boundaries of y + y->SetBounds(2, 4); + solver.Solve(); + EXPECT_NEAR(obj->Value(), 4, ERROR_RATE); + + // change the boundaries of y + // the objective + // the boundaries of c4 + y->SetBounds(0, infinity); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, 0); + c4->SetBounds(2, 6); + solver.Solve(); + EXPECT_NEAR(obj->Value(), 8, ERROR_RATE); +} + +/** + * Solves the initial problem + * max x + * st. x + y >= 2 + * -2x + y <= 4 + * x + y <= 10 + * x - y <= 8 + * x , y >= 0 + * Then applies changes in the problem + * with incrementality option off + */ +TEST(KnitroInterface, ChangePostsolve2) { + UNITTEST_INIT_LP(); + const double infinity = solver.solver_infinity(); + + MPVariable* const x = solver.MakeNumVar(0.0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0.0, infinity, "y"); + + MPConstraint* const c1 = solver.MakeRowConstraint(2, infinity, "c1"); + c1->SetCoefficient(x, 1); + c1->SetCoefficient(y, 1); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 4, "c2"); + c2->SetCoefficient(x, -2); + c2->SetCoefficient(y, 1); + MPConstraint* const c3 = solver.MakeRowConstraint(-infinity, 10, "c3"); + c3->SetCoefficient(x, 1); + c3->SetCoefficient(y, 1); + MPConstraint* const c4 = solver.MakeRowConstraint(-infinity, 8, "c4"); + c4->SetCoefficient(x, 1); + c4->SetCoefficient(y, -1); + + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetMaximization(); + + solver.Solve(); + EXPECT_NEAR(obj->Value(), 9, ERROR_RATE); + + y->SetBounds(0, infinity); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, 0); + c4->SetBounds(2, 6); + + // turn incrementality off + MPSolverParameters params; + params.SetIntegerParam(MPSolverParameters::INCREMENTALITY, + MPSolverParameters::INCREMENTALITY_OFF); + solver.Solve(params); + EXPECT_NEAR(obj->Value(), 8, ERROR_RATE); +} + +/** + * Solves the initial problem + * max x - y + * st. .5x + y <= 3 + * x + y <= 3 + * Then removes a constraint and solves the new problem + */ +TEST(KnitroInterface, ClearConstraint2) { + UNITTEST_INIT_LP(); + double infinity = solver.infinity(); + MPVariable* const x = solver.MakeNumVar(0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0, infinity, "y"); + MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 3, "c1"); + c1->SetCoefficient(x, .5); + c1->SetCoefficient(y, 1); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 3, "c2"); + c2->SetCoefficient(x, 1); + c2->SetCoefficient(y, 1); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, -1); + obj->SetMaximization(); + + solver.Solve(); + EXPECT_NEAR(3, obj->Value(), ERROR_RATE); + EXPECT_NEAR(3, x->solution_value(), ERROR_RATE); + EXPECT_NEAR(0, y->solution_value(), ERROR_RATE); + + c2->Clear(); + solver.Solve(); + EXPECT_NEAR(6, obj->Value(), ERROR_RATE); + EXPECT_NEAR(6, x->solution_value(), ERROR_RATE); + EXPECT_NEAR(0, y->solution_value(), ERROR_RATE); +} + +/** + * Solves the initial problem + * max x - y + * st. .5x + y <= 3 + * x + y <= 3 + * Then changes the objective and solves the new problem + */ +TEST(KnitroInterface, ClearObjective2) { + UNITTEST_INIT_LP(); + double infinity = solver.infinity(); + MPVariable* const x = solver.MakeNumVar(0, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(0, infinity, "y"); + MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 3, "c1"); + c1->SetCoefficient(x, .5); + c1->SetCoefficient(y, 1); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 3, "c2"); + c2->SetCoefficient(x, 1); + c2->SetCoefficient(y, 1); + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, -1); + obj->SetMaximization(); + + solver.Solve(); + EXPECT_NEAR(3, obj->Value(), ERROR_RATE); + EXPECT_NEAR(3, x->solution_value(), ERROR_RATE); + EXPECT_NEAR(0, y->solution_value(), ERROR_RATE); + + obj->Clear(); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, 1); + solver.Solve(); + EXPECT_NEAR(0, obj->Value(), ERROR_RATE); + EXPECT_NEAR(0, x->solution_value(), ERROR_RATE); + EXPECT_NEAR(0, y->solution_value(), ERROR_RATE); +} + +/** + * Solves the initial problem + * max x + * st. x + y >= 2.5 + * x + y >= -2.5 + * x - y <= 2.5 + * x - y >= -2.5 + * x , y \in R + * Then changes x into integer type and solves the new problem + * Finally changes x back into continuous var and solves + */ +TEST(KnitroInterface, ChangeVarIntoInteger) { + UNITTEST_INIT_MIP(); + double infinity = solver.solver_infinity(); + MPVariable* const x = solver.MakeNumVar(-infinity, infinity, "x"); + MPVariable* const y = solver.MakeNumVar(-infinity, infinity, "y"); + MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 2.5, "c1"); + c1->SetCoefficient(x, 1); + c1->SetCoefficient(y, 1); + MPConstraint* const c2 = solver.MakeRowConstraint(-2.5, infinity, "c2"); + c2->SetCoefficient(x, 1); + c2->SetCoefficient(y, 1); + MPConstraint* const c3 = solver.MakeRowConstraint(-infinity, 2.5, "c3"); + c3->SetCoefficient(x, 1); + c3->SetCoefficient(y, -1); + MPConstraint* const c4 = solver.MakeRowConstraint(-2.5, infinity, "c4"); + c4->SetCoefficient(x, 1); + c4->SetCoefficient(y, -1); + + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetMaximization(); + + solver.Solve(); + EXPECT_NEAR(obj->Value(), 2.5, ERROR_RATE); + + // Change x into integer + x->SetInteger(true); + solver.Solve(); + EXPECT_NEAR(obj->Value(), 2, ERROR_RATE); + + // Change x back into continuous + x->SetInteger(false); + solver.Solve(); + EXPECT_NEAR(obj->Value(), 2.5, ERROR_RATE); +} + +/** + * Solves the initial problem + * max x + y + * st. 0 <= x,y <= 1 + * Then changes the problem into + * max x + y + z + * st. 0 <= z <= 1 (c) + * 0 <= x,y <= 1 + * z >= 0 + */ +TEST(KnitroInterface, AddVarAndConstraint) { + UNITTEST_INIT_MIP(); + double infinity = solver.solver_infinity(); + MPVariable* const x = solver.MakeNumVar(0, 1, "x"); + MPVariable* const y = solver.MakeNumVar(0, 1, "y"); + + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetCoefficient(y, 1); + obj->SetMaximization(); + + solver.Solve(); + EXPECT_NEAR(obj->Value(), 2, ERROR_RATE); + + MPVariable* const z = solver.MakeNumVar(0, infinity, "z"); + MPConstraint* const c = solver.MakeRowConstraint(0, 1, "c"); + c->SetCoefficient(z, 1); + obj->SetCoefficient(z, 1); + + solver.Solve(); + EXPECT_NEAR(obj->Value(), 3, ERROR_RATE); +} + +/** + * Solves the initial problem + * max x + * st. x <= 7 + * x <= 4 + * x >= 0 + * + * Then add a new variable to the problem + * max x + y + * st. x + 2y <= 7 + * x - y <= 4 + * x >= 0 + */ +TEST(KnitroInterface, AddVarToExistingConstraint) { + UNITTEST_INIT_LP(); + double infinity = solver.infinity(); + MPVariable* const x = solver.MakeNumVar(0, infinity, "x"); + + MPObjective* const obj = solver.MutableObjective(); + obj->SetCoefficient(x, 1); + obj->SetMaximization(); + + MPConstraint* const c1 = solver.MakeRowConstraint(-infinity, 7, "c1"); + c1->SetCoefficient(x, 1); + MPConstraint* const c2 = solver.MakeRowConstraint(-infinity, 4, "c2"); + c2->SetCoefficient(x, 1); + + solver.Solve(); + EXPECT_NEAR(obj->Value(), 4, ERROR_RATE); + + MPVariable* const y = solver.MakeNumVar(0, infinity, "y"); + c1->SetCoefficient(y, 2); + c2->SetCoefficient(y, -1); + obj->SetCoefficient(y, 1); + + solver.Solve(); + EXPECT_NEAR(obj->Value(), 6, ERROR_RATE); + EXPECT_NEAR(x->solution_value(), 5, ERROR_RATE); + EXPECT_NEAR(y->solution_value(), 1, ERROR_RATE); +} + +/** + * Since GLOP do not implement Write method + * + */ +void write_readible_problem_model(MPSolver& solver, const char* file_name) { + FILE* file; + file = fopen(file_name, "w"); + + // writing variables + int nb_var = solver.NumVariables(); + fprintf(file, "nb variables : %i\n", nb_var); + for (int i = 0; i < nb_var; i++) { + fprintf(file, "%4.0f %4.0f\n", solver.variable(i)->ub(), + solver.variable(i)->lb()); + } + fprintf(file, "\n"); + + // writing A matrix + int nb_con = solver.NumConstraints(); + fprintf(file, "A : %i x %i\n", nb_con, nb_var); + for (int j = 0; j < nb_con; j++) { + MPConstraint* ct = solver.constraint(j); + for (int i = 0; i < nb_var; i++) { + fprintf(file, "%3.0f ", ct->GetCoefficient(solver.variable(i))); + } + fprintf(file, "\n"); + } + fprintf(file, "\n"); + + // writing cT vector + MPObjective* const obj = solver.MutableObjective(); + for (int i = 0; i < nb_var; i++) + fprintf(file, "%3.0f ", obj->GetCoefficient(solver.variable(i))); + + fclose(file); +} + +/** + * Solve a random generated LP + * max cT.x + * st. Ax <= b + * u <= x <= v + * With + * x \in R^n + * Matrix A a randomly generated invertible lower triangular matrix + * u and v the lower and upper bound of x respectively + */ +TEST(KnitroInterface, RandomLP) { + srand(time(NULL)); + + // Create a LP problem with Knitro solver + UNITTEST_INIT_LP(); + double infinity = solver.infinity(); + const int nb_var = 100; + std::vector vars; + for (int i = 0; i < nb_var; i++) + vars.push_back(solver.MakeNumVar(-rand() % 1000, rand() % 1000, + "x_" + std::to_string(i))); + std::vector cons; + for (int j = 0; j < nb_var; j++) { + cons.push_back(solver.MakeRowConstraint(-infinity, rand() % 2001 - 1000, + "c_" + std::to_string(j))); + for (int i = 0; i <= j; i++) { + cons.back()->SetCoefficient( + vars[i], (i == j) ? rand() % 100 + 1 : rand() % 199 - 99); + } + } + MPObjective* const objective = solver.MutableObjective(); + for (int i = 0; i < nb_var; i++) { + objective->SetCoefficient(vars[i], rand() % 199 - 99); + } + objective->SetMaximization(); + time_t start_time; + time(&start_time); + MPSolver::ResultStatus kc_status = solver.Solve(); + printf("KNITRO solving time = %ld\n", time(NULL) - start_time); + write_readible_problem_model(solver, "lp_problem_knitro.mps"); + + // Create the same problem with GLOP solver + MPSolver solverbis("GLOP_LP", MPSolver::GLOP_LINEAR_PROGRAMMING); + for (int i = 0; i < nb_var; i++) + solverbis.MakeNumVar(vars[i]->lb(), vars[i]->ub(), vars[i]->name()); + for (int j = 0; j < nb_var; j++) { + MPConstraint* ct = solverbis.MakeRowConstraint(cons[j]->lb(), cons[j]->ub(), + cons[j]->name()); + for (int i = 0; i <= j; i++) { + ct->SetCoefficient(solverbis.variable(i), + cons[j]->GetCoefficient(vars[i])); + } + } + MPObjective* const objectivebis = solverbis.MutableObjective(); + for (int i = 0; i < nb_var; i++) { + objectivebis->SetCoefficient(solverbis.variable(i), + objective->GetCoefficient(vars[i])); + } + objectivebis->SetMaximization(); + time(&start_time); + MPSolver::ResultStatus glop_status = solverbis.Solve(); + printf("GLOP solving time = %ld\n", time(NULL) - start_time); + write_readible_problem_model(solverbis, "lp_problem_glop.mps"); + + EXPECT_EQ(kc_status, glop_status); + if (glop_status == MPSolver::ResultStatus::OPTIMAL) { + EXPECT_NEAR(objective->Value(), objectivebis->Value(), 1e-3); + } +} + +// /** +// * Solve a random generated MIP with SCIP and Knitro solver +// * max cT.x +// * st. Ax <= b +// * u <= x <= v +// * With +// * x \in Z^n +// * Matrix A a randomly generated invertible lower triangular matrix +// * u and v the lower and upper bound of x respectively +// */ +// TEST(KnitroInterface, RandomMIP) { +// srand(time(NULL)); + +// // Create a LP problem with Knitro solver +// UNITTEST_INIT_MIP(); + +// double infinity = solver.infinity(); +// const int nb_var = 30; +// std::vector vars; +// for (int i = 0; i < nb_var; i++) +// vars.push_back(solver.MakeIntVar(-rand() % 1000, rand() % 1000, +// "x_" + std::to_string(i))); +// std::vector cons; +// for (int j = 0; j < nb_var; j++) { +// cons.push_back(solver.MakeRowConstraint(-infinity, rand() % 2001 - 1000, +// "c_" + std::to_string(j))); +// for (int i = 0; i <= j; i++) { +// cons.back()->SetCoefficient( +// vars[i], (i == j) ? rand() % 100 + 1 : rand() % 199 - 99); +// } +// } +// MPObjective* const objective = solver.MutableObjective(); +// for (int i = 0; i < nb_var; i++) { +// objective->SetCoefficient(vars[i], rand() % 199 - 99); +// } +// objective->SetMaximization(); +// time_t start_time; +// time(&start_time); +// MPSolver::ResultStatus kc_status = solver.Solve(); +// printf("KNITRO solving time = %ld\n", time(NULL) - start_time); +// write_readible_problem_model(solver, "mip_problem_knitro.mps"); + +// // Create the same problem with SCIP solver +// MPSolver solverbis("SCIP_MIP", MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING); +// for (int i = 0; i < nb_var; i++) +// solverbis.MakeIntVar(vars[i]->lb(), vars[i]->ub(), vars[i]->name()); +// for (int j = 0; j < nb_var; j++) { +// MPConstraint* ct = solverbis.MakeRowConstraint(cons[j]->lb(), cons[j]->ub(), +// cons[j]->name()); +// for (int i = 0; i <= j; i++) { +// ct->SetCoefficient(solverbis.variable(i), +// cons[j]->GetCoefficient(vars[i])); +// } +// } +// MPObjective* const objectivebis = solverbis.MutableObjective(); +// for (int i = 0; i < nb_var; i++) { +// objectivebis->SetCoefficient(solverbis.variable(i), +// objective->GetCoefficient(vars[i])); +// } +// objectivebis->SetMaximization(); +// time(&start_time); +// MPSolver::ResultStatus scip_status = solverbis.Solve(); +// printf("SCIP solving time = %ld\n", time(NULL) - start_time); +// write_readible_problem_model(solverbis, "mip_problem_scip.mps"); + +// EXPECT_EQ(kc_status, scip_status); +// if (scip_status == MPSolver::ResultStatus::OPTIMAL) { +// EXPECT_NEAR(objective->Value(), objectivebis->Value(), 1e-3); +// } +// } + +/*-------------------- Callback --------------------*/ + +/** + * Test for lazy constraint extracted from Knitro's distribution + * C code examples + */ + +/** + * User structure for the lazy constraints callback. + */ +typedef struct LazyConstraintsCallbackUserParams { + /** Number of vertices. */ + int number_of_vertices; + + /** Pointer to the distance matrix. */ + int*** distances; + + /** Pointer to the variable indices. */ + int*** variable_indices; + +} LazyConstraintsCallbackUserParams; + +class KNMPCallback : public MPCallback { + private: + LazyConstraintsCallbackUserParams* userparams_; + KN_context* kc_ptr_; + MPSolver* mpSolver_; + + public: + KNMPCallback(LazyConstraintsCallbackUserParams* userParams, KN_context* kc, + MPSolver* solver) + : MPCallback(false, true), + userparams_(userParams), + kc_ptr_(kc), + mpSolver_(solver){}; + + ~KNMPCallback() override{}; + + void RunCallback(MPCallbackContext* callback_context) override { + // Return code of Knitro API. + int knitro_return_code = 0; + + double infinity = mpSolver_->infinity(); + + // Avoid + // 'error: 'for' loop initial declarations are only allowed in C99 mode' + int vertex_id_1 = -1; + int vertex_id_2 = -1; + int pos = -1; + + // We only add cuts for integral solutions. + // Retrieve the integer tolerance value. + double integer_tol = 0.0; + knitro_return_code = + KN_get_double_param(kc_ptr_, KN_PARAM_MIP_INTEGERTOL, &integer_tol); + if (knitro_return_code) return; + + // Stop if the solution is not integral. + // printf(" Check if solution is integral.\n"); + for (vertex_id_1 = 0; vertex_id_1 < userparams_->number_of_vertices; + ++vertex_id_1) { + for (vertex_id_2 = 0; vertex_id_2 < vertex_id_1; ++vertex_id_2) { + int variable_id = + (*userparams_->variable_indices)[vertex_id_1][vertex_id_2]; + double value = + callback_context->VariableValue(mpSolver_->variable(variable_id)); + if (fabs(value - round(value)) > integer_tol) { + // printf(" The solution is not integral.\n\n"); + return; + } + } + } + // printf(" The solution is integral.\n"); + + // Get objective value. + double objective = -1; + knitro_return_code = KN_get_obj_value(kc_ptr_, &objective); + if (knitro_return_code) return; + + // printf( + // " Lazy constraints called on an integral solution of value + // %e.\n", objective); + + // For each vertex, retrieve its two neighbors. + int(*neighbors)[2]; + neighbors = + (int(*)[2])malloc(userparams_->number_of_vertices * sizeof(int[2])); + for (vertex_id_1 = 0; vertex_id_1 < userparams_->number_of_vertices; + ++vertex_id_1) { + neighbors[vertex_id_1][0] = -1; + neighbors[vertex_id_1][1] = -1; + } + for (vertex_id_1 = 0; vertex_id_1 < userparams_->number_of_vertices; + ++vertex_id_1) { + for (vertex_id_2 = 0; vertex_id_2 < vertex_id_1; ++vertex_id_2) { + int variable_id = + (*userparams_->variable_indices)[vertex_id_1][vertex_id_2]; + double value = + callback_context->VariableValue(mpSolver_->variable(variable_id)); + if (value > 0.5) { + if (neighbors[vertex_id_1][0] == -1) { + neighbors[vertex_id_1][0] = vertex_id_2; + } else { + neighbors[vertex_id_1][1] = vertex_id_2; + } + if (neighbors[vertex_id_2][0] == -1) { + neighbors[vertex_id_2][0] = vertex_id_1; + } else { + neighbors[vertex_id_2][1] = vertex_id_1; + } + } + } + } + + // For each vertex, the sub-tour it belongs to. + int* vertex_sub_tour; + vertex_sub_tour = + (int*)malloc(userparams_->number_of_vertices * sizeof(int)); + for (vertex_id_1 = 0; vertex_id_1 < userparams_->number_of_vertices; + ++vertex_id_1) { + vertex_sub_tour[vertex_id_1] = -1; + } + + // The current sub-tour. + int* current_sub_tour; + current_sub_tour = + (int*)malloc(userparams_->number_of_vertices * sizeof(int)); + int current_sub_tour_size = 0; + + // Find the sub-tours. + int number_of_sub_tours = 0; + for (;;) { + // Find the first vertex which sub-tour has not been found. + int vertex_id = 0; + while (vertex_id < userparams_->number_of_vertices && + vertex_sub_tour[vertex_id] != -1) { + vertex_id++; + } + if (vertex_id == userparams_->number_of_vertices) break; + + // Loop through the tour starting at vertex 'vertex_id'. + current_sub_tour_size = 0; + while (vertex_sub_tour[vertex_id] == -1) { + vertex_sub_tour[vertex_id] = number_of_sub_tours; + current_sub_tour[current_sub_tour_size] = vertex_id; + if (current_sub_tour_size == 0 || + neighbors[vertex_id][0] != + current_sub_tour[current_sub_tour_size - 1]) { + vertex_id = neighbors[vertex_id][0]; + } else { + vertex_id = neighbors[vertex_id][1]; + } + current_sub_tour_size++; + } + + // Add the sub-tour elimination constraint. + if (current_sub_tour_size < userparams_->number_of_vertices) { + number_of_sub_tours++; + + LinearExpr ct; + for (pos = 0; pos < current_sub_tour_size; ++pos) { + int vertex_id_1 = current_sub_tour[pos]; + int vertex_id_2 = current_sub_tour[(pos + 1) % current_sub_tour_size]; + int variable_id = + (vertex_id_1 > vertex_id_2) + ? (*userparams_->variable_indices)[vertex_id_1][vertex_id_2] + : (*userparams_->variable_indices)[vertex_id_2][vertex_id_1]; + ct += LinearExpr(mpSolver_->variable(variable_id)); + } + + callback_context->AddLazyConstraint( + LinearRange(-infinity, ct, current_sub_tour_size - 1)); + } + } + + // if (number_of_sub_tours == 0) { + // printf(" No sub-tour found, the solution is feasible.\n"); + // } else { + // printf(" %i sub-tour(s) found.\n", number_of_sub_tours); + // } + // printf("\n"); + + // Free allocated structures. + free(neighbors); + free(vertex_sub_tour); + free(current_sub_tour); + + return; + }; + + LazyConstraintsCallbackUserParams* GetUserParams() { return userparams_; } +}; + +TEST(KnitroInterface, LazyConstraint) { + // Avoid + // 'error: 'for' loop initial declarations are only allowed in C99 mode' + int vertex_id_1 = -1; + int vertex_id_2 = -1; + + int fscanf_return_value = -1; + + ////////// + // Data // + ////////// + + // Data of the traveling salesman problem. + std::filesystem::path p = std::filesystem::current_path(); + std::cout << "Current path" << p << std::endl; + FILE* file = fopen("ortools/knitro/resources/bayg29.tsp", "r"); + if (file != nullptr) { + printf("bayg29.tsp found in Knitro resources rep\n"); + } else { + file = fopen("or-tools/ortools/knitro/resources/bayg29.tsp", "r"); + if (file != nullptr) { + printf("bayg29.tsp found in submodule OR-Tools Knitro resources rep\n"); + } else { + file = fopen(absl::StrCat(getenv("OR_ROOT"), "/ortools/knitro/resources/bayg29.tsp").c_str(), "r"); + if (file != nullptr) { + printf("bayg29.tsp found with OR_ROOT %s\n", getenv("OR_ROOT")); + } else { + printf("bayg29.tsp not found !\n"); + EXPECT_TRUE(false); + } + } + } + + int number_of_vertices = -1; + fscanf_return_value = fscanf(file, "%d", &number_of_vertices); + EXPECT_EQ(fscanf_return_value, 1); + + int** distances; + distances = (int**)malloc(number_of_vertices * sizeof(int*)); + for (vertex_id_1 = 1; vertex_id_1 < number_of_vertices; ++vertex_id_1) { + distances[vertex_id_1] = (int*)malloc(vertex_id_1 * sizeof(int)); + } + for (vertex_id_1 = 0; vertex_id_1 < number_of_vertices; ++vertex_id_1) { + for (vertex_id_2 = 0; vertex_id_2 < vertex_id_1; ++vertex_id_2) { + int distance = 0; + fscanf_return_value = fscanf(file, "%i", &distance); + EXPECT_EQ(fscanf_return_value, 1); + distances[vertex_id_1][vertex_id_2] = distance; + } + } + fclose(file); + + /////////////////////////////// + // Initialize Knitro context // + /////////////////////////////// + + // Return code of Knitro API. + int knitro_return_code = 0; + + // Create a new Knitro context. + UNITTEST_INIT_MIP(); + MPObjective* obj = solver.MutableObjective(); + + /////////////// + // Variables // + /////////////// + + // Structure to retrieve variable indices from vertex indices. + int** variable_indices; + variable_indices = (int**)malloc(number_of_vertices * sizeof(int*)); + for (vertex_id_1 = 1; vertex_id_1 < number_of_vertices; ++vertex_id_1) { + variable_indices[vertex_id_1] = (int*)malloc(vertex_id_1 * sizeof(int)); + } + + // Add variables. + for (vertex_id_1 = 0; vertex_id_1 < number_of_vertices; ++vertex_id_1) { + for (vertex_id_2 = 0; vertex_id_2 < vertex_id_1; ++vertex_id_2) { + // Add the variable corresponding to edge (vertex_id_1, vertex_id_2). + int variable_id = -1; + MPVariable* var_tmp = solver.MakeBoolVar(""); + variable_id = var_tmp->index(); + variable_indices[vertex_id_1][vertex_id_2] = variable_id; + } + } + + /////////////// + // Objective // + /////////////// + + // Set the objective. + for (vertex_id_1 = 0; vertex_id_1 < number_of_vertices; ++vertex_id_1) { + for (vertex_id_2 = 0; vertex_id_2 < vertex_id_1; ++vertex_id_2) { + obj->SetCoefficient( + solver.variable(variable_indices[vertex_id_1][vertex_id_2]), + distances[vertex_id_1][vertex_id_2]); + } + } + + ///////////////// + // Constraints // + ///////////////// + + // For each vertex, select exactly two incident edges. + for (vertex_id_1 = 0; vertex_id_1 < number_of_vertices; ++vertex_id_1) { + // Add the constraint. + MPConstraint* ct = solver.MakeRowConstraint(2, 2); + + // Add the constraint terms. + for (vertex_id_2 = 0; vertex_id_2 < number_of_vertices; ++vertex_id_2) { + if (vertex_id_2 == vertex_id_1) continue; + int variable_id = (vertex_id_1 > vertex_id_2) + ? variable_indices[vertex_id_1][vertex_id_2] + : variable_indices[vertex_id_2][vertex_id_1]; + ct->SetCoefficient(solver.variable(variable_id), 1); + } + } + + // Sub-tour elimination constraints added through lazy constraints. + LazyConstraintsCallbackUserParams lazyconstraints_callback_user_params; + lazyconstraints_callback_user_params.number_of_vertices = number_of_vertices; + lazyconstraints_callback_user_params.distances = &distances; + lazyconstraints_callback_user_params.variable_indices = &variable_indices; + KNMPCallback* callback = new KNMPCallback( + &lazyconstraints_callback_user_params, + reinterpret_cast(solver.underlying_solver()), &solver); + solver.SetCallback(callback); + + /////////// + // Solve // + /////////// + + solver.Solve(); + + /////////////////////////////// + // Free allocated structures // + /////////////////////////////// + + // Delete distances and variable_indices. + for (vertex_id_1 = 1; vertex_id_1 < number_of_vertices; ++vertex_id_1) { + free(distances[vertex_id_1]); + free(variable_indices[vertex_id_1]); + } + free(distances); + free(variable_indices); + free(callback); + + double integer_tol; + getter.Double_Param(KN_PARAM_MIP_INTEGERTOL, &integer_tol); + + EXPECT_NEAR(obj->Value(), 1610, integer_tol); +} + +} // namespace operations_research + +int main(int argc, char** argv) { + absl::SetFlag(&FLAGS_stderrthreshold, 1); + testing::InitGoogleTest(&argc, argv); + if (!operations_research::KnitroIsCorrectlyInstalled()) { + LOG(ERROR) << "Knitro solver is not available"; + return EXIT_SUCCESS; + } else { + if (!RUN_ALL_TESTS()) { + remove("knitro_interface_test_LP_model"); + remove("knitro_interface_test_empty"); + remove("lp_problem_knitro.mps"); + remove("lp_problem_glop.mps"); + remove("mip_problem_knitro.mps"); + remove("mip_problem_scip.mps"); + return EXIT_SUCCESS; + } + return EXIT_FAILURE; + } +} diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 77de096ce99..44c0ae06d5b 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -406,7 +406,8 @@ extern MPSolverInterface* BuildCplexInterface(bool mip, MPSolver* const solver); #endif extern MPSolverInterface* BuildXpressInterface(bool mip, MPSolver* const solver); - +extern MPSolverInterface* BuildKnitroInterface(bool mip, + MPSolver* const solver); namespace { MPSolverInterface* BuildSolverInterface(MPSolver* const solver) { DCHECK(solver != nullptr); @@ -463,6 +464,10 @@ MPSolverInterface* BuildSolverInterface(MPSolver* const solver) { return BuildXpressInterface(true, solver); case MPSolver::XPRESS_LINEAR_PROGRAMMING: return BuildXpressInterface(false, solver); + case MPSolver::KNITRO_MIXED_INTEGER_PROGRAMMING: + return BuildKnitroInterface(true, solver); + case MPSolver::KNITRO_LINEAR_PROGRAMMING: + return BuildKnitroInterface(false, solver); default: // TODO(user): Revert to the best *available* interface. LOG(FATAL) << "Linear solver not recognized."; @@ -499,6 +504,7 @@ MPSolver::~MPSolver() { Clear(); } extern bool GurobiIsCorrectlyInstalled(); extern bool XpressIsCorrectlyInstalled(); +extern bool KnitroIsCorrectlyInstalled(); // static bool MPSolver::SupportsProblemType(OptimizationProblemType problem_type) { @@ -547,6 +553,10 @@ bool MPSolver::SupportsProblemType(OptimizationProblemType problem_type) { problem_type == XPRESS_LINEAR_PROGRAMMING) { return XpressIsCorrectlyInstalled(); } + if (problem_type == KNITRO_MIXED_INTEGER_PROGRAMMING || + problem_type == KNITRO_LINEAR_PROGRAMMING) { + return KnitroIsCorrectlyInstalled(); + } return false; } @@ -585,6 +595,8 @@ constexpr {MPSolver::KNAPSACK_MIXED_INTEGER_PROGRAMMING, "knapsack"}, {MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING, "cplex"}, {MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING, "xpress"}, + {MPSolver::KNITRO_LINEAR_PROGRAMMING, "knitro_lp"}, + {MPSolver::KNITRO_MIXED_INTEGER_PROGRAMMING, "knitro"}, }; // static bool MPSolver::ParseSolverType(absl::string_view solver_id, diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index 0b363d5d307..c98a3cea42f 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -237,6 +237,8 @@ class MPSolver { XPRESS_MIXED_INTEGER_PROGRAMMING = 102, COPT_LINEAR_PROGRAMMING = 103, COPT_MIXED_INTEGER_PROGRAMMING = 104, + KNITRO_LINEAR_PROGRAMMING = 105, + KNITRO_MIXED_INTEGER_PROGRAMMING = 106, }; /// Create a solver with the given name and underlying solver backend. @@ -891,6 +893,7 @@ class MPSolver { friend class GurobiInterface; friend class CplexInterface; friend class XpressInterface; + friend class KnitroInterface; friend class SLMInterface; friend class MPSolverInterface; friend class GLOPInterface; @@ -1123,6 +1126,7 @@ class MPObjective { friend class GurobiInterface; friend class CplexInterface; friend class XpressInterface; + friend class KnitroInterface; friend class GLOPInterface; friend class BopInterface; friend class SatInterface; @@ -1237,6 +1241,7 @@ class MPVariable { friend class GurobiInterface; friend class CplexInterface; friend class XpressInterface; + friend class KnitroInterface; friend class GLOPInterface; friend class MPVariableSolutionValueTest; friend class BopInterface; @@ -1386,6 +1391,7 @@ class MPConstraint { friend class GurobiInterface; friend class CplexInterface; friend class XpressInterface; + friend class KnitroInterface; friend class GLOPInterface; friend class BopInterface; friend class SatInterface; diff --git a/ortools/linear_solver/linear_solver.proto b/ortools/linear_solver/linear_solver.proto index d90e4a074ac..6b8e58cd44d 100644 --- a/ortools/linear_solver/linear_solver.proto +++ b/ortools/linear_solver/linear_solver.proto @@ -423,6 +423,7 @@ message MPModelRequest { GUROBI_LINEAR_PROGRAMMING = 6; // Commercial, needs a valid license. XPRESS_LINEAR_PROGRAMMING = 101; // Commercial, needs a valid license. NOLINT + KNITRO_LINEAR_PROGRAMMING = 105; CPLEX_LINEAR_PROGRAMMING = 10; // Commercial, needs a valid license. NOLINT HIGHS_LINEAR_PROGRAMMING = 15; @@ -432,6 +433,7 @@ message MPModelRequest { GUROBI_MIXED_INTEGER_PROGRAMMING = 7; // Commercial, needs a valid license. XPRESS_MIXED_INTEGER_PROGRAMMING = 102; // Commercial, needs a valid license. NOLINT + KNITRO_MIXED_INTEGER_PROGRAMMING = 106; CPLEX_MIXED_INTEGER_PROGRAMMING = 11; // Commercial, needs a valid license. NOLINT HIGHS_MIXED_INTEGER_PROGRAMMING = 16; diff --git a/ortools/linear_solver/python/linear_solver.i b/ortools/linear_solver/python/linear_solver.i index a475c55a777..f71a1393d4a 100644 --- a/ortools/linear_solver/python/linear_solver.i +++ b/ortools/linear_solver/python/linear_solver.i @@ -314,6 +314,8 @@ PY_CONVERT(MPVariable); %unignore operations_research::MPSolver::CPLEX_MIXED_INTEGER_PROGRAMMING; %unignore operations_research::MPSolver::XPRESS_LINEAR_PROGRAMMING; %unignore operations_research::MPSolver::XPRESS_MIXED_INTEGER_PROGRAMMING; +%unignore operations_research::MPSolver::KNITRO_LINEAR_PROGRAMMING; +%unignore operations_research::MPSolver::KNITRO_MIXED_INTEGER_PROGRAMMING; // Expose the MPSolver::ResultStatus enum. %unignore operations_research::MPSolver::ResultStatus; diff --git a/ortools/math_opt/solver_tests/status_tests.cc b/ortools/math_opt/solver_tests/status_tests.cc index 7c2860a4c01..1d888351b70 100644 --- a/ortools/math_opt/solver_tests/status_tests.cc +++ b/ortools/math_opt/solver_tests/status_tests.cc @@ -99,6 +99,9 @@ TEST_P(StatusTest, PrimalAndDualInfeasible) { << "Ignoring this test as GLPK gets stuck in presolve for IP's " "with a primal-dual infeasible LP relaxation."; } + if (GetParam().solver_type == SolverType::kHighs) { + GTEST_SKIP() << "Ignoring this test as Highs 1.7+ returns error."; + } Model model; const Variable x1 = diff --git a/ortools/routing/BUILD.bazel b/ortools/routing/BUILD.bazel deleted file mode 100644 index 1e9d469acab..00000000000 --- a/ortools/routing/BUILD.bazel +++ /dev/null @@ -1,291 +0,0 @@ -# Copyright 2010-2024 Google LLC -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_proto_library") -load("@rules_java//java:defs.bzl", "java_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") -load("@rules_python//python:proto.bzl", "py_proto_library") - -package(default_visibility = ["//visibility:public"]) - -config_setting( - name = "on_linux", - constraint_values = ["@platforms//os:linux"], -) - -config_setting( - name = "on_macos", - constraint_values = ["@platforms//os:macos"], -) - -config_setting( - name = "on_windows", - constraint_values = ["@platforms//os:windows"], -) - -proto_library( - name = "enums_proto", - srcs = ["enums.proto"], -) - -cc_proto_library( - name = "enums_cc_proto", - deps = [":enums_proto"], -) - -java_proto_library( - name = "enums_java_proto", - deps = [":enums_proto"], -) - -proto_library( - name = "ils_proto", - srcs = ["ils.proto"], - deps = [":enums_proto"], -) - -cc_proto_library( - name = "ils_cc_proto", - deps = [":ils_proto"], -) - -py_proto_library( - name = "ils_py_pb2", - deps = [":ils_proto"], -) - -java_proto_library( - name = "ils_java_proto", - deps = [":ils_proto"], -) - -proto_library( - name = "parameters_proto", - srcs = ["parameters.proto"], - deps = [ - ":enums_proto", - ":ils_proto", - "//ortools/constraint_solver:solver_parameters_proto", - "//ortools/sat:sat_parameters_proto", - "//ortools/util:optional_boolean_proto", - "@com_google_protobuf//:duration_proto", - ], -) - -cc_proto_library( - name = "parameters_cc_proto", - deps = [":parameters_proto"], -) - -java_proto_library( - name = "parameters_java_proto", - deps = [":parameters_proto"], -) - -py_proto_library( - name = "parameters_py_pb2", - deps = [":parameters_proto"], -) - -py_proto_library( - name = "enums_py_pb2", - deps = [":enums_proto"], -) - -cc_library( - name = "parameters", - srcs = ["parameters.cc"], - hdrs = ["parameters.h"], - deps = [ - ":enums_cc_proto", - ":ils_cc_proto", - ":parameters_cc_proto", - "//ortools/base", - "//ortools/base:proto_enum_utils", - "//ortools/base:protoutil", - "//ortools/base:types", - "//ortools/constraint_solver:cp", - "//ortools/constraint_solver:solver_parameters_cc_proto", - "//ortools/port:proto_utils", - "//ortools/sat:sat_parameters_cc_proto", - "//ortools/util:optional_boolean_cc_proto", - "//ortools/util:testing_utils", - "@com_google_absl//absl/container:flat_hash_map", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/strings:str_format", - "@com_google_absl//absl/time", - "@com_google_protobuf//:protobuf", - ], -) - -cc_library( - name = "parameters_utils", - srcs = ["parameters_utils.cc"], - hdrs = ["parameters_utils.h"], - deps = [ - ":parameters_cc_proto", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( - name = "types", - hdrs = ["types.h"], - deps = [ - "//ortools/base:int_type", - "//ortools/util:piecewise_linear_function", - ], -) - -cc_library( - name = "utils", - srcs = ["utils.cc"], - hdrs = ["utils.h"], - deps = [ - "//ortools/util:saturated_arithmetic", - "@com_google_absl//absl/log:check", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( - name = "neighborhoods", - srcs = ["neighborhoods.cc"], - hdrs = ["neighborhoods.h"], - deps = [ - ":types", - ":utils", - "//ortools/base:types", - "//ortools/constraint_solver:cp", - "//ortools/util:bitset", - "//ortools/util:saturated_arithmetic", - "@com_google_absl//absl/log:check", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( - name = "index_manager", - srcs = ["index_manager.cc"], - hdrs = ["index_manager.h"], - deps = [ - ":types", - "//ortools/base", - "//ortools/base:strong_vector", - "//ortools/base:types", - "@com_google_absl//absl/container:flat_hash_set", - "@com_google_absl//absl/log:check", - "@com_google_absl//absl/types:span", - ], -) - -cc_library( - name = "routing", - srcs = [ - "breaks.cc", - "constraints.cc", - "decision_builders.cc", - "filters.cc", - "flow.cc", - "ils.cc", - "insertion_lns.cc", - "lp_scheduling.cc", - "routing.cc", - "sat.cc", - "search.cc", - ], - hdrs = [ - "constraints.h", - "decision_builders.h", - "filters.h", - "ils.h", - "insertion_lns.h", - "lp_scheduling.h", - "routing.h", - "search.h", - ], - copts = select({ - "on_linux": [], - "on_macos": [], - "on_windows": ["/Zc:preprocessor"], - "//conditions:default": [], - }), - deps = [ - ":enums_cc_proto", - ":ils_cc_proto", - ":index_manager", - ":neighborhoods", - ":parameters", - ":parameters_cc_proto", - ":parameters_utils", - ":types", - ":utils", - "//ortools/base", - "//ortools/base:dump_vars", - "//ortools/base:int_type", - "//ortools/base:map_util", - "//ortools/base:mathutil", - "//ortools/base:protoutil", - "//ortools/base:stl_util", - "//ortools/base:strong_vector", - "//ortools/base:types", - "//ortools/constraint_solver:cp", - "//ortools/constraint_solver:solver_parameters_cc_proto", - "//ortools/glop:lp_solver", - "//ortools/glop:parameters_cc_proto", - "//ortools/graph", - "//ortools/graph:christofides", - "//ortools/graph:connected_components", - "//ortools/graph:ebert_graph", - "//ortools/graph:linear_assignment", - "//ortools/graph:min_cost_flow", - "//ortools/lp_data", - "//ortools/lp_data:base", - "//ortools/port:proto_utils", - "//ortools/sat:cp_model_cc_proto", - "//ortools/sat:cp_model_solver", - "//ortools/sat:integer", - "//ortools/sat:lp_utils", - "//ortools/sat:model", - "//ortools/sat:sat_parameters_cc_proto", - "//ortools/sat:theta_tree", - "//ortools/util:bitset", - "//ortools/util:flat_matrix", - "//ortools/util:optional_boolean_cc_proto", - "//ortools/util:piecewise_linear_function", - "//ortools/util:range_minimum_query", - "//ortools/util:range_query_function", - "//ortools/util:saturated_arithmetic", - "//ortools/util:sorted_interval_list", - "//ortools/util:time_limit", - "@com_google_absl//absl/algorithm:container", - "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/container:btree", - "@com_google_absl//absl/container:flat_hash_map", - "@com_google_absl//absl/container:flat_hash_set", - "@com_google_absl//absl/container:inlined_vector", - "@com_google_absl//absl/flags:flag", - "@com_google_absl//absl/functional:bind_front", - "@com_google_absl//absl/hash", - "@com_google_absl//absl/log", - "@com_google_absl//absl/log:check", - "@com_google_absl//absl/log:die_if_null", - "@com_google_absl//absl/memory", - "@com_google_absl//absl/status:statusor", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/strings:str_format", - "@com_google_absl//absl/time", - "@com_google_absl//absl/types:span", - "@com_google_protobuf//:protobuf", - ], -) diff --git a/ortools/sat/BUILD.bazel b/ortools/sat/BUILD.bazel index 851f3f2bbe3..fb305e4db8f 100644 --- a/ortools/sat/BUILD.bazel +++ b/ortools/sat/BUILD.bazel @@ -520,6 +520,122 @@ cc_library( ], ) +cc_library( + name = "cp_model_solver_helpers", + srcs = ["cp_model_solver_helpers.cc"], + hdrs = ["cp_model_solver_helpers.h"], + deps = [ + ":circuit", + ":clause", + ":cp_model_cc_proto", + ":cp_model_checker", + ":cp_model_lns", + ":cp_model_loader", + ":cp_model_mapping", + ":cp_model_postsolve", + ":cp_model_presolve", + ":cp_model_search", + ":cp_model_solver_helpers", + ":cp_model_symmetries", + ":cp_model_utils", + ":cuts", + ":feasibility_jump", + ":feasibility_pump", + ":implied_bounds", + ":integer", + ":integer_expr", + ":integer_search", + ":intervals", + ":lb_tree_search", + ":linear_constraint", + ":linear_model", + ":linear_programming_constraint", + ":linear_relaxation", + ":lp_utils", + ":max_hs", + ":model", + ":optimization", + ":parameters_validation", + ":precedences", + ":presolve_context", + ":probing", + ":rins", + ":sat_base", + ":sat_inprocessing", + ":sat_parameters_cc_proto", + ":sat_solver", + ":shaving_solver", + ":simplification", + ":stat_tables", + ":subsolver", + ":synchronization", + ":util", + ":work_assignment", + "//ortools/base", + "//ortools/base:status_macros", + "//ortools/base:strong_vector", + "//ortools/base:timer", + "//ortools/base:types", + "//ortools/graph:connected_components", + "//ortools/linear_solver:linear_solver_cc_proto", + "//ortools/port:proto_utils", + "//ortools/util:logging", + "//ortools/util:random_engine", + "//ortools/util:sorted_interval_list", + "//ortools/util:strong_integers", + "//ortools/util:time_limit", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/cleanup", + "@com_google_absl//absl/container:btree", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/container:inlined_vector", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/log", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/meta:type_traits", + "@com_google_absl//absl/random:distributions", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + "@com_google_protobuf//:protobuf", + ], +) + +cc_library( + name = "shaving_solver", + srcs = ["shaving_solver.cc"], + hdrs = ["shaving_solver.h"], + deps = [ + ":cp_model_cc_proto", + ":cp_model_lns", + ":cp_model_presolve", + ":cp_model_solver_helpers", + ":cp_model_utils", + ":integer", + ":model", + ":presolve_context", + ":sat_parameters_cc_proto", + ":subsolver", + ":synchronization", + ":util", + "//ortools/graph:connected_components", + "//ortools/util:sorted_interval_list", + "//ortools/util:time_limit", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/log", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/random:distributions", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", + ], +) + cc_library( name = "cp_model_solver", srcs = ["cp_model_solver.cc"], diff --git a/ortools/sat/cp_model_presolve.cc b/ortools/sat/cp_model_presolve.cc index cf1cdc0c050..66aeb9bd342 100644 --- a/ortools/sat/cp_model_presolve.cc +++ b/ortools/sat/cp_model_presolve.cc @@ -7187,6 +7187,9 @@ void CpModelPresolver::Probe() { } probing_timer->AddCounter("fixed_bools", num_fixed); + DetectDuplicateConstraintsWithDifferentEnforcements( + mapping, implication_graph, model.GetOrCreate()); + int num_equiv = 0; int num_changed_bounds = 0; const int num_variables = context_->working_model->variables().size(); @@ -8984,6 +8987,35 @@ void CpModelPresolver::DetectDuplicateConstraintsWithDifferentEnforcements( continue; } + // If we have a trail, we can check if any variable of the enforcement is + // fixed to false. This is useful for what follows since calling + // implication_graph->DirectImplications() is invalid for fixed variables. + if (trail != nullptr) { + bool found_false_enforcement = false; + for (const int c : {dup, rep}) { + for (const int l : + context_->working_model->constraints(c).enforcement_literal()) { + if (trail->Assignment().LiteralIsFalse(mapping->Literal(l))) { + found_false_enforcement = true; + break; + } + } + if (found_false_enforcement) { + context_->UpdateRuleStats("enforcement: false literal"); + if (c == rep) { + rep_ct->Swap(dup_ct); + context_->UpdateConstraintVariableUsage(rep); + } + dup_ct->Clear(); + context_->UpdateConstraintVariableUsage(dup); + break; + } + } + if (found_false_enforcement) { + continue; + } + } + // If one of them has no enforcement, then the other can be ignored. // We always keep rep, but clear its enforcement if any. if (dup_ct->enforcement_literal().empty() || @@ -12530,6 +12562,43 @@ void ModelCopy::AddLinearConstraintForInterval(const ConstraintProto& ct) { } } +void ModelCopy::AddLinearConstraintForInterval(const ConstraintProto& ct) { + // Add the linear constraint enforcement => (start + size == end). + // + // We rely on the presolve for simplification, but deal with the trivial + // case of (start, offset, start + offset) here. + const IntervalConstraintProto& itv = ct.interval(); + if (itv.size().vars().empty() && + itv.start().offset() + itv.size().offset() == itv.end().offset() && + absl::Span(itv.start().vars()) == + absl::Span(itv.end().vars()) && + absl::Span(itv.start().coeffs()) == + absl::Span(itv.end().coeffs())) { + // Trivial constraint, nothing to do. + } else { + ConstraintProto* new_ct = context_->working_model->add_constraints(); + *new_ct->mutable_enforcement_literal() = ct.enforcement_literal(); + + LinearConstraintProto* mutable_linear = new_ct->mutable_linear(); + mutable_linear->add_domain(0); + mutable_linear->add_domain(0); + AddLinearExpressionToLinearConstraint(itv.start(), 1, mutable_linear); + AddLinearExpressionToLinearConstraint(itv.size(), 1, mutable_linear); + AddLinearExpressionToLinearConstraint(itv.end(), -1, mutable_linear); + } + + // An enforced interval must have is size non-negative. + const LinearExpressionProto& size_expr = itv.size(); + if (context_->MinOf(size_expr) < 0) { + ConstraintProto* new_ct = context_->working_model->add_constraints(); + *new_ct->mutable_enforcement_literal() = ct.enforcement_literal(); + *new_ct->mutable_linear()->mutable_vars() = size_expr.vars(); + *new_ct->mutable_linear()->mutable_coeffs() = size_expr.coeffs(); + new_ct->mutable_linear()->add_domain(-size_expr.offset()); + new_ct->mutable_linear()->add_domain(std::numeric_limits::max()); + } +} + void ModelCopy::CopyAndMapNoOverlap(const ConstraintProto& ct) { // Note that we don't copy names or enforcement_literal (not supported) here. auto* new_ct = diff --git a/ortools/sat/csharp/SatSolverTests.cs b/ortools/sat/csharp/SatSolverTests.cs index 6d18a08d5ac..dfdb4ae5e5e 100644 --- a/ortools/sat/csharp/SatSolverTests.cs +++ b/ortools/sat/csharp/SatSolverTests.cs @@ -794,5 +794,25 @@ public void TestHint() Assert.Equal(2, model.Model.SolutionHint.Vars[2]); Assert.Equal(1, model.Model.SolutionHint.Values[2]); } + + [Fact] + public void TestHint() + { + output_.WriteLine("TestHint test"); + CpModel model = new CpModel(); + IntVar v = model.NewIntVar(-10, 10, "v"); + BoolVar b = model.NewBoolVar("b"); + BoolVar c = model.NewBoolVar("c"); + model.AddHint(v, 3); + model.AddHint(b, false); + model.AddHint(c.Not(), false); + Assert.Equal(3, model.Model.SolutionHint.Vars.Count); + Assert.Equal(0, model.Model.SolutionHint.Vars[0]); + Assert.Equal(3, model.Model.SolutionHint.Values[0]); + Assert.Equal(1, model.Model.SolutionHint.Vars[1]); + Assert.Equal(0, model.Model.SolutionHint.Values[1]); + Assert.Equal(2, model.Model.SolutionHint.Vars[2]); + Assert.Equal(1, model.Model.SolutionHint.Values[2]); + } } } // namespace Google.OrTools.Tests diff --git a/ortools/sat/cuts.h b/ortools/sat/cuts.h index 28359dc474c..8a15e8da780 100644 --- a/ortools/sat/cuts.h +++ b/ortools/sat/cuts.h @@ -544,6 +544,11 @@ class CoverCutHelper { CutData bool_base_ct_; int bool_cover_size_ = 0; + // Hack to not sort twice. + bool has_bool_base_ct_ = false; + CutData bool_base_ct_; + int bool_cover_size_ = 0; + // Stats. SharedStatistics* shared_stats_ = nullptr; int64_t num_lifting_ = 0; diff --git a/ortools/sat/linear_programming_constraint.h b/ortools/sat/linear_programming_constraint.h index 093e68de9af..e335165d6fd 100644 --- a/ortools/sat/linear_programming_constraint.h +++ b/ortools/sat/linear_programming_constraint.h @@ -539,6 +539,8 @@ class LinearProgrammingConstraint : public PropagatorInterface, int watcher_id_; + int watcher_id_; + BoolRLTCutHelper rlt_cut_helper_; // Used while deriving cuts. diff --git a/ortools/sat/samples/BUILD.bazel b/ortools/sat/samples/BUILD.bazel index 95de48b8098..b32270d2d4a 100644 --- a/ortools/sat/samples/BUILD.bazel +++ b/ortools/sat/samples/BUILD.bazel @@ -22,6 +22,8 @@ load( code_sample_py(name = "all_different_except_zero_sample_sat") +code_sample_py(name = "all_different_except_zero_sample_sat") + code_sample_cc_py(name = "assignment_sat") code_sample_cc_py(name = "assignment_groups_sat") diff --git a/patches/highs.patch b/patches/highs.patch new file mode 100644 index 00000000000..5975d50788b --- /dev/null +++ b/patches/highs.patch @@ -0,0 +1,88 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 22b0048cd..e8beb5db0 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -50,7 +50,7 @@ endif() + + option(PYTHON_BUILD_SETUP "Build Python interface from setup.py" OFF) + message(STATUS "Build Python: ${PYTHON_BUILD_SETUP}") +-if (PYTHON_BUILD_SETUP) ++if (PYTHON_BUILD_SETUP) + set(BUILD_CXX OFF) + set(BUILD_TESTING OFF) + endif() +@@ -64,7 +64,7 @@ message(STATUS "Build all tests: ${ALL_TESTS}") + + option(ZLIB "ZLIB" ON) + message(STATUS "ZLIB: ${ZLIB}") +-if (PYTHON_BUILD_SETUP) ++if (PYTHON_BUILD_SETUP) + set(ZLIB OFF) + endif() + +@@ -181,7 +181,7 @@ if (BUILD_CXX) + endif() + endif() + +-endif() ++endif() + + include(CheckCXXSourceCompiles) + check_cxx_source_compiles( +@@ -297,7 +297,7 @@ if(MSVC) + add_compile_options("$<$:-D_CRT_SECURE_NO_WARNINGS>") + add_compile_options("$<$:/MP>") + +- # Try to split large pdb files into objects. ++ # Try to split large pdb files into objects. + # https://github.com/tensorflow/tensorflow/issues/31610 + add_compile_options("/Z7") + add_link_options("/DEBUG:FASTLINK") +@@ -353,7 +353,7 @@ endif() + # set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined") + + # if zlib is found, then we can enable reading zlib-compressed input +-if(ZLIB) ++if(ZLIB AND NOT TARGET ZLIB::ZLIB) + find_package(ZLIB 1.2.3) + endif() + +@@ -455,7 +455,7 @@ if(NOT FAST_BUILD) + COMMENT "Resetting code coverage counters to zero.") + endif() + endif() +- ++ + include_directories( + ${HIGHS_BINARY_DIR} + ${HIGHS_SOURCE_DIR}/app +@@ -496,7 +496,7 @@ if(NOT FAST_BUILD) + + else(FAST_BUILD) + message(STATUS "FAST_BUILD set to on.") +- ++ + option(BUILD_EXAMPLES "Build examples" ON) + message(STATUS "Build examples: ${BUILD_EXAMPLES}") + +diff --git a/cmake/sources.cmake b/cmake/sources.cmake +index cdf109699..e9e1362af 100644 +--- a/cmake/sources.cmake ++++ b/cmake/sources.cmake +@@ -128,7 +128,7 @@ set(ipx_sources + ipm/ipx/symbolic_invert.cc + ipm/ipx/timer.cc + ipm/ipx/utils.cc) +- ++ + set(ipx_headers + ipm/ipx/basiclu_kernel.h + ipm/ipx/basiclu_wrapper.h +@@ -186,6 +186,7 @@ set(highs_sources + lp_data/HighsDebug.cpp + lp_data/HighsInfo.cpp + lp_data/HighsInfoDebug.cpp ++ lp_data/HighsDeprecated.cpp + lp_data/HighsInterface.cpp + lp_data/HighsLp.cpp + lp_data/HighsLpUtils.cpp diff --git a/patches/protobuf-v26.1.patch b/patches/protobuf-v26.1.patch new file mode 100644 index 00000000000..1d8ab93f39f --- /dev/null +++ b/patches/protobuf-v26.1.patch @@ -0,0 +1,75 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +<<<<<<<< HEAD:patches/protobuf-v28.2.patch +index 807ef014..8937d5eb 100644 +======== +index 312eeb928..3e154785b 100644 +>>>>>>>> a095a4b836 ([YJ] knitro branch sqaush):patches/protobuf-v26.1.patch +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -42,7 +42,7 @@ else (BUILD_SHARED_LIBS) + endif (BUILD_SHARED_LIBS) + option(protobuf_BUILD_SHARED_LIBS "Build Shared Libraries" ${protobuf_BUILD_SHARED_LIBS_DEFAULT}) + include(CMakeDependentOption) +-cmake_dependent_option(protobuf_MSVC_STATIC_RUNTIME "Link static runtime libraries" ON ++cmake_dependent_option(protobuf_MSVC_STATIC_RUNTIME "Link static runtime libraries" OFF + "NOT protobuf_BUILD_SHARED_LIBS" OFF) + set(protobuf_WITH_ZLIB_DEFAULT ON) + option(protobuf_WITH_ZLIB "Build with zlib support" ${protobuf_WITH_ZLIB_DEFAULT}) +@@ -160,24 +160,16 @@ endif() + + set(_protobuf_FIND_ZLIB) + if (protobuf_WITH_ZLIB) +- find_package(ZLIB) +- if (ZLIB_FOUND) +- set(HAVE_ZLIB 1) +- # FindZLIB module define ZLIB_INCLUDE_DIRS variable +- # Set ZLIB_INCLUDE_DIRECTORIES for compatible +- set(ZLIB_INCLUDE_DIRECTORIES ${ZLIB_INCLUDE_DIRECTORIES} ${ZLIB_INCLUDE_DIRS}) +- # Using imported target if exists +- if (TARGET ZLIB::ZLIB) +- set(ZLIB_LIBRARIES ZLIB::ZLIB) +- set(_protobuf_FIND_ZLIB "if(NOT ZLIB_FOUND)\n find_package(ZLIB)\nendif()") +- endif (TARGET ZLIB::ZLIB) +- else (ZLIB_FOUND) +- set(HAVE_ZLIB 0) +- # Explicitly set these to empty (override NOT_FOUND) so cmake doesn't +- # complain when we use them later. +- set(ZLIB_INCLUDE_DIRECTORIES) +- set(ZLIB_LIBRARIES) +- endif (ZLIB_FOUND) ++ if (NOT TARGET ZLIB::ZLIB) ++ find_package(ZLIB REQUIRED) ++ endif() ++ set(HAVE_ZLIB 1) ++ # FindZLIB module define ZLIB_INCLUDE_DIRS variable ++ # Set ZLIB_INCLUDE_DIRECTORIES for compatible ++ set(ZLIB_INCLUDE_DIRECTORIES ${ZLIB_INCLUDE_DIRECTORIES} ${ZLIB_INCLUDE_DIRS}) ++ # Using imported target if exists ++ set(ZLIB_LIBRARIES ZLIB::ZLIB) ++ set(_protobuf_FIND_ZLIB "if(NOT ZLIB_FOUND AND NOT TARGET ZLIB::ZLIB)\n find_package(ZLIB REQUIRED)\nendif()") + endif (protobuf_WITH_ZLIB) + + # We need to link with libatomic on systems that do not have builtin atomics, or +@@ -279,7 +271,6 @@ else (MSVC) + endif (MSVC) + + include_directories( +- ${ZLIB_INCLUDE_DIRECTORIES} + ${protobuf_BINARY_DIR} + # Support #include-ing other top-level directories, i.e. upb_generator. + ${protobuf_SOURCE_DIR} +<<<<<<<< HEAD:patches/protobuf-v28.2.patch +======== +diff --git a/cmake/install.cmake b/cmake/install.cmake +index 52914a8ea..d7dc5f232 100644 +--- a/cmake/install.cmake ++++ b/cmake/install.cmake +@@ -31,6 +31,7 @@ foreach(_library ${_protobuf_libraries}) + set_property(TARGET ${_library} + PROPERTY INTERFACE_INCLUDE_DIRECTORIES + $ ++ $ + $) + if (UNIX AND NOT APPLE) + set_property(TARGET ${_library} +>>>>>>>> a095a4b836 ([YJ] knitro branch sqaush):patches/protobuf-v26.1.patch diff --git a/patches/protobuf-v28.2.patch b/patches/protobuf-v28.2.patch index 331e0267979..1d8ab93f39f 100644 --- a/patches/protobuf-v28.2.patch +++ b/patches/protobuf-v28.2.patch @@ -1,5 +1,9 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt +<<<<<<<< HEAD:patches/protobuf-v28.2.patch index 807ef014..8937d5eb 100644 +======== +index 312eeb928..3e154785b 100644 +>>>>>>>> a095a4b836 ([YJ] knitro branch sqaush):patches/protobuf-v26.1.patch --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,7 @@ else (BUILD_SHARED_LIBS) @@ -54,3 +58,18 @@ index 807ef014..8937d5eb 100644 ${protobuf_BINARY_DIR} # Support #include-ing other top-level directories, i.e. upb_generator. ${protobuf_SOURCE_DIR} +<<<<<<<< HEAD:patches/protobuf-v28.2.patch +======== +diff --git a/cmake/install.cmake b/cmake/install.cmake +index 52914a8ea..d7dc5f232 100644 +--- a/cmake/install.cmake ++++ b/cmake/install.cmake +@@ -31,6 +31,7 @@ foreach(_library ${_protobuf_libraries}) + set_property(TARGET ${_library} + PROPERTY INTERFACE_INCLUDE_DIRECTORIES + $ ++ $ + $) + if (UNIX AND NOT APPLE) + set_property(TARGET ${_library} +>>>>>>>> a095a4b836 ([YJ] knitro branch sqaush):patches/protobuf-v26.1.patch