diff --git a/.github/workflows/dockercentos.yml b/.github/workflows/dockercentos.yml index 2494213d5..e3d613a26 100644 --- a/.github/workflows/dockercentos.yml +++ b/.github/workflows/dockercentos.yml @@ -18,11 +18,13 @@ jobs: fail-fast: false matrix: cfg: - - { img: 'lebarsfa/manylinux_2_28_x86_64-for-codac' , os: ubuntu-latest , shell: bash, arch: x86_64 , bitness: 64, runtime: manylinux_2_28, min_python: '3.14', max_python: ' ', desc: 'CentOS manylinux_2_28 x86_64 Python >=3.14' } + - { img: 'lebarsfa/manylinux_2_28_x86_64-for-codac' , os: ubuntu-latest , shell: bash, arch: x86_64 , bitness: 64, runtime: manylinux_2_28, min_python: '3.15', max_python: ' ', desc: 'CentOS manylinux_2_28 x86_64 Python >=3.15' } + - { img: 'lebarsfa/manylinux_2_28_x86_64-for-codac' , os: ubuntu-latest , shell: bash, arch: x86_64 , bitness: 64, runtime: manylinux_2_28, min_python: '3.14', max_python: '3.14', desc: 'CentOS manylinux_2_28 x86_64 Python 3.14' } - { img: 'lebarsfa/manylinux_2_28_x86_64-for-codac' , os: ubuntu-latest , shell: bash, arch: x86_64 , bitness: 64, runtime: manylinux_2_28, min_python: '3.13', max_python: '3.13', desc: 'CentOS manylinux_2_28 x86_64 Python 3.13' } - { img: 'lebarsfa/manylinux_2_28_x86_64-for-codac' , os: ubuntu-latest , shell: bash, arch: x86_64 , bitness: 64, runtime: manylinux_2_28, min_python: '3.11', max_python: '3.12', desc: 'CentOS manylinux_2_28 x86_64 Python 3.11-3.12' } - { img: 'lebarsfa/manylinux_2_28_x86_64-for-codac' , os: ubuntu-latest , shell: bash, arch: x86_64 , bitness: 64, runtime: manylinux_2_28, min_python: ' ', max_python: '3.10', desc: 'CentOS manylinux_2_28 x86_64 Python <=3.10' } - - { img: 'lebarsfa/manylinux_2_28_aarch64-for-codac', os: ubuntu-24.04-arm , shell: bash, arch: aarch64, bitness: 64, runtime: manylinux_2_28, min_python: '3.14', max_python: ' ', docker_flags: '--platform linux/arm64', desc: 'CentOS manylinux_2_28 aarch64 Python >=3.14' } + - { img: 'lebarsfa/manylinux_2_28_aarch64-for-codac', os: ubuntu-24.04-arm , shell: bash, arch: aarch64, bitness: 64, runtime: manylinux_2_28, min_python: '3.15', max_python: ' ', docker_flags: '--platform linux/arm64', desc: 'CentOS manylinux_2_28 aarch64 Python >=3.15' } + - { img: 'lebarsfa/manylinux_2_28_aarch64-for-codac', os: ubuntu-24.04-arm , shell: bash, arch: aarch64, bitness: 64, runtime: manylinux_2_28, min_python: '3.14', max_python: '3.14', docker_flags: '--platform linux/arm64', desc: 'CentOS manylinux_2_28 aarch64 Python 3.14' } - { img: 'lebarsfa/manylinux_2_28_aarch64-for-codac', os: ubuntu-24.04-arm , shell: bash, arch: aarch64, bitness: 64, runtime: manylinux_2_28, min_python: '3.13', max_python: '3.13', docker_flags: '--platform linux/arm64', desc: 'CentOS manylinux_2_28 aarch64 Python 3.13' } - { img: 'lebarsfa/manylinux_2_28_aarch64-for-codac', os: ubuntu-24.04-arm , shell: bash, arch: aarch64, bitness: 64, runtime: manylinux_2_28, min_python: '3.11', max_python: '3.12', docker_flags: '--platform linux/arm64', desc: 'CentOS manylinux_2_28 aarch64 Python 3.11-3.12' } - { img: 'lebarsfa/manylinux_2_28_aarch64-for-codac', os: ubuntu-24.04-arm , shell: bash, arch: aarch64, bitness: 64, runtime: manylinux_2_28, min_python: ' ', max_python: '3.10', docker_flags: '--platform linux/arm64', desc: 'CentOS manylinux_2_28 aarch64 Python <=3.10' } diff --git a/.github/workflows/dockermatrix.yml b/.github/workflows/dockermatrix.yml index 5045d0245..6a0452741 100644 --- a/.github/workflows/dockermatrix.yml +++ b/.github/workflows/dockermatrix.yml @@ -68,7 +68,7 @@ jobs: # if: (matrix.cfg.arch!='amd64')&&(matrix.cfg.arch!='x86_64')&&(matrix.cfg.arch!='i386') - run: | docker run ${{ matrix.cfg.docker_flags }} -i -v "${PWD}/..:${PWD}/.." ${{ matrix.cfg.img }} /bin/bash -c "uname -a ; cat /etc/os-release ; lsb_release -a ; cd ${PWD} && pwd && \ - git config --global --add safe.directory ${PWD} && \ + git config --global --add safe.directory ${PWD} && git config --global --add safe.directory ${PWD}/.git || true && \ if [ \"${{ matrix.cfg.deb }}\" = \"true\" ]; then \ sudo sh -c 'echo \"deb [trusted=yes] https://webperso.ensta.fr/packages/\$(if [ -z \"\$(. /etc/os-release && echo \$UBUNTU_CODENAME)\" ]; then echo debian/\$(. /etc/os-release && echo \$VERSION_CODENAME); else echo ubuntu/\$(. /etc/os-release && echo \$UBUNTU_CODENAME); fi) ./\" > /etc/apt/sources.list.d/ensta-bretagne.list' && \ #sudo apt-get -q update ; sudo apt-get -y install libeigen3-dev catch2 dpkg-dev || true && \\ diff --git a/.github/workflows/macosmatrix.yml b/.github/workflows/macosmatrix.yml index 3fe504024..b0460ef7b 100644 --- a/.github/workflows/macosmatrix.yml +++ b/.github/workflows/macosmatrix.yml @@ -21,10 +21,12 @@ jobs: fail-fast: false matrix: cfg: - - { os: macos-14 , shell: bash, arch: arm64 , runtime: sonoma , cmake_flags: '-fPIC', trgt: '11.0' , cpcfg: '-macosx_11_0_arm64' , py_v_maj: 3, py_v_min: 14, desc: 'macOS Sonoma Python 3.14 arm64' } - - { os: macos-14 , shell: bash, arch: arm64 , runtime: sonoma , cmake_flags: '-fPIC', trgt: '11.0' , cpcfg: '-macosx_11_0_arm64' , py_v_maj: 3, py_v_min: 13, desc: 'macOS Sonoma Python 3.13 arm64' } - - { os: macos-14 , shell: bash, arch: arm64 , runtime: sonoma , cmake_flags: '-fPIC', trgt: '11.0' , cpcfg: '-macosx_11_0_arm64' , py_v_maj: 3, py_v_min: 12, desc: 'macOS Sonoma Python 3.12 arm64' } - - { os: macos-14 , shell: bash, arch: arm64 , runtime: sonoma , cmake_flags: '-fPIC', trgt: '11.0' , cpcfg: '-macosx_11_0_arm64' , py_v_maj: 3, py_v_min: 11, desc: 'macOS Sonoma Python 3.11 arm64' } + - { os: macos-15 , shell: bash, arch: arm64 , runtime: sonoma , cmake_flags: '-fPIC', trgt: '11.0' , cpcfg: '-macosx_11_0_arm64' , py_v_maj: 3, py_v_min: 15, desc: 'macOS Sequoia Python 3.15 arm64' } + - { os: macos-15 , shell: bash, arch: arm64 , runtime: sonoma , cmake_flags: '-fPIC', trgt: '11.0' , cpcfg: '-macosx_11_0_arm64' , py_v_maj: 3, py_v_min: 14, desc: 'macOS Sequoia Python 3.14 arm64' } + - { os: macos-15 , shell: bash, arch: arm64 , runtime: sonoma , cmake_flags: '-fPIC', trgt: '11.0' , cpcfg: '-macosx_11_0_arm64' , py_v_maj: 3, py_v_min: 13, desc: 'macOS Sequoia Python 3.13 arm64' } + - { os: macos-15 , shell: bash, arch: arm64 , runtime: sonoma , cmake_flags: '-fPIC', trgt: '11.0' , cpcfg: '-macosx_11_0_arm64' , py_v_maj: 3, py_v_min: 12, desc: 'macOS Sequoia Python 3.12 arm64' } + - { os: macos-15 , shell: bash, arch: arm64 , runtime: sonoma , cmake_flags: '-fPIC', trgt: '11.0' , cpcfg: '-macosx_11_0_arm64' , py_v_maj: 3, py_v_min: 11, desc: 'macOS Sequoia Python 3.11 arm64' } + - { os: macos-15-intel , shell: bash, arch: x86_64 , runtime: sequoia , cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 15, desc: 'macOS Sequoia Python 3.15 x86_64' } - { os: macos-15-intel , shell: bash, arch: x86_64 , runtime: sequoia , cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 14, desc: 'macOS Sequoia Python 3.14 x86_64' } - { os: macos-15-intel , shell: bash, arch: x86_64 , runtime: sequoia , cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 13, desc: 'macOS Sequoia Python 3.13 x86_64' } - { os: macos-15-intel , shell: bash, arch: x86_64 , runtime: sequoia , cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 12, desc: 'macOS Sequoia Python 3.12 x86_64' } @@ -54,54 +56,11 @@ jobs: # if: runner.os=='macOS' - run: brew install catch2 # Issues with binary packages when cross-compiling... if: (runner.os=='macOS')&&(matrix.cfg.cross!=true) - # Doxygen 1.18.0 crashes when parsing Codac headers on macOS. - # Doxygen 1.16.1 ARM64 binaries require macOS 15: build from source on macOS 14. - - name: Install Doxygen 1.16.1 - shell: bash - env: - GH_TOKEN: ${{ github.token }} - run: | - set -euo pipefail - case "${{ matrix.cfg.arch }}" in - arm64) archive="doxygen-1.16.1.src.tar.gz" ;; - x86_64) archive="doxygen-1.16.1-mac-intel.zip" ;; - *) echo "Unsupported architecture" >&2; exit 1 ;; - esac - tmpdir="$(mktemp -d)" - trap 'rm -rf "$tmpdir"' EXIT - - # Verify the archive using its official GitHub release SHA-256 digest. - expected_sha="$( - curl -fsSL --retry 3 \ - -H "Authorization: Bearer ${GH_TOKEN}" \ - -H "Accept: application/vnd.github+json" \ - https://api.github.com/repos/doxygen/doxygen/releases/tags/Release_1_16_1 \ - | python3 -c 'import json,sys; a=next(x for x in json.load(sys.stdin)["assets"] if x["name"]==sys.argv[1]); d=a["digest"]; assert d and d.startswith("sha256:") and len(d)==71; print(d[7:])' "$archive" - )" - curl -fsSL --retry 3 \ - "https://github.com/doxygen/doxygen/releases/download/Release_1_16_1/${archive}" \ - -o "$tmpdir/$archive" - echo "${expected_sha} ${tmpdir}/${archive}" | shasum -a 256 -c - - if [[ "${{ matrix.cfg.arch }}" == arm64 ]]; then - brew install ninja flex bison - mkdir "$tmpdir/src" - tar -xzf "$tmpdir/$archive" -C "$tmpdir/src" - export PATH="$(brew --prefix flex)/bin:$(brew --prefix bison)/bin:$PATH" - cmake -G Ninja -S "$tmpdir/src/doxygen-1.16.1" -B "$tmpdir/build" \ - -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \ - -Dbuild_wizard=OFF -Dbuild_doc=OFF -Duse_libclang=OFF - cmake --build "$tmpdir/build" --target doxygen --parallel 4 - doxygen_bin="$tmpdir/build/bin/doxygen" - else - unzip -q "$tmpdir/$archive" -d "$tmpdir/unpacked" - doxygen_bin="$(find "$tmpdir/unpacked" -type f -name doxygen -print -quit)" - fi - - mkdir -p "$RUNNER_TEMP/codac-doxygen-bin" - install -m 755 "$doxygen_bin" "$RUNNER_TEMP/codac-doxygen-bin/doxygen" - echo "$RUNNER_TEMP/codac-doxygen-bin" >> "$GITHUB_PATH" - "$RUNNER_TEMP/codac-doxygen-bin/doxygen" --version + # Doxygen 1.18.0 crashes when parsing Codac headers on macOS. + - run: | + wget https://github.com/lebarsfa/xbrew/releases/latest/download/xbrew.sh --no-check-certificate -nv ; sudo mv -f xbrew.sh /usr/local/bin/xbrew ; sudo chmod +x /usr/local/bin/xbrew + xbrew reinstall https://github.com/Homebrew/homebrew-core/raw/1d8f87380f143b838b0d6a10068e7488db79ba5d/Formula/d/doxygen.rb ; brew pin --formula doxygen + if: runner.os=='macOS' - run: brew install graphviz ; python -m pip install --upgrade pip ; pip install --upgrade wheel setuptools sphinx breathe sphinx_rtd_theme sphinx-tabs sphinx-issues sphinx-reredirects furo sphinx-math-dollar sphinx_togglebutton sympy if: runner.os=='macOS' - run: | diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index 9c5bb18f7..648d545e1 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -28,10 +28,10 @@ jobs: fail-fast: false matrix: cfg: - - { os: windows-11-vs2026-arm, shell: cmd , arch: arm64 , bitness: 64, runtime: vc18 , cmake_params: '-G "Visual Studio 18" -T v145 -A arm64', cmake_flags: ' /MP4 /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', desc: 'Windows Visual Studio 2026 arm64' } + - { os: windows-11-arm , shell: cmd , arch: arm64 , bitness: 64, runtime: vc18 , cmake_params: '-G "Visual Studio 18" -T v145 -A arm64', cmake_flags: ' /MP4 /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', desc: 'Windows Visual Studio 2026 arm64' } - { os: windows-2025-vs2026 , shell: cmd , arch: x64 , bitness: 64, runtime: vc18 , cmake_params: '-G "Visual Studio 18" -T v145 -A x64' , cmake_flags: ' /MP4 /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', desc: 'Windows Visual Studio 2026 x64' } - { os: windows-2025-vs2026 , shell: cmd , arch: x86 , bitness: 32, runtime: vc18 , cmake_params: '-G "Visual Studio 18" -T v145 -A Win32', cmake_flags: ' /MP4 /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', choco_flags: '--x86', desc: 'Windows Visual Studio 2026 x86' } - - { os: windows-11-arm , shell: cmd , arch: arm64 , bitness: 64, runtime: vc17 , cmake_params: '-G "Visual Studio 18 2026" -T v143 -A arm64', cmake_flags: ' /MP4 /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', desc: 'Windows Visual Studio 2026 arm64 (v143)' } + - { os: windows-11-arm , shell: cmd , arch: arm64 , bitness: 64, runtime: vc17 , cmake_params: '-G "Visual Studio 18" -T v143 -A arm64', cmake_flags: ' /MP4 /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', desc: 'Windows Visual Studio 2022 arm64' } - { os: windows-2022 , shell: cmd , arch: x64 , bitness: 64, runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A x64' , cmake_flags: ' /MP4 /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', desc: 'Windows Visual Studio 2022 x64' } - { os: windows-2022 , shell: cmd , arch: x86 , bitness: 32, runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', cmake_flags: ' /MP4 /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', choco_flags: '--x86', desc: 'Windows Visual Studio 2022 x86' } # Problems related to C++20 for Visual Studio 2019 and earlier? @@ -62,12 +62,12 @@ jobs: - { os: ubuntu-24.04-arm , shell: bash, arch: arm64 , bitness: 64, runtime: noble , cmake_flags: '-fPIC', deb: true, desc: 'Ubuntu 24.04 arm64' } - { os: ubuntu-22.04 , shell: bash, arch: amd64 , bitness: 64, runtime: jammy , cmake_flags: '-fPIC', deb: true, desc: 'Ubuntu 22.04 amd64' } - { os: ubuntu-22.04-arm , shell: bash, arch: arm64 , bitness: 64, runtime: jammy , cmake_flags: '-fPIC', deb: true, desc: 'Ubuntu 22.04 arm64' } + - { os: xcode-27 , shell: bash, arch: arm64 , bitness: 64, runtime: goldengate , cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=arm64' , cmake_flags: '-fPIC', desc: 'macOS Golden Gate arm64' } + - { os: xcode-27 , shell: bash, arch: x86_64 , bitness: 64, runtime: goldengate , cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=x86_64 -D CMAKE_OSX_DEPLOYMENT_TARGET=27.0', cmake_flags: '-fPIC', cross: true, desc: 'macOS Golden Gate x86_64 (cross)' } - { os: macos-26 , shell: bash, arch: arm64 , bitness: 64, runtime: tahoe , cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=arm64' , cmake_flags: '-fPIC', desc: 'macOS Tahoe arm64' } - - { os: macos-26 , shell: bash, arch: x86_64 , bitness: 64, runtime: tahoe , cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=x86_64 -D CMAKE_OSX_DEPLOYMENT_TARGET=26.0', cmake_flags: '-fPIC', cross: true, desc: 'macOS Tahoe x86_64 (cross)' } + - { os: macos-26-intel , shell: bash, arch: x86_64 , bitness: 64, runtime: tahoe , cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=x86_64', cmake_flags: '-fPIC', desc: 'macOS Tahoe x86_64' } - { os: macos-15 , shell: bash, arch: arm64 , bitness: 64, runtime: sequoia , cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=arm64' , cmake_flags: '-fPIC', desc: 'macOS Sequoia arm64' } - { os: macos-15-intel , shell: bash, arch: x86_64 , bitness: 64, runtime: sequoia , cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=x86_64', cmake_flags: '-fPIC', desc: 'macOS Sequoia x86_64' } - - { os: macos-14 , shell: bash, arch: arm64 , bitness: 64, runtime: sonoma , cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=arm64' , cmake_flags: '-fPIC', desc: 'macOS Sonoma arm64' } - - { os: macos-14 , shell: bash, arch: x86_64 , bitness: 64, runtime: sonoma , cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=x86_64 -D CMAKE_OSX_DEPLOYMENT_TARGET=14.0', cmake_flags: '-fPIC', cross: true, desc: 'macOS Sonoma x86_64 (cross)' } name: ${{ matrix.cfg.desc }} steps: - uses: actions/checkout@v7 diff --git a/.github/workflows/vcmatrix.yml b/.github/workflows/vcmatrix.yml index e7997f6d3..439ddde90 100644 --- a/.github/workflows/vcmatrix.yml +++ b/.github/workflows/vcmatrix.yml @@ -19,6 +19,7 @@ jobs: matrix: cfg: # Should be Visual Studio 2015 for Python 3.5-3.7, Visual Studio 2019 for Python 3.8-3.10, but need at least Visual Studio 2022 for C++20 compatibility...? + - { os: windows-2022 , shell: cmd , arch: x86 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 15, desc: 'Windows Visual Studio 2022 x86 Python 3.15' } - { os: windows-2022 , shell: cmd , arch: x86 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 14, desc: 'Windows Visual Studio 2022 x86 Python 3.14' } - { os: windows-2022 , shell: cmd , arch: x86 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 13, desc: 'Windows Visual Studio 2022 x86 Python 3.13' } - { os: windows-2022 , shell: cmd , arch: x86 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 12, desc: 'Windows Visual Studio 2022 x86 Python 3.12' } @@ -26,10 +27,12 @@ jobs: - { os: windows-2022 , shell: cmd , arch: x86 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 10, desc: 'Windows Visual Studio 2022 x86 Python 3.10' } - { os: windows-2022 , shell: cmd , arch: x86 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 9 , desc: 'Windows Visual Studio 2022 x86 Python 3.9' } - { os: windows-2022 , shell: cmd , arch: x86 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 8 , desc: 'Windows Visual Studio 2022 x86 Python 3.8' } - - { os: windows-11-arm , shell: cmd , arch: arm64 , runtime: vc17 , cmake_params: '-G "Visual Studio 18 2026" -T v143 -A arm64', cpcfg: '-win_arm64', py_v_maj: 3, py_v_min: 14, desc: 'Windows Visual Studio 2026 arm64 Python 3.14' } - - { os: windows-11-arm , shell: cmd , arch: arm64 , runtime: vc17 , cmake_params: '-G "Visual Studio 18 2026" -T v143 -A arm64', cpcfg: '-win_arm64', py_v_maj: 3, py_v_min: 13, desc: 'Windows Visual Studio 2026 arm64 Python 3.13' } - - { os: windows-11-arm , shell: cmd , arch: arm64 , runtime: vc17 , cmake_params: '-G "Visual Studio 18 2026" -T v143 -A arm64', cpcfg: '-win_arm64', py_v_maj: 3, py_v_min: 12, desc: 'Windows Visual Studio 2026 arm64 Python 3.12' } - - { os: windows-11-arm , shell: cmd , arch: arm64 , runtime: vc17 , cmake_params: '-G "Visual Studio 18 2026" -T v143 -A arm64', cpcfg: '-win_arm64', py_v_maj: 3, py_v_min: 11, desc: 'Windows Visual Studio 2026 arm64 Python 3.11' } + - { os: windows-11-arm , shell: cmd , arch: arm64 , runtime: vc17 , cmake_params: '-G "Visual Studio 18" -T v143 -A arm64', cpcfg: '-win_arm64', py_v_maj: 3, py_v_min: 15, desc: 'Windows Visual Studio 2022 arm64 Python 3.15' } + - { os: windows-11-arm , shell: cmd , arch: arm64 , runtime: vc17 , cmake_params: '-G "Visual Studio 18" -T v143 -A arm64', cpcfg: '-win_arm64', py_v_maj: 3, py_v_min: 14, desc: 'Windows Visual Studio 2022 arm64 Python 3.14' } + - { os: windows-11-arm , shell: cmd , arch: arm64 , runtime: vc17 , cmake_params: '-G "Visual Studio 18" -T v143 -A arm64', cpcfg: '-win_arm64', py_v_maj: 3, py_v_min: 13, desc: 'Windows Visual Studio 2022 arm64 Python 3.13' } + - { os: windows-11-arm , shell: cmd , arch: arm64 , runtime: vc17 , cmake_params: '-G "Visual Studio 18" -T v143 -A arm64', cpcfg: '-win_arm64', py_v_maj: 3, py_v_min: 12, desc: 'Windows Visual Studio 2022 arm64 Python 3.12' } + - { os: windows-11-arm , shell: cmd , arch: arm64 , runtime: vc17 , cmake_params: '-G "Visual Studio 18" -T v143 -A arm64', cpcfg: '-win_arm64', py_v_maj: 3, py_v_min: 11, desc: 'Windows Visual Studio 2022 arm64 Python 3.11' } + - { os: windows-2022 , shell: cmd , arch: x64 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A x64' , cpcfg: '-win_amd64', py_v_maj: 3, py_v_min: 15, desc: 'Windows Visual Studio 2022 x64 Python 3.15' } - { os: windows-2022 , shell: cmd , arch: x64 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A x64' , cpcfg: '-win_amd64', py_v_maj: 3, py_v_min: 14, desc: 'Windows Visual Studio 2022 x64 Python 3.14' } - { os: windows-2022 , shell: cmd , arch: x64 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A x64' , cpcfg: '-win_amd64', py_v_maj: 3, py_v_min: 13, desc: 'Windows Visual Studio 2022 x64 Python 3.13' } - { os: windows-2022 , shell: cmd , arch: x64 , runtime: vc17 , cmake_params: '-G "Visual Studio 17" -T v143 -A x64' , cpcfg: '-win_amd64', py_v_maj: 3, py_v_min: 12, desc: 'Windows Visual Studio 2022 x64 Python 3.12' } diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c727d35e..89aa66f1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ # Compilation configuration ################################################################################ + include(GNUInstallDirs) include(FetchContent) if(NOT CMAKE_BUILD_TYPE) @@ -130,23 +131,46 @@ # Looking for Eigen3 ################################################################################ - option(ENABLE_FIND_PACKAGE_EIGEN3 "ENABLE_FIND_PACKAGE_EIGEN3" OFF) - if(ENABLE_FIND_PACKAGE_EIGEN3) - find_package(Eigen3 3.4.0 QUIET) # Use Eigen3_DIR or CMAKE_PREFIX_PATH to specify a custom Eigen3 installation path... - endif() - if(Eigen3_FOUND) - message(STATUS "Found Eigen3 version ${Eigen3_VERSION} in ${Eigen3_DIR}") - else() - message(STATUS "Attempt to install custom Eigen3 automatically...") + #option(ENABLE_FIND_PACKAGE_EIGEN3 "ENABLE_FIND_PACKAGE_EIGEN3" OFF) + #if(ENABLE_FIND_PACKAGE_EIGEN3) + # find_package(Eigen3 3.4.0 QUIET) # Use Eigen3_DIR or CMAKE_PREFIX_PATH to specify a custom Eigen3 installation path... + #endif() + #if(Eigen3_FOUND) + # message(STATUS "Found Eigen3 version ${Eigen3_VERSION} in ${Eigen3_DIR}") + #else() + #message(STATUS "Attempt to get Eigen3 automatically...") + message(STATUS "Attempt to get custom Eigen3...") # Over HTTPS, not plain HTTP: the connections to port 80 of github.com timed # out now and then on the GitHub Actions runners, failing the whole job at # configuration time ("Failed to connect to github.com port 80"), and HTTPS # also guarantees that the archive comes from GitHub unaltered. FetchContent_Declare(Eigen3 URL https://github.com/codac-team/eigen/archive/refs/heads/eigen-5.0.zip) #FetchContent_Declare(Eigen3 URL ${CMAKE_CURRENT_SOURCE_DIR}/3rd/eigen-a0dc3994bd5d4e804dab58decb78c56a5af516ba.zip) # If needed to be self-contained... - FetchContent_MakeAvailable(Eigen3) - endif() - # Adds Eigen3::Eigen + # + #FetchContent_MakeAvailable(Eigen3) + # + # This avoids the install part of Eigen3 to override the system-wide Eigen3 installation if any... + cmake_policy(PUSH) + if (POLICY CMP0169) + cmake_policy(SET CMP0169 OLD) + endif() + FetchContent_Populate(Eigen3) + cmake_policy(POP) + add_library(${PROJECT_NAME}-eigen INTERFACE) + target_include_directories(${PROJECT_NAME}-eigen + INTERFACE + "$" + "$" + ) + #if (CODAC_INSTALL) + install(DIRECTORY ${eigen3_SOURCE_DIR}/unsupported/Eigen DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-eigen/unsupported) + install(DIRECTORY ${eigen3_SOURCE_DIR}/Eigen DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-eigen) + #endif() + add_library(${PROJECT_NAME}::${PROJECT_NAME}-eigen ALIAS ${PROJECT_NAME}-eigen) + # + #endif() + ## Adds Eigen3::Eigen + # Adds ${PROJECT_NAME}-eigen ################################################################################ # Looking for Threads diff --git a/doc/manual/_static/logos/logo_ensta.jpeg b/doc/manual/_static/logos/logo_ensta.jpeg new file mode 100644 index 000000000..61dabdc1e Binary files /dev/null and b/doc/manual/_static/logos/logo_ensta.jpeg differ diff --git a/doc/manual/_static/logos/logo_labsticc.jpeg b/doc/manual/_static/logos/logo_labsticc.jpeg new file mode 100644 index 000000000..9162e19ee Binary files /dev/null and b/doc/manual/_static/logos/logo_labsticc.jpeg differ diff --git a/doc/manual/index.rst b/doc/manual/index.rst index 642b81072..b64f24cf4 100644 --- a/doc/manual/index.rst +++ b/doc/manual/index.rst @@ -160,6 +160,21 @@ This list is in alphabetical order by surname. We appreciate all contributions, whether code, documentation, bug reports, or suggestions. If you believe your name should be included here and it is not, please contact us so we can update the list. +Codac is primarily developed and maintained by researchers at `Lab-STICC `_ (`Robex team `_), particularly those based at `ENSTA `_. +The project also benefits from contributions from researchers and developers at other institutions and welcomes new participants regardless of their affiliation. + +.. |labsticc-logo| image:: /_static/logos/logo_labsticc.jpeg + :width: 95px + :alt: Lab-STICC + +.. |ensta-logo| image:: /_static/logos/logo_ensta.jpeg + :width: 245px + :alt: ENSTA, Institut Polytechnique de Paris + +|labsticc-logo| |ensta-logo| + + +| Provisional Plan ^^^^^^^^^^^^^^^^ @@ -168,8 +183,6 @@ Below is a provisional outline for the structure of this manual. Some pages are already available. Please note that sections may be revised or added as the content continues to evolve. -| - Overview of Codac ----------------- @@ -193,6 +206,7 @@ User manual * :ref:`sec-intervals-class` * :ref:`sec-intervals-intervalvector-class` * :ref:`sec-intervals-boolinterval-class` + * :ref:`sec-intervals-rounding` * :ref:`sec-linear` * :ref:`sec-linear-vecmat` @@ -215,14 +229,16 @@ User manual * Extension to custom expressions * :ref:`sec-tubes-trajectories` - * :ref:`sec-trajectories-sampledtraj` - * :ref:`sec-trajectories-analytictraj` - * :ref:`sec-trajectories-operations` - * :ref:`sec-trajectories-io` - * :ref:`sec-tubes-tdomain` - * :ref:`sec-tubes-slice` - * :ref:`sec-tubes-slicedtube` - * :ref:`sec-tubes-examples` + * Trajectories + * :ref:`sec-trajectories-sampledtraj` + * :ref:`sec-trajectories-analytictraj` + * :ref:`sec-trajectories-operations` + * :ref:`sec-trajectories-io` + * Tubes + * :ref:`sec-tubes-tdomain` + * :ref:`sec-tubes-slice` + * :ref:`sec-tubes-slicedtube` + * :ref:`sec-tubes-examples` * Contractors * What are contractors? diff --git a/doc/manual/manual/installation/cpp.rst b/doc/manual/manual/installation/cpp.rst index d92dc75b9..e4bf9a3f9 100644 --- a/doc/manual/manual/installation/cpp.rst +++ b/doc/manual/manual/installation/cpp.rst @@ -100,7 +100,7 @@ Steps .. warning:: - **GAOL prerequisite:** On some platforms, you might need to install manually `MathLib `_ and `GAOL `_ with CMake and `specify where they are `_ in order to build IBEX successfully and have accurate computations. + **GAOL prerequisite:** On some platforms, you might need to install manually `MathLib `_ and `GAOL `_ with CMake and `specify where they are `_ in order to build IBEX successfully and have accurate computations. 3. **Install the Codac library**: diff --git a/doc/manual/manual/installation/matlab.rst b/doc/manual/manual/installation/matlab.rst index 02f1f7c78..aa4ae963e 100644 --- a/doc/manual/manual/installation/matlab.rst +++ b/doc/manual/manual/installation/matlab.rst @@ -28,6 +28,50 @@ Once Codac is installed, you can use it in your MATLAB scripts using the followi .. py.importlib.import_module('codac') +Known installation issues and possible workarounds +-------------------------------------------------- + +* On some configurations, you might need to use ``pip3`` instead of ``pip``, and/or ``--break-system-packages`` parameter, *e.g.* + + .. code-block:: bash + + pip3 install --break-system-packages codac4matlab + + or + + .. code-block:: bash + + python3 -m pip install --break-system-packages codac4matlab + +* In some cases, you might have multiple Python installations at different locations on your system (possibly the same Python version can be installed separately at different locations, also some versions of Python might be installed but incompatible with your version of MATLAB). In MATLAB, try to examine the output of the ``pyenv`` command to try to determine where is the Python installation that it uses and possibly run the pip install command from inside MATLAB command window with the ``!`` prefix *e.g.* ``!pip install codac4matlab``, or from a Windows Administrator command prompt with the full path to the python executable *e.g* ``"C:\Python312\python.exe" -m pip install codac4matlab``. + +* Python virtual environments compatibility has not been tested. + +* MATLAB Online: you will need to run `codac4matlabonline.m `_. Tweak it if it does not work for you. It might not be possible to view the `VIBes viewer <../visualization/vibes.html>`_ windows, possibly use the VIBes functions to save the desired pictures as a workaround. + + +MATLAB specificities +-------------------- + +* You might need to add as prefix ``py.codac4matlab.`` to class or function names, e.g. ``py.codac4matlab.Interval`` for ``Interval`` to avoid potential name conflicts with other libraries, and/or do explicitely *e.g.* ``import py.codac4matlab.Interval; import py.codac4matlab.cos;`` instead of just ``import py.codac4matlab.*`` depending on your needs. + +* When we click on a Codac variable e.g. ``IntervalVector`` (``py.codac4matlab._core.IntervalVector``), we do not get help. Please check `codac.io <../..>`_ for the documentation. Also, you can try typing *e.g.* ``X0.`` followed by the TAB key (assuming ``X0`` is a ``py.codac4matlab._core.IntervalVector``) to get a list of suggestions of properties and methods. + +.. admonition:: Note + + Check `codac4matlab_usage.m `_ example for some MATLAB specificities. + + See also `Codac v1 documentation `_ for some remaining issues and potential workarounds. + + +Python to MATLAB conversions +---------------------------- + +* Be sure that Python multiline strings are correctly converted to multiline MATLAB strings between ``'``. Remember that multiline statements in MATLAB need ``...`` before next line. + +* Please also convert Python `for` loops to typical MATLAB `for` loops, same for `if-else`, `+=` statements. + + Potential problem with VIBes ---------------------------- @@ -40,4 +84,5 @@ A solution is to avoid using ``sudo``. If required, run MATLAB with the correct .. code:: - sudo HOME=/home/your_username matlab \ No newline at end of file + sudo HOME=/home/your_username matlab + diff --git a/doc/manual/manual/intervals/Interval_class.rst b/doc/manual/manual/intervals/Interval_class.rst index 11450b9c6..e6141b76a 100644 --- a/doc/manual/manual/intervals/Interval_class.rst +++ b/doc/manual/manual/intervals/Interval_class.rst @@ -213,6 +213,8 @@ Dealing with closed intervals, most of the operations can rely on their bounds. Note that Codac is built upon a low-level interval library, `GAOL `_, which has been built to provide functionalities for computing arithmetic on intervals, involving basic operations as well as non-linear functions. +For compatibility with other C++ numerical libraries (such as OpenCV), see :ref:`Floating-point rounding and library compatibility `. + All standard arithmetic operations are supported in Codac, both element-wise and with real numbers. .. tabs:: diff --git a/doc/manual/manual/intervals/index.rst b/doc/manual/manual/intervals/index.rst index bd3078c8e..f861673ee 100644 --- a/doc/manual/manual/intervals/index.rst +++ b/doc/manual/manual/intervals/index.rst @@ -10,6 +10,9 @@ Codac provides data structures for handling basic interval sets. These structure - ``IntervalMatrix``: represents a matrix where each element is an interval. - :ref:`The BoolInterval class `: represents a Boolean interval. +For C++ applications using other numerical libraries, see +:ref:`Floating-point rounding and library compatibility `. + .. toctree:: :hidden: @@ -17,6 +20,7 @@ Codac provides data structures for handling basic interval sets. These structure Interval_class.rst IntervalVector_class.rst BoolInterval_class.rst + rounding.rst .. What is an interval? The Interval class diff --git a/doc/manual/manual/intervals/rounding.rst b/doc/manual/manual/intervals/rounding.rst new file mode 100644 index 000000000..7ccc95d2c --- /dev/null +++ b/doc/manual/manual/intervals/rounding.rst @@ -0,0 +1,37 @@ +.. _sec-intervals-rounding: + +Floating-point rounding and library compatibility (C++) +======================================================= + +This page concerns the C++ interface of Codac. + +Codac relies on `GAOL `_ for interval arithmetic. +To guarantee interval enclosures, the current implementation uses upward rounding (toward :math:`+\infty`). +The floating-point rounding mode also affects computations performed outside Codac in the same thread. + +Some libraries assume the usual round-to-nearest mode. +For example, using `OpenCV `_ alongside Codac may cause unexpected results or runtime errors, including segmentation faults in functions such as ``cv::resize``. +This is a rounding-mode compatibility issue rather than necessarily a memory-management bug. +Its occurrence depends on the platform, build configuration, and operations used. +See also `IBEX issue #402 `_. + +Workaround +---------- + +Before calling a library that expects round-to-nearest, select this mode using ``gaol::round_nearest()`` or ``std::fesetround(FE_TONEAREST)`` from ````. +Before resuming Codac interval calculations, restore upward rounding using ``gaol::round_upward()``. + +The previous rounding mode can also be saved using ``std::fegetround()`` and restored using ``std::fesetround()``. +If this approach is used, ensure that upward rounding is active before performing further Codac interval calculations. + +.. warning:: + + Do not perform Codac interval arithmetic while round-to-nearest is active, since the current implementation relies on upward rounding for its guarantees. + Rounding modes are generally thread-local, so a change in one thread does not automatically configure other threads. + +Why Codac does not restore the rounding mode automatically +---------------------------------------------------------- + +The current implementation uses GAOL in a configuration that assumes upward rounding to avoid repeated changes of the processor's rounding mode. +GAOL also provides a ``preserve-rounding`` build option, but Codac explicitly selects upward rounding in several places. +Enabling this option alone is therefore not a validated compatibility fix for Codac. diff --git a/doc/manual/manual/tubes/src.cpp b/doc/manual/manual/tubes/src.cpp index c3d690c36..e525583d5 100644 --- a/doc/manual/manual/tubes/src.cpp +++ b/doc/manual/manual/tubes/src.cpp @@ -336,6 +336,16 @@ TEST_CASE("Trajectory classes - manual") CHECK(x.tdomain() == Interval(0,1)); } + { + // [traj-ops-common-tdomain-beg] + SampledTraj x1({0.,4.}, {0,4}); + SampledTraj x2({2.,5}, {Vector({1,2}), Vector({5,6})}); + truncate_to_common_tdomain(x1,x2); // common time domain: [2,4] + // [traj-ops-common-tdomain-end] + CHECK(x1.tdomain() == Interval(2,4)); + CHECK(x2.tdomain() == Interval(2,4)); + } + { // [traj-analytic-create-beg] ScalarVar t; diff --git a/doc/manual/manual/tubes/src.py b/doc/manual/manual/tubes/src.py index 1ab733ca3..9b1e12753 100644 --- a/doc/manual/manual/tubes/src.py +++ b/doc/manual/manual/tubes/src.py @@ -274,6 +274,14 @@ def test_Trajectories_manual(test): shifted.stretch_tdomain([0,1]) # rescale time, not values # [traj-sampled-time-end] + # [traj-ops-common-tdomain-beg] + x1 = SampledTraj({0.:0, 4.:4}) + x2 = SampledTraj({2.:Vector([1,2]), 5.:Vector([5,6])}) + truncate_to_common_tdomain(x1,x2) # common time domain: [2,4] + # [traj-ops-common-tdomain-end] + test.assertEqual(x1.tdomain(), Interval(2,4)) + test.assertEqual(x2.tdomain(), Interval(2,4)) + # [traj-sampled-npz-beg] import numpy as np import io diff --git a/doc/manual/manual/tubes/trajectory_operations.rst b/doc/manual/manual/tubes/trajectory_operations.rst index 72302c2ad..7460cdd28 100644 --- a/doc/manual/manual/tubes/trajectory_operations.rst +++ b/doc/manual/manual/tubes/trajectory_operations.rst @@ -67,6 +67,29 @@ Cartesian products :end-before: [traj-ops-cartprod-end] :dedent: 4 +Common time domain +------------------ + +``truncate_to_common_tdomain(x1,x2,...)`` truncates all trajectories in place to the intersection of their time domains. An empty intersection raises an error. + +.. tabs:: + + .. group-tab:: Python + + .. literalinclude:: src.py + :language: python + :start-after: [traj-ops-common-tdomain-beg] + :end-before: [traj-ops-common-tdomain-end] + :dedent: 4 + + .. group-tab:: C++ + + .. literalinclude:: src.cpp + :language: c++ + :start-after: [traj-ops-common-tdomain-beg] + :end-before: [traj-ops-common-tdomain-end] + :dedent: 4 + Unwrapping periodic signals --------------------------- diff --git a/packages/temporary/gennewcodacpi_armhf.sh b/packages/temporary/gennewcodacpi_armhf.sh index 7ec2b7a02..a87972290 100644 --- a/packages/temporary/gennewcodacpi_armhf.sh +++ b/packages/temporary/gennewcodacpi_armhf.sh @@ -12,11 +12,11 @@ cd codac git submodule init git submodule update -for DIST in bookworm bullseye; do +for DIST in trixie bookworm bullseye; do docker pull lebarsfa/pi:$DIST-for-codac docker run --rm -v `pwd`:/io lebarsfa/pi:$DIST-for-codac /bin/bash -c "uname -a ; cat /etc/os-release ; lsb_release -a ; \ -if [ \"\$(lsb_release -cs)\" = \"bookworm\" ]; then \ +if [ \"\$(lsb_release -cs)\" = \"bookworm\" ] || [ \"\$(lsb_release -cs)\" = \"trixie\" ]; then \ PIP_OPTIONS=--break-system-packages ; \ #python3 -m pip install \$PIP_OPTIONS --upgrade \"auditwheel\" ; \\ else \ @@ -25,7 +25,10 @@ else \ fi && \ #sudo apt-get -q update --allow-releaseinfo-change ; sudo apt-get -y install libeigen3-dev python3-dev patchelf python3-pip python3-wheel python3-setuptools || true && \\ sudo apt-get -q update --allow-releaseinfo-change ; sudo apt-get -y install python3-dev patchelf python3-pip python3-wheel python3-setuptools || true && \ -python3 -m pip install \$PIP_OPTIONS --upgrade patchelf --prefer-binary --extra-index-url https://www.piwheels.org/simple || true && \ +# On bookworm (and possibly earlier), auditwheel repair asks for a recent version of patchelf... \\ +if [ \"\$(lsb_release -cs)\" = \"buster\" ] || [ \"\$(lsb_release -cs)\" = \"bullseye\" ] || [ \"\$(lsb_release -cs)\" = \"bookworm\" ]; then \ + python3 -m pip install \$PIP_OPTIONS --upgrade patchelf --prefer-binary --extra-index-url https://www.piwheels.org/simple || true ; \ +fi && \ python3 -m pip install \$PIP_OPTIONS --upgrade auditwheel --prefer-binary --extra-index-url https://www.piwheels.org/simple && \ # wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20260819/ibex_armhf_\$(lsb_release -cs).zip --no-check-certificate -nv is causing illegal instruction on a Mac M1... \\ curl -L -O https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20260819/ibex_armhf_\$(lsb_release -cs).zip --insecure && \ @@ -34,12 +37,17 @@ rm -Rf ibex_armhf_\$(lsb_release -cs).zip && \ sudo cp -Rf ibex/* /usr/local/ && \ \ git config --global --add safe.directory /io && \ +git config --global --add safe.directory /io/.git || true && \ cd /io && \ \ # Issues when some packages are upgraded or not...? \\ -python3 -m pip install \$PIP_OPTIONS --upgrade pip --prefer-binary --extra-index-url https://www.piwheels.org/simple && \ +if [ \"\$(lsb_release -cs)\" = \"buster\" ] || [ \"\$(lsb_release -cs)\" = \"bullseye\" ]; then \ + python3 -m pip install \$PIP_OPTIONS --upgrade pip --prefer-binary --extra-index-url https://www.piwheels.org/simple || true ; \ +fi && \ # Without wheel upgrade from pip, the architecture might be wrong for bookworm (and possibly earlier) when building the .whl... \\ -python3 -m pip install \$PIP_OPTIONS --upgrade wheel --prefer-binary --extra-index-url https://www.piwheels.org/simple && \ +if [ \"\$(lsb_release -cs)\" = \"buster\" ] || [ \"\$(lsb_release -cs)\" = \"bullseye\" ] || [ \"\$(lsb_release -cs)\" = \"bookworm\" ]; then \ + python3 -m pip install \$PIP_OPTIONS --upgrade wheel --prefer-binary --extra-index-url https://www.piwheels.org/simple || true ; \ +fi && \ # With setuptools upgrade from pip, building the .whl might fail for bullseye... \\ #python3 -m pip install \$PIP_OPTIONS --upgrade setuptools --prefer-binary --extra-index-url https://www.piwheels.org/simple && \\ mkdir -p build_dir_\$(lsb_release -cs) && cd build_dir_\$(lsb_release -cs) && \ @@ -68,6 +76,7 @@ sudo apt-get -y install libopenblas0-pthread || true && \ sudo apt-get -y install libgfortran5 || true && \ python3 -m pip install \$PIP_OPTIONS numpy --prefer-binary --extra-index-url https://www.piwheels.org/simple && \ #sudo apt-get -y install python3-numpy || true && \\ +python3 -m pip install \$PIP_OPTIONS sympy --prefer-binary --extra-index-url https://www.piwheels.org/simple && \ python3 -m unittest discover codac.tests && \ \ if [ \"\$(lsb_release -cs)\" = \"buster\" ]; then \ diff --git a/python/src/core/CMakeLists.txt b/python/src/core/CMakeLists.txt index c8a7c7a43..6adb86409 100644 --- a/python/src/core/CMakeLists.txt +++ b/python/src/core/CMakeLists.txt @@ -132,6 +132,7 @@ trajectory/codac2_py_SampledTraj.cpp trajectory/codac2_py_TrajBase.h trajectory/codac2_py_traj_cart_prod.cpp + trajectory/codac2_py_traj_truncate_common.cpp ) target_include_directories(_core diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index f0cefd778..46bbd23bb 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -171,6 +171,7 @@ void export_trunc(py::module& m); void export_AnalyticTraj(py::module& m); void export_SampledTraj(py::module& m); void export_traj_cart_prod(py::module& m); +void export_traj_truncate_common(py::module& m); // Extension > sympy void export_sympy(py::module& m); @@ -357,6 +358,7 @@ PYBIND11_MODULE(_core, m) export_AnalyticTraj(m); export_SampledTraj(m); export_traj_cart_prod(m); + export_traj_truncate_common(m); m.def("srand", []() { diff --git a/python/src/core/trajectory/codac2_py_traj_truncate_common.cpp b/python/src/core/trajectory/codac2_py_traj_truncate_common.cpp new file mode 100644 index 000000000..6e17fc3ab --- /dev/null +++ b/python/src/core/trajectory/codac2_py_traj_truncate_common.cpp @@ -0,0 +1,42 @@ +/** + * traj_truncate_common binding + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include +#include "codac2_py_TrajBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_cast.h" + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +void export_traj_truncate_common(py::module& m) +{ + m.def("truncate_to_common_tdomain", [](py::args trajs) + { + if(trajs.empty()) + throw py::value_error("At least one trajectory is required"); + + Interval t; + + for(const auto& traj : trajs) + t &= traj.attr("tdomain")().cast(); + + if(t.is_empty()) + throw py::value_error("Trajectories have disjoint time domains"); + + for(const auto& traj : trajs) + traj.attr("truncate_tdomain")(t); + }, + VOID_TRUNCATE_TO_COMMON_TDOMAIN_T_REF_VARIADIC); +} \ No newline at end of file diff --git a/scripts/MATLAB/codac4matlab_usage.m b/scripts/MATLAB/codac4matlab_usage.m new file mode 100644 index 000000000..ffb62ea28 --- /dev/null +++ b/scripts/MATLAB/codac4matlab_usage.m @@ -0,0 +1,106 @@ +import py.codac4matlab.* + +a=Interval(-1,2) +a.lb +a.ub + +x=[1,2] +X=IntervalVector(x) +X.size +X(2) +X(2).init(Interval(-10,10)) +X + +x={{-5,5},{-4,4}} +X=IntervalVector(x) +X.size + +M=[1,2;3,4;5,6] +C=arrayfun(@(i) num2cell(M(i,:)), 1:size(M,1), 'UniformOutput', false); % Inverse operation would be cell2mat(vertcat(C{:})) +A=IntervalMatrix(Matrix(C)) +A.rows +A.cols +A(3,2) +A(3,2).init(Interval(-10,10)) +A.set_item({1,2},Interval(11,12)) +A + +A_lb = Matrix({{-1,-2},{-3,-4},{-5,-6}}); +A_ub = Matrix({{1,2},{3,4},{5,6}}); +A=IntervalMatrix(A_lb,A_ub) +A.rows +A.cols +A(3,2) + +A_ub.set_item({1,2},10) +A_ub + +function C = Matrix2cell(M) + import py.codac4matlab.* + r = int32(M.rows); + c = int32(M.cols); + C = cell(1,r); + for i=1:r + rl = cell(1,c); + for j=1:c + rl{j} = double(M(i,j)); + end + C{i} = rl; + end +end + +%M=Matrix({{1,2},{3,4},{5,6}}) +%Matrix2cell(M) +%return + +% It seems we cannot do A(i,j).init(x) if A is a Matrix... But we can do +% A.set_item({i,j},x)... +function B = setitemM(A,i,j,x) +%SETITEMM Set element (i,j) of a Codac Matrix. +% +% B = setitemM(A,i,j,x) +% +% A : Codac Matrix +% i : row index (1-based MATLAB indexing) +% j : column index (1-based MATLAB indexing) +% x : double + + import py.codac4matlab.* + C = Matrix2cell(A); + C{i}{j} = x; + B = Matrix(C); +end + +% Does the same as A(i,j).init(x), probably in a slower way... +function B = setitemIM(A,i,j,x) +%SETITEMIM Set element (i,j) of a Codac IntervalMatrix. +% +% B = setitemIM(A,i,j,x) +% +% A : Codac IntervalMatrix +% i : row index (1-based MATLAB indexing) +% j : column index (1-based MATLAB indexing) +% x : Codac Interval + + import py.codac4matlab.* + C_lb = Matrix2cell(A.lb); + C_lb{i}{j} = x.lb; + C_ub = Matrix2cell(A.ub); + C_ub{i}{j} = x.ub; + B = IntervalMatrix(Matrix(C_lb),Matrix(C_ub)); +end + +A = Matrix({{1,2},{3,4},{5,6}}); +A = setitemM(A,3,2,99) + +A(3,2) +A + +A_lb = Matrix({{-1,-2},{-3,-4},{-5,-6}}); +A_ub = Matrix({{1,2},{3,4},{5,6}}); +A = IntervalMatrix(A_lb,A_ub); + +A = setitemIM(A,2,1,Interval(100,200)); + +A(2,1) +A diff --git a/scripts/MATLAB/codac4matlabonline.m b/scripts/MATLAB/codac4matlabonline.m new file mode 100644 index 000000000..20893be21 --- /dev/null +++ b/scripts/MATLAB/codac4matlabonline.m @@ -0,0 +1,51 @@ +% +% Since pip and AppImage do not seem to work on MATLAB Online, this script downloads and extracts codac4matlab and VIBes in the "/MATLAB Drive" folder. +% +% Known issues: +% It might not be possible to view the VIBes windows, possibly use the VIBes functions to save the desired pictures as a workaround... +% +% TODO: +% Replace "/MATLAB Drive" with the output of matlabdrive command (warning: might be different than $HOME...)? Might not work with shell commands prefixed by "!", but maybe with e.g. drive = matlabdrive; system('wget ... "' + drive + '/..."')...? +% + +!lsb_release -a +!uname -a +pyenv + +disp('Checking, downloading and installing codac4matlab prerequisites in "/MATLAB Drive/pythonlibs" and "/MATLAB Drive/vibes"...'); + +% Equivalent of pip install --user codac4matlab +!mkdir -p "/MATLAB Drive/pythonlibs" +if ~isfolder("/MATLAB Drive/pythonlibs/codac4matlab") + % If it does not work, please download the necessary .whl from https://pypi.org/project/codac4matlab/#files and unzip it in "/MATLAB Drive/pythonlibs"... + !PY_V_MAJ=`python3 -c "import sys; print(sys.version_info[0])"`; PY_V_MIN=`python3 -c "import sys; print(sys.version_info[1])"`; CP="cp${PY_V_MAJ}${PY_V_MIN}"; VER=$(wget -qO- https://pypi.org/pypi/codac4matlab/json | grep -o '"version":"[^"]*' | head -n 1 | cut -d'"' -f4); URL=$(wget -qO- https://pypi.org/pypi/codac4matlab/json | grep -o '"url":"[^"]*' | cut -d'"' -f4 | grep "/codac4matlab-${VER}-${CP}-${CP}.*manylinux.*x86_64\.whl$" | head -n 1); cd "/MATLAB Drive/pythonlibs" && wget -q -O "$(basename "$URL")" --show-progress --progress=dot:giga "$URL" && unzip -q "$(basename "$URL")" +end +d = dir("/MATLAB Drive/pythonlibs/vibes-*"); +if ~any([d.isdir]) + % If it does not work, please download the necessary .tar.gz or .whl from https://pypi.org/project/vibes/#files and extract it in "/MATLAB Drive/pythonlibs"... + !VER=$(wget -qO- https://pypi.org/pypi/vibes/json | grep -o '"version":"[^"]*' | head -n 1 | cut -d'"' -f4); URL=$(wget -qO- https://pypi.org/pypi/vibes/json | grep -o '"url":"[^"]*' | cut -d'"' -f4 | grep "/vibes-${VER}\.tar\.gz$" | head -n 1); cd "/MATLAB Drive/pythonlibs" && wget -q -O "$(basename "$URL")" --show-progress --progress=dot:giga "$URL" && tar xfz "$(basename "$URL")" +end + +% VIBes-viewer +if ~isfolder("/MATLAB Drive/vibes/squashfs-root") + !mkdir -p "/MATLAB Drive/vibes" + !cd "/MATLAB Drive/vibes" ; rm -f VIBes-viewer_amd64.AppImage + !cd "/MATLAB Drive/vibes" ; wget -q --show-progress --progress=dot:giga https://github.com/ENSTABretagneRobotics/VIBES/releases/latest/download/VIBes-viewer_amd64.AppImage + !cd "/MATLAB Drive/vibes" ; ./VIBes-viewer_amd64.AppImage --appimage-extract >/dev/null + !cd "/MATLAB Drive/vibes" ; mv squashfs-root/lib/x86_64-linux-gnu/libc.so.6 libc.so.6.bak + % To run in the background, but probably no way to make the window might visible... + !QT_QPA_PLATFORM_PLUGIN_PATH="/MATLAB Drive/vibes/squashfs-root/usr/lib/x86_64-linux-gnu/qt5/plugins/platforms/" ./squashfs-root/usr/bin/VIBes-viewer & + !xwininfo -root -tree | grep VIBes + % Maybe capture it with [~,out] = system('xwininfo -root -tree | grep "Codac - default figure"'); wid = regexp(out,'0x[0-9A-Fa-f]+','match','once'); system(sprintf('xwd -id %s -silent -out vibes.xwd', wid));... +end + +disp('End of codac4matlab prerequisites checks.'); + +% This is probably necessary every time... +if count(py.sys.path, "/MATLAB Drive/pythonlibs") == 0 + insert(py.sys.path, int32(0), "/MATLAB Drive/pythonlibs"); +end + +disp('Notes:'); +disp('_ This script needs to be run every time MATLAB Online is started.'); +disp('_ To uninstall, remove the "/MATLAB Drive/pythonlibs" and "/MATLAB Drive/vibes" folders, and remove related entries from py.sys.path.'); diff --git a/scripts/docker/build_pybinding.sh b/scripts/docker/build_pybinding.sh index ab98904f3..c86aa2592 100755 --- a/scripts/docker/build_pybinding.sh +++ b/scripts/docker/build_pybinding.sh @@ -8,6 +8,7 @@ rm -Rf ibex_$(uname -m)_manylinux_2_28.zip sudo cp -Rf ibex/* /usr/local/ git config --global --add safe.directory /io +git config --global --add safe.directory /io/.git || true cd /io # Read optional constraints from environment diff --git a/scripts/docker/build_pybinding_codac4matlab.sh b/scripts/docker/build_pybinding_codac4matlab.sh index b25fd262d..b7fd2d74b 100644 --- a/scripts/docker/build_pybinding_codac4matlab.sh +++ b/scripts/docker/build_pybinding_codac4matlab.sh @@ -8,6 +8,7 @@ rm -Rf ibex_$(uname -m)_manylinux_2_28.zip sudo cp -Rf ibex/* /usr/local/ git config --global --add safe.directory /io +git config --global --add safe.directory /io/.git || true cd /io # Read optional constraints from environment diff --git a/scripts/wheels/gencodacwhl.sh b/scripts/wheels/gencodacwhl.sh index b69db0d1b..5bf26a77d 100644 --- a/scripts/wheels/gencodacwhl.sh +++ b/scripts/wheels/gencodacwhl.sh @@ -4,8 +4,9 @@ read -p "Please enter the codac package version (X.Y.Z[.D]) : " PACKAGE_VERSION PY_V_MAJ=3 -for PY_V_MIN in 8 9 10 11 12 13 14; do - for CPCFG in "-macosx_10_16_x86_64" "-macosx_11_0_arm64" "-manylinux_2_17_x86_64.manylinux_2_28_x86_64" "-manylinux_2_17_aarch64.manylinux_2_28_aarch64" "-win32" "-win_amd64" "-win_arm64"; do - rm -Rf codac-$PACKAGE_VERSION-cp$PY_V_MAJ$PY_V_MIN-cp$PY_V_MAJ$PY_V_MIN$CPCFG.whl ; wget https://github.com/codac-team/codac/releases/download/v$PACKAGE_VERSION/codac-$PACKAGE_VERSION-cp$PY_V_MAJ$PY_V_MIN-cp$PY_V_MAJ$PY_V_MIN$CPCFG.whl --no-check-certificate -nv +for PY_V_MIN in 8 9 10 11 12 13 14 15; do + for CPCFG in "-macosx_10_16_x86_64" "-macosx_11_0_arm64" "-manylinux_2_27_x86_64.manylinux_2_28_x86_64" "-manylinux_2_26_aarch64.manylinux_2_28_aarch64" "-win32" "-win_amd64" "-win_arm64"; do + rm -Rf codac-${PACKAGE_VERSION}-cp${PY_V_MAJ}${PY_V_MIN}-cp${PY_V_MAJ}${PY_V_MIN}${CPCFG}.whl ; wget https://github.com/codac-team/codac/releases/download/v${PACKAGE_VERSION}/codac-${PACKAGE_VERSION}-cp${PY_V_MAJ}${PY_V_MIN}-cp${PY_V_MAJ}${PY_V_MIN}${CPCFG}.whl --no-check-certificate -nv + rm -Rf codac-${PACKAGE_VERSION}-cp${PY_V_MAJ}${PY_V_MIN}-cp${PY_V_MAJ}${PY_V_MIN}t${CPCFG}.whl ; wget https://github.com/codac-team/codac/releases/download/v${PACKAGE_VERSION}/codac-${PACKAGE_VERSION}-cp${PY_V_MAJ}${PY_V_MIN}-cp${PY_V_MAJ}${PY_V_MIN}t${CPCFG}.whl --no-check-certificate -nv done done diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 28fd1c4fc..c284c553e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,6 +53,8 @@ "# Try to find Codac # This file has been generated by CMake + find_path(CODAC_EIGEN_INCLUDE_DIR Eigen/Core + PATH_SUFFIXES include/${PROJECT_NAME}-eigen) find_path(CODAC_CORE_INCLUDE_DIR ${PROJECT_NAME}-core.h PATH_SUFFIXES include/${PROJECT_NAME}-core) find_path(CODAC_GRAPHICS_INCLUDE_DIR ${PROJECT_NAME}-graphics.h @@ -71,7 +73,7 @@ set(CODAC_VERSION ${PROJECT_VERSION}) set(CODAC_LIBRARIES \${CODAC_CORE_LIBRARY} \${CODAC_GRAPHICS_LIBRARY} \${CODAC_UNSUPPORTED_LIBRARY} Ibex::ibex) - set(CODAC_INCLUDE_DIRS \${CODAC_CORE_INCLUDE_DIR}/../ \${CODAC_CORE_INCLUDE_DIR}/../eigen3/ \${CODAC_CORE_INCLUDE_DIR} \${CODAC_GRAPHICS_INCLUDE_DIR} \${CODAC_UNSUPPORTED_INCLUDE_DIR}) + set(CODAC_INCLUDE_DIRS \${CODAC_CORE_INCLUDE_DIR}/../ \${CODAC_EIGEN_INCLUDE_DIR} \${CODAC_CORE_INCLUDE_DIR} \${CODAC_GRAPHICS_INCLUDE_DIR} \${CODAC_UNSUPPORTED_INCLUDE_DIR}) set(CODAC_C_FLAGS \"\") set(CODAC_CXX_FLAGS \"\") diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1573630ce..7c3752756 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -331,7 +331,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/tools ${CMAKE_CURRENT_SOURCE_DIR}/trajectory ) - target_link_libraries(${PROJECT_NAME}-core PUBLIC Ibex::ibex Eigen3::Eigen Threads::Threads) + target_link_libraries(${PROJECT_NAME}-core PUBLIC ${PROJECT_NAME}-eigen Ibex::ibex Threads::Threads) #Eigen3::Eigen ################################################################################ diff --git a/src/core/trajectory/codac2_TrajBase.h b/src/core/trajectory/codac2_TrajBase.h index dba040afa..34af41052 100644 --- a/src/core/trajectory/codac2_TrajBase.h +++ b/src/core/trajectory/codac2_TrajBase.h @@ -45,4 +45,13 @@ namespace codac2 SampledTraj sampled_as(const SampledTraj& x) const; SampledTraj primitive(double dt) const; }; + + template + void truncate_to_common_tdomain(T&... x) + { + static_assert(sizeof...(x) > 0); + Interval t = (x.tdomain() & ...); + assert_release(!t.is_empty() && "Trajectories have disjoint time domains"); + (x.truncate_tdomain(t), ...); + } } diff --git a/src/extensions/capd/CMakeLists.txt b/src/extensions/capd/CMakeLists.txt index 0214cb955..72c364450 100644 --- a/src/extensions/capd/CMakeLists.txt +++ b/src/extensions/capd/CMakeLists.txt @@ -22,7 +22,7 @@ list(APPEND CODAC_CAPD_SRC #endif() add_library(${PROJECT_NAME}-capd ${CODAC_CAPD_SRC}) - target_link_libraries(${PROJECT_NAME}-capd PUBLIC ${PROJECT_NAME}-core Ibex::ibex Eigen3::Eigen capd::capd) + target_link_libraries(${PROJECT_NAME}-capd PUBLIC ${PROJECT_NAME}-core ${PROJECT_NAME}-eigen Ibex::ibex capd::capd) # Eigen3::Eigen ################################################################################ diff --git a/src/extensions/sympy/CMakeLists.txt b/src/extensions/sympy/CMakeLists.txt index d92bae572..00e893260 100644 --- a/src/extensions/sympy/CMakeLists.txt +++ b/src/extensions/sympy/CMakeLists.txt @@ -31,7 +31,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) add_library(${PROJECT_NAME}-sympy ${CODAC_SYMPY_SRC}) - target_link_libraries(${PROJECT_NAME}-sympy PUBLIC ${PROJECT_NAME}-core Ibex::ibex Eigen3::Eigen) + target_link_libraries(${PROJECT_NAME}-sympy PUBLIC ${PROJECT_NAME}-core ${PROJECT_NAME}-eigen Ibex::ibex) # Eigen3::Eigen target_link_libraries(${PROJECT_NAME}-sympy PRIVATE pybind11::pybind11) ################################################################################ diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt index 453a547d1..3a08363f5 100644 --- a/src/graphics/CMakeLists.txt +++ b/src/graphics/CMakeLists.txt @@ -53,7 +53,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/paver # deprecated, to be removed ${CMAKE_CURRENT_SOURCE_DIR}/styles ) - target_link_libraries(${PROJECT_NAME}-graphics PUBLIC ${PROJECT_NAME}-core Ibex::ibex Eigen3::Eigen ${PROJECT_NAME}-core) + target_link_libraries(${PROJECT_NAME}-graphics PUBLIC ${PROJECT_NAME}-core ${PROJECT_NAME}-eigen Ibex::ibex ${PROJECT_NAME}-core) # Eigen3::Eigen ################################################################################ diff --git a/src/unsupported/CMakeLists.txt b/src/unsupported/CMakeLists.txt index a0a0f8d8f..f229909a1 100644 --- a/src/unsupported/CMakeLists.txt +++ b/src/unsupported/CMakeLists.txt @@ -25,7 +25,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/paver ${CMAKE_CURRENT_SOURCE_DIR}/styles ) - target_link_libraries(${PROJECT_NAME}-unsupported PUBLIC ${PROJECT_NAME}-core Eigen3::Eigen) + target_link_libraries(${PROJECT_NAME}-unsupported PUBLIC ${PROJECT_NAME}-core ${PROJECT_NAME}-eigen) # Eigen3::Eigen ################################################################################ diff --git a/tests/core/trajectory/codac2_tests_SampledTraj.cpp b/tests/core/trajectory/codac2_tests_SampledTraj.cpp index 4addc7c93..6fa742c72 100644 --- a/tests/core/trajectory/codac2_tests_SampledTraj.cpp +++ b/tests/core/trajectory/codac2_tests_SampledTraj.cpp @@ -149,4 +149,23 @@ TEST_CASE("SampledTraj: derivative") for(double i = 0 ; i < 10 ; i+=1e-1) CHECK(Approx(p(i),1e-2) == x(i)); +} + +TEST_CASE("truncate_to_common_tdomain") +{ + SampledTraj x({0.,4.}, {0,4}); + SampledTraj y({{1.,{1,2}}, {5.,{5,6}}}); + + ScalarVar t; + AnalyticFunction f({t},t); + AnalyticTraj z({2,6},f); + + truncate_to_common_tdomain(x,y,z); + + CHECK(x.tdomain() == Interval(2,4)); + CHECK(y.tdomain() == Interval(2,4)); + CHECK(z.tdomain() == Interval(2,4)); + + CHECK(x(2.) == 2.); // interpolated boundary + CHECK(y(4.) == Vector({4.,5.})); } \ No newline at end of file diff --git a/tests/core/trajectory/codac2_tests_SampledTraj.py b/tests/core/trajectory/codac2_tests_SampledTraj.py index da0072f37..db069dc39 100644 --- a/tests/core/trajectory/codac2_tests_SampledTraj.py +++ b/tests/core/trajectory/codac2_tests_SampledTraj.py @@ -130,6 +130,25 @@ def test_SampledTraj(self): for i in np.arange(0, 10, 1e-1): self.assertTrue(Approx(p(i),1e-2) == x(i)) + + + # truncate_to_common_tdomain + + x = SampledTraj_Scalar({0.:0., 4.:4.}) + y = SampledTraj_Vector({1.:[1.,2.], 5.:[5.,6.]}) + + t = ScalarVar() + z = AnalyticTraj([2,6], AnalyticFunction([t],t)) + + truncate_to_common_tdomain(x,y,z) + + self.assertTrue(x.tdomain() == Interval(2,4)) + self.assertTrue(y.tdomain() == Interval(2,4)) + self.assertTrue(z.tdomain() == Interval(2,4)) + + self.assertTrue(x(2.) == 2.) + self.assertTrue(y(4.) == Vector([4.,5.])) + if __name__ == '__main__': unittest.main() \ No newline at end of file