From 6d9ed0f3f7e5ff0410e4987570dd38a67254e259 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sun, 20 Oct 2024 15:29:50 +0200 Subject: [PATCH 001/102] Add macOS Sequoia support --- .github/workflows/unixmatrix.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index c4f10a6d..e976231f 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -50,6 +50,8 @@ jobs: - { os: ubuntu-22.04, shell: bash, arch: amd64, bitness: 64, runtime: jammy, cmake_flags: '-fPIC', deb: true, desc: 'Ubuntu 22.04 amd64' } # Problems related to C++20? #- { os: ubuntu-20.04, shell: bash, arch: amd64, bitness: 64, runtime: focal, cmake_flags: '-fPIC', deb: true, desc: 'Ubuntu 20.04 amd64' } + - { 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, 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', cross: true, desc: 'macOS Sequoia x86_64 (cross)' } - { 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', cmake_flags: '-fPIC', cross: true, desc: 'macOS Sonoma x86_64 (cross)' } - { os: macos-13, shell: bash, arch: arm64, bitness: 64, runtime: ventura, cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=arm64', cmake_flags: '-fPIC', cross: true, desc: 'macOS Ventura arm64 (cross)' } From 197ef0be1d4667d44107f39607fd8564d9d854ce Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sun, 20 Oct 2024 15:29:00 +0200 Subject: [PATCH 002/102] Add Python 3.13 support --- .github/workflows/macosmatrix.yml | 2 ++ .github/workflows/vcmatrix.yml | 4 +++- packages/temporary/gennewcodacpi_armhf.sh | 6 ++++-- scripts/docker/build_pybinding.sh | 3 ++- scripts/wheels/gencodacwhl.sh | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/macosmatrix.yml b/.github/workflows/macosmatrix.yml index 4d4415f7..08bdec60 100644 --- a/.github/workflows/macosmatrix.yml +++ b/.github/workflows/macosmatrix.yml @@ -20,6 +20,7 @@ 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: 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-12, shell: bash, arch: arm64, runtime: monterey, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: '-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 10, cross: true, desc: 'macOS Monterey Python 3.10 arm64 (cross)' } @@ -27,6 +28,7 @@ jobs: - { os: macos-12, shell: bash, arch: arm64, runtime: monterey, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: '-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 8, cross: true, desc: 'macOS Monterey Python 3.8 arm64 (cross)' } - { os: macos-12, shell: bash, arch: arm64, runtime: monterey, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: 'm-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 7, cross: true, desc: 'macOS Monterey Python 3.7 arm64 (cross)' } - { os: macos-12, shell: bash, arch: arm64, runtime: monterey, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: 'm-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 6, cross: true, desc: 'macOS Monterey Python 3.6 arm64 (cross)' } + - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 13, desc: 'macOS Monterey Python 3.13 x86_64' } - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 12, desc: 'macOS Monterey Python 3.12 x86_64' } - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 11, desc: 'macOS Monterey Python 3.11 x86_64' } - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 10, desc: 'macOS Monterey Python 3.10 x86_64' } diff --git a/.github/workflows/vcmatrix.yml b/.github/workflows/vcmatrix.yml index bf1e3636..7b098108 100644 --- a/.github/workflows/vcmatrix.yml +++ b/.github/workflows/vcmatrix.yml @@ -17,11 +17,13 @@ jobs: fail-fast: false matrix: cfg: + - { 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' } - { 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: 11, desc: 'Windows Visual Studio 2022 x86 Python 3.11' } - { os: windows-2022, shell: cmd, arch: x86, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 10, desc: 'Windows Visual Studio 2019 x86 Python 3.10' } - { os: windows-2022, shell: cmd, arch: x86, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 9, desc: 'Windows Visual Studio 2019 x86 Python 3.9' } - { os: windows-2022, shell: cmd, arch: x86, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 8, desc: 'Windows Visual Studio 2019 x86 Python 3.8' } + - { 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' } - { 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: 11, desc: 'Windows Visual Studio 2022 x64 Python 3.11' } - { os: windows-2022, shell: cmd, arch: x64, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A x64', cpcfg: '-win_amd64', py_v_maj: 3, py_v_min: 10, desc: 'Windows Visual Studio 2019 x64 Python 3.10' } @@ -57,7 +59,7 @@ jobs: if: runner.os=='Windows' - run: choco install -y -r --no-progress eigen --version=3.4.0.20240224 ${{ matrix.cfg.choco_flags }} if: runner.os=='Windows' - - run: choco install -y -r --no-progress graphviz doxygen.install & pip install --upgrade wheel setuptools sphinx breathe sphinx-issues sphinx-tabs sphinx_rtd_theme sphinx-reredirects + - run: choco install -y -r --no-progress graphviz doxygen.install & python -m pip install --upgrade pip & pip install --upgrade wheel setuptools sphinx breathe sphinx-issues sphinx-tabs sphinx_rtd_theme sphinx-reredirects if: runner.os=='Windows' - run: | wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex.2.8.9.20240417.nupkg --no-check-certificate -nv diff --git a/packages/temporary/gennewcodacpi_armhf.sh b/packages/temporary/gennewcodacpi_armhf.sh index 4a6ea9b6..e81115b5 100644 --- a/packages/temporary/gennewcodacpi_armhf.sh +++ b/packages/temporary/gennewcodacpi_armhf.sh @@ -36,6 +36,7 @@ git config --global --add safe.directory /io && \ cd /io && \ \ python3 -m pip install \$PIP_OPTIONS --upgrade pip && \ +python3 -m pip install \$PIP_OPTIONS --upgrade wheel setuptools && \ mkdir -p build_dir_\$(lsb_release -cs) && cd build_dir_\$(lsb_release -cs) && \ cmake -E env CXXFLAGS=\"-fPIC\" CFLAGS=\"-fPIC\" cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -DWITH_CAPD=OFF -DWITH_PYTHON=ON .. && \ make -j4 && \ @@ -54,13 +55,14 @@ done ; \ #done ; \\ \ python3 -m pip install \$PIP_OPTIONS codac --no-deps --no-index -f /io/wheelhouse && \ -python3 -m ../examples/02_centered_form/main.py && \ +python3 ../examples/02_centered_form/main.py && \ # Prerequisites for numpy. \\ sudo apt-get -y install libatlas3-base || true && \ 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 && \ -#(cd \"\$HOME\"; python3 -m unittest discover codac.tests) && \\ +#python3 -m unittest discover codac.tests && \\ +\ if [ \"\$(lsb_release -cs)\" = \"buster\" ]; then \ echo \"TESTS DISABLED FOR BUSTER DUE TO CATCH2\" ; \ else \ diff --git a/scripts/docker/build_pybinding.sh b/scripts/docker/build_pybinding.sh index 81bf7972..a579a7f3 100755 --- a/scripts/docker/build_pybinding.sh +++ b/scripts/docker/build_pybinding.sh @@ -16,6 +16,7 @@ for PYBIN in /opt/python/cp3*/bin; do #fi "${PYBIN}/python" -m pip install --upgrade pip + "${PYBIN}/python" -m pip install --upgrade wheel setuptools mkdir -p build_dir && cd build_dir cmake -E env CXXFLAGS="-fPIC" CFLAGS="-fPIC" cmake -DPYTHON_EXECUTABLE=${PYBIN}/python -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -DWITH_CAPD=OFF -DWITH_PYTHON=ON .. make -j4 @@ -27,8 +28,8 @@ for PYBIN in /opt/python/cp3*/bin; do done "${PYBIN}/python" -m pip install codac --no-deps --no-index -f /io/wheelhouse - "${PYBIN}/python" -m pip install numpy --prefer-binary "${PYBIN}/python" ../examples/02_centered_form/main.py + "${PYBIN}/python" -m pip install numpy --prefer-binary "${PYBIN}/python" -m unittest discover codac.tests make test ARGS="-V --output-on-failure" diff --git a/scripts/wheels/gencodacwhl.sh b/scripts/wheels/gencodacwhl.sh index 7b94aba7..bff102d5 100644 --- a/scripts/wheels/gencodacwhl.sh +++ b/scripts/wheels/gencodacwhl.sh @@ -10,7 +10,7 @@ for PY_V_MIN in 6 7; do done done -for PY_V_MIN in 8 9 10 11 12; do +for PY_V_MIN in 8 9 10 11 12 13; do for CPCFG in "-macosx_10_16_x86_64" "-macosx_11_0_arm64" "-manylinux_2_17_x86_64.manylinux2014_x86_64" "-win32" "-win_amd64"; 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 done From 255d94bc6ea747ea702befcfe2c29131defa1c21 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Mon, 21 Oct 2024 12:38:26 +0200 Subject: [PATCH 003/102] [proj] added CtcProj + binding --- python/src/core/CMakeLists.txt | 1 + python/src/core/codac2_py_core.cpp | 2 + .../core/contractors/codac2_py_CtcProj.cpp | 64 +++++++++++ .../src/core/separators/codac2_py_SepProj.cpp | 2 +- src/core/CMakeLists.txt | 6 + src/core/contractors/codac2_CtcProj.cpp | 57 ++++++++++ src/core/contractors/codac2_CtcProj.h | 48 ++++++++ src/core/proj/codac2_ProjBase.cpp | 107 ++++++++++++++++++ src/core/proj/codac2_ProjBase.h | 34 ++++++ src/core/separators/codac2_SepProj.cpp | 88 -------------- src/core/separators/codac2_SepProj.h | 14 +-- 11 files changed, 324 insertions(+), 99 deletions(-) create mode 100644 python/src/core/contractors/codac2_py_CtcProj.cpp create mode 100644 src/core/contractors/codac2_CtcProj.cpp create mode 100644 src/core/contractors/codac2_CtcProj.h create mode 100644 src/core/proj/codac2_ProjBase.cpp create mode 100644 src/core/proj/codac2_ProjBase.h diff --git a/python/src/core/CMakeLists.txt b/python/src/core/CMakeLists.txt index e4d01d4d..3e806496 100644 --- a/python/src/core/CMakeLists.txt +++ b/python/src/core/CMakeLists.txt @@ -21,6 +21,7 @@ contractors/codac2_py_CtcLazy.cpp contractors/codac2_py_CtcNot.cpp contractors/codac2_py_CtcPolar.cpp + contractors/codac2_py_CtcProj.cpp contractors/codac2_py_CtcSegment.cpp contractors/codac2_py_CtcUnion.cpp contractors/codac2_py_CtcWrapper.cpp diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index 888acc85..8d2bcfc6 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -37,6 +37,7 @@ void export_CtcInter(py::module& m, py::class_,pyCtcInte void export_CtcLazy(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcNot(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcPolar(py::module& m, py::class_,pyCtcIntervalVector>& ctc); +void export_CtcProj(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcSegment(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcUnion(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcWrapper(py::module& m, py::class_,pyCtcIntervalVector>& ctc); @@ -130,6 +131,7 @@ PYBIND11_MODULE(_core, m) export_CtcLazy(m, py_ctc_iv); export_CtcNot(m, py_ctc_iv); export_CtcPolar(m, py_ctc_iv); + export_CtcProj(m, py_ctc_iv); export_CtcSegment(m, py_ctc_iv); export_CtcUnion(m, py_ctc_iv); export_CtcWrapper(m, py_ctc_iv); diff --git a/python/src/core/contractors/codac2_py_CtcProj.cpp b/python/src/core/contractors/codac2_py_CtcProj.cpp new file mode 100644 index 00000000..d115bf51 --- /dev/null +++ b/python/src/core/contractors/codac2_py_CtcProj.cpp @@ -0,0 +1,64 @@ +/** + * Codac binding (core) + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include "codac2_py_Ctc.h" +#include "codac2_py_CtcProj_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py): + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +void export_CtcProj(py::module& m, py::class_,pyCtcIntervalVector>& pyctc) +{ + py::class_ exported(m, "CtcProj", pyctc, CTCPROJ_MAIN); + exported + + .def(py::init( + [](const CtcBase& c, std::vector proj_indices, double default_eps) + { + std::transform(std::begin(proj_indices),std::end(proj_indices),std::begin(proj_indices), + [](size_t_type x) + { + matlab::test_integer(x); + return matlab::input_index(x); + }); + + return std::make_unique(c.copy(), proj_indices, default_eps); + }), + CTCPROJ_CTCPROJ_CONST_C_REF_CONST_VECTOR_SIZET_REF_DOUBLE, + "c"_a, "proj_indices"_a, "default_eps"_a=0.01) + + .def(py::init( + [](const CtcBase& c, std::vector proj_indices, const IntervalVector& y, double default_eps) + { + std::transform(std::begin(proj_indices),std::end(proj_indices),std::begin(proj_indices), + [](size_t_type x) + { + matlab::test_integer(x); + return matlab::input_index(x); + }); + + return std::make_unique(c.copy(), proj_indices, y, default_eps); + }), + CTCPROJ_CTCPROJ_CONST_C_REF_CONST_VECTOR_SIZET_REF_CONST_INTERVALVECTOR_REF_DOUBLE, + "c"_a, "proj_indices"_a, "y"_a, "default_eps"_a=0.01) + + .def("contract", (void(CtcProj::*)(IntervalVector&,double) const) &CtcProj::contract, + VOID_CTCPROJ_CONTRACT_INTERVALVECTOR_REF_DOUBLE_CONST, + "x"_a, "eps"_a) + + .def(CONTRACT_BOX_METHOD(CtcProj, + VOID_CTCPROJ_CONTRACT_INTERVALVECTOR_REF_CONST)) + ; +} \ No newline at end of file diff --git a/python/src/core/separators/codac2_py_SepProj.cpp b/python/src/core/separators/codac2_py_SepProj.cpp index 9ba8f6c3..4be5b97b 100644 --- a/python/src/core/separators/codac2_py_SepProj.cpp +++ b/python/src/core/separators/codac2_py_SepProj.cpp @@ -59,7 +59,7 @@ void export_SepProj(py::module& m, py::class_& pysep) "x"_a) .def("separate", (BoxPair(SepProj::*)(const IntervalVector&,double) const) &SepProj::separate, - BOXPAIR_SEPPROJ_SEPARATE_CONST_INTERVALVECTOR_REF_CONST, + BOXPAIR_SEPPROJ_SEPARATE_CONST_INTERVALVECTOR_REF_DOUBLE_CONST, "x"_a, "eps"_a) ; } \ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 216cd50a..5c1c9e6c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -31,6 +31,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcUnion.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcPolar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcPolar.h + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcProj.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcProj.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcSegment.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcSegment.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcWrapper.h @@ -98,6 +100,9 @@ ${CMAKE_CURRENT_SOURCE_DIR}/paver/codac2_pave.cpp ${CMAKE_CURRENT_SOURCE_DIR}/paver/codac2_pave.h + ${CMAKE_CURRENT_SOURCE_DIR}/proj/codac2_ProjBase.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/proj/codac2_ProjBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/separators/codac2_Sep.h ${CMAKE_CURRENT_SOURCE_DIR}/separators/codac2_SepAction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/separators/codac2_SepAction.h @@ -159,6 +164,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/graphics/vibes ${CMAKE_CURRENT_SOURCE_DIR}/matrices ${CMAKE_CURRENT_SOURCE_DIR}/paver + ${CMAKE_CURRENT_SOURCE_DIR}/proj ${CMAKE_CURRENT_SOURCE_DIR}/separators ${CMAKE_CURRENT_SOURCE_DIR}/tools ) diff --git a/src/core/contractors/codac2_CtcProj.cpp b/src/core/contractors/codac2_CtcProj.cpp new file mode 100644 index 00000000..146ea1c5 --- /dev/null +++ b/src/core/contractors/codac2_CtcProj.cpp @@ -0,0 +1,57 @@ +/** + * codac2_CtcProj.cp + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_CtcProj.h" + +using namespace std; +using namespace codac2; + +namespace codac2 +{ + void CtcProj::contract(IntervalVector& x) const + { + contract(x, _default_eps); + } + + void CtcProj::contract(IntervalVector& x, double eps) const + { + assert_release(eps > 0.); + assert_release(x.size() == this->size()); + + list l_stack { cart_prod_xy(x,_y) }; + x.set_empty(); + + // The stack allows to explore along the y-column to be projected, + // performing bisections along y if necesary + while(!l_stack.empty()) + { + auto w = l_stack.front(); // one box-guess in the projected column + l_stack.pop_front(); + + IntervalVector w_ctc(w); + _ctc.front().contract(w_ctc); + + // If the guess box may contain some values + if(!w_ctc.is_empty()) + { + // If the current guess w is not a leaf, proceed to a bisection of the guess + auto y = extract_y(w); + if(y.max_diam() > eps) + { + auto b = w.bisect(y_max_diam_index(y)); + l_stack.push_back(b.first); + l_stack.push_back(b.second); + } + + else + x |= extract_x(w_ctc); + } + } + } +} \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcProj.h b/src/core/contractors/codac2_CtcProj.h new file mode 100644 index 00000000..8bca8538 --- /dev/null +++ b/src/core/contractors/codac2_CtcProj.h @@ -0,0 +1,48 @@ +/** + * \file codac2_CtcProj.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include +#include "codac2_Collection.h" +#include "codac2_template_tools.h" +#include "codac2_ProjBase.h" + +namespace codac2 +{ + class CtcProj : public Ctc, protected ProjBase + { + public: + + template + requires IsCtcBaseOrPtr + CtcProj(const C& c, const std::vector& proj_indices, double default_eps = 0.01) + : CtcProj(c, proj_indices, IntervalVector(size_of(c)-proj_indices.size()), default_eps) + { } + + template + requires IsCtcBaseOrPtr + CtcProj(const C& c, const std::vector& proj_indices, const IntervalVector& y, double default_eps = 0.01) + : Ctc(proj_indices.size()), ProjBase(proj_indices,y,default_eps), _ctc(c) + { + assert_release(_y.size() == size_of(c)-_xi.size()); + assert_release(*min_element(_xi.begin(),_xi.end()) >= 0); + assert_release(*max_element(_xi.begin(),_xi.end()) < size_of(c)); + assert_release(size_of(c) >= _xi.size() && "cannot compute a projection of a set into a superset"); + assert_release(default_eps > 0.); + } + + void contract(IntervalVector& x) const; + void contract(IntervalVector& x, double eps) const; + + protected: + + const Collection> _ctc; + }; +} \ No newline at end of file diff --git a/src/core/proj/codac2_ProjBase.cpp b/src/core/proj/codac2_ProjBase.cpp new file mode 100644 index 00000000..d2fb5f94 --- /dev/null +++ b/src/core/proj/codac2_ProjBase.cpp @@ -0,0 +1,107 @@ +/** + * codac2_ProjBase.cp + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_ProjBase.h" + +using namespace std; + +namespace codac2 +{ + ProjBase::ProjBase(const std::vector& proj_indices, const IntervalVector& y, double default_eps) + : _n(proj_indices.size()+y.size()), _xi(proj_indices), _y(y), _default_eps(default_eps) + { + assert(default_eps > 0.); + } + + IntervalVector ProjBase::extract_x(const IntervalVector& w) const + { + assert(w.size() == _n); + + IntervalVector x(_xi.size()); + size_t k = 0; + for(const auto& xi : _xi) + x[k++] = w[xi]; + assert(k == _xi.size()); // all components have been reached + return x; + } + + IntervalVector ProjBase::extract_y(const IntervalVector& w) const + { + assert(w.size() == _n); + + IntervalVector y(_y.size()); + size_t k = 0; + for(size_t j = 0 ; j < w.size() ; j++) + { + bool outside_proj = true; + for(const auto& xi : _xi) + if(xi == j) + { + outside_proj = false; + break; + } + + if(outside_proj) + y[k++] = w[j]; + } + + assert(k == y.size()); // all components have been reached + return y; + } + + IntervalVector ProjBase::cart_prod_xy(const IntervalVector& x, const IntervalVector& y) const + { + assert(x.size() == _xi.size()); + assert(y.size() == _y.size()); + + size_t ix = 0, iy = 0; + IntervalVector w(_n); + + for(size_t j = 0 ; j < _n ; j++) + { + bool outside_proj = true; + for(const auto& xi : _xi) + if(xi == j) + { + outside_proj = false; + break; + } + + w[j] = outside_proj ? y[iy++] : x[ix++]; + } + + assert(ix+iy == w.size()); // all components have been reached + return w; + } + + size_t ProjBase::y_max_diam_index(const IntervalVector& y) const + { + size_t k = 0, y_max = y.max_diam_index(); + for(size_t i = 0 ; i < _n ; i++) + { + bool outside_proj = true; + for(const auto& xi : _xi) + if(xi == i) + { + outside_proj = false; + break; + } + + if(outside_proj) + { + if(k == y_max) + return i; + k++; + } + } + + assert(false && "unable to find y-index"); + return 0; + } +} \ No newline at end of file diff --git a/src/core/proj/codac2_ProjBase.h b/src/core/proj/codac2_ProjBase.h new file mode 100644 index 00000000..7a52e390 --- /dev/null +++ b/src/core/proj/codac2_ProjBase.h @@ -0,0 +1,34 @@ +/** + * \file codac2_CtcProj.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include +#include "codac2_IntervalVector.h" + +namespace codac2 +{ + class ProjBase + { + protected: + + ProjBase(const std::vector& proj_indices, const IntervalVector& y, double default_eps = 0.01); + IntervalVector extract_x(const IntervalVector& w) const; + IntervalVector extract_y(const IntervalVector& w) const; + IntervalVector cart_prod_xy(const IntervalVector& x, const IntervalVector& y) const; + size_t y_max_diam_index(const IntervalVector& y) const; + + protected: + + const size_t _n; + const std::vector _xi; + const IntervalVector _y; + const double _default_eps; + }; +} \ No newline at end of file diff --git a/src/core/separators/codac2_SepProj.cpp b/src/core/separators/codac2_SepProj.cpp index 131ebb1c..b62ac9ac 100644 --- a/src/core/separators/codac2_SepProj.cpp +++ b/src/core/separators/codac2_SepProj.cpp @@ -84,92 +84,4 @@ namespace codac2 assert((x_in | x_out) == x); return { x_in, x_out }; } - - IntervalVector SepProj::extract_x(const IntervalVector& w) const - { - assert(w.size() == this->_sep.front().size()); - - IntervalVector x(_xi.size()); - size_t k = 0; - for(const auto& xi : _xi) - x[k++] = w[xi]; - assert(k == _xi.size()); // all components have been reached - return x; - } - - IntervalVector SepProj::extract_y(const IntervalVector& w) const - { - assert(w.size() == this->_sep.front().size()); - - IntervalVector y(_y.size()); - size_t k = 0; - for(size_t j = 0 ; j < w.size() ; j++) - { - bool outside_proj = true; - for(const auto& xi : _xi) - if(xi == j) - { - outside_proj = false; - break; - } - - if(outside_proj) - y[k++] = w[j]; - } - - assert(k == y.size()); // all components have been reached - return y; - } - - IntervalVector SepProj::cart_prod_xy(const IntervalVector& x, const IntervalVector& y) const - { - size_t n = this->_sep.front().size(); - assert(x.size() == this->size()); - assert(y.size() == _y.size()); - assert(x.size()+y.size() == n); - - size_t ix = 0, iy = 0; - IntervalVector w(n); - - for(size_t j = 0 ; j < n ; j++) - { - bool outside_proj = true; - for(const auto& xi : _xi) - if(xi == j) - { - outside_proj = false; - break; - } - - w[j] = outside_proj ? y[iy++] : x[ix++]; - } - - assert(ix+iy == w.size()); // all components have been reached - return w; - } - - size_t SepProj::y_max_diam_index(const IntervalVector& y) const - { - size_t k = 0, y_max = y.max_diam_index(); - for(size_t i = 0 ; i < this->_sep.front().size() ; i++) - { - bool outside_proj = true; - for(const auto& xi : _xi) - if(xi == i) - { - outside_proj = false; - break; - } - - if(outside_proj) - { - if(k == y_max) - return i; - k++; - } - } - - assert(false && "unable to find y-index"); - return 0; - } } \ No newline at end of file diff --git a/src/core/separators/codac2_SepProj.h b/src/core/separators/codac2_SepProj.h index 484659c6..8ac409c8 100644 --- a/src/core/separators/codac2_SepProj.h +++ b/src/core/separators/codac2_SepProj.h @@ -13,10 +13,11 @@ #include "codac2_Sep.h" #include "codac2_Collection.h" #include "codac2_template_tools.h" +#include "codac2_ProjBase.h" namespace codac2 { - class SepProj : public Sep + class SepProj : public Sep, protected ProjBase { public: @@ -29,12 +30,13 @@ namespace codac2 template requires IsSepBaseOrPtr SepProj(const S& s, const std::vector& proj_indices, const IntervalVector& y, double default_eps = 0.01) - : Sep(proj_indices.size()), _sep(s), _xi(proj_indices), _y(y), _default_eps(default_eps) + : Sep(proj_indices.size()), ProjBase(proj_indices,y,default_eps), _sep(s) { assert_release(_y.size() == size_of(s)-_xi.size()); assert_release(*min_element(_xi.begin(),_xi.end()) >= 0); assert_release(*max_element(_xi.begin(),_xi.end()) < size_of(s)); assert_release(size_of(s) >= _xi.size() && "cannot compute a projection of a set into a superset"); + assert_release(default_eps > 0.); } BoxPair separate(const IntervalVector& x) const; @@ -42,14 +44,6 @@ namespace codac2 protected: - IntervalVector extract_x(const IntervalVector& w) const; - IntervalVector extract_y(const IntervalVector& w) const; - IntervalVector cart_prod_xy(const IntervalVector& x, const IntervalVector& y) const; - size_t y_max_diam_index(const IntervalVector& w) const; - const Collection _sep; - const std::vector _xi; - const IntervalVector _y; - const double _default_eps; }; } \ No newline at end of file From ac0a85190c59003600410d06db3acbe544ad0e92 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 22 Oct 2024 14:33:08 +0200 Subject: [PATCH 004/102] [git] updated .gitignore for XML files (generated for IPE) --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index aa002231..f1986dcd 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,7 @@ wheelhouse/ # VSCode files *.vscode -.idea/ \ No newline at end of file +.idea/ + +# Graphics files +examples/**/*.xml \ No newline at end of file From 224de6edae33530d9c4acba256b3fb0b511a3f24 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 22 Oct 2024 14:55:31 +0200 Subject: [PATCH 005/102] [graphics] color constructor from html string --- .../src/graphics/styles/codac2_py_Color.cpp | 4 ++++ src/graphics/styles/codac2_Color.cpp | 21 +++++++++++++++++++ src/graphics/styles/codac2_Color.h | 1 + 3 files changed, 26 insertions(+) diff --git a/python/src/graphics/styles/codac2_py_Color.cpp b/python/src/graphics/styles/codac2_py_Color.cpp index 861b7651..f86cfdec 100644 --- a/python/src/graphics/styles/codac2_py_Color.cpp +++ b/python/src/graphics/styles/codac2_py_Color.cpp @@ -38,6 +38,10 @@ void export_Color(py::module& m) COLOR_COLOR_FLOAT_FLOAT_FLOAT_FLOAT, "r"_a, "g"_a, "b"_a, "alpha"_a=1.) + .def(py::init(), + COLOR_COLOR_CONST_STRING_REF, + "hex_str"_a) + // Predefined colors .def_static("none", &Color::none, diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index 99350065..05a09905 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -31,4 +31,25 @@ Color::Color(int r_, int g_, int b_, int alpha_) : Color((float)(r_/255.), (float)(g_/255.), (float)(b_/255.), (float)(alpha_/255.)) { assert(r_ >= 0 && r_ <= 255 && g_ >= 0 && g_ <= 255 && b_ >= 0 && b_ <= 255 && alpha_ >= 0 && alpha_ <= 255); +} + +Color::Color(const std::string& hex_str_) + : hex_str(hex_str_) +{ + assert(hex_str_.size() == 7 || hex_str_.size() == 9); + assert(hex_str_[0] == '#'); + int red,green,blue,a; + std::istringstream(hex_str_.substr(1,2)) >> std::hex >> red; + std::istringstream(hex_str_.substr(3,2)) >> std::hex >> green; + std::istringstream(hex_str_.substr(5,2)) >> std::hex >> blue; + r = (float)red/255.; + g = (float)green/255.; + b = (float)blue/255.; + if(hex_str_.size() == 9) + { + std::istringstream(hex_str_.substr(7,2)) >> std::hex >> a; + alpha = (float)a/255.; + } + else + alpha = 1.; } \ No newline at end of file diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index 03c52692..dee7addd 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -29,6 +29,7 @@ namespace codac2 explicit Color(float r_, float g_, float b_, float alpha_ = 1.); explicit Color(int r_, int g_, int b_, int alpha_ = 255); + explicit Color(const std::string& hex_str_); static Color none() { return Color(255, 255, 255, 0 ); }; static Color black(float alpha = 1) { return Color(0, 0, 0, (int)(alpha*255)); }; From 60a397e9b5c17d2470efc4f5a283a2ab5799275d Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 22 Oct 2024 14:59:55 +0200 Subject: [PATCH 006/102] [ctc] added CtcEmpty and CtcIdentity + binding. --- python/src/core/CMakeLists.txt | 2 ++ python/src/core/codac2_py_core.cpp | 4 +++ .../core/contractors/codac2_py_CtcEmpty.cpp | 35 +++++++++++++++++++ .../contractors/codac2_py_CtcIdentity.cpp | 35 +++++++++++++++++++ src/core/CMakeLists.txt | 4 +++ src/core/contractors/codac2_CtcEmpty.cpp | 22 ++++++++++++ src/core/contractors/codac2_CtcEmpty.h | 25 +++++++++++++ src/core/contractors/codac2_CtcFixpoint.h | 2 +- src/core/contractors/codac2_CtcIdentity.cpp | 20 +++++++++++ src/core/contractors/codac2_CtcIdentity.h | 25 +++++++++++++ 10 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 python/src/core/contractors/codac2_py_CtcEmpty.cpp create mode 100644 python/src/core/contractors/codac2_py_CtcIdentity.cpp create mode 100644 src/core/contractors/codac2_CtcEmpty.cpp create mode 100644 src/core/contractors/codac2_CtcEmpty.h create mode 100644 src/core/contractors/codac2_CtcIdentity.cpp create mode 100644 src/core/contractors/codac2_CtcIdentity.h diff --git a/python/src/core/CMakeLists.txt b/python/src/core/CMakeLists.txt index 3e806496..3b632b38 100644 --- a/python/src/core/CMakeLists.txt +++ b/python/src/core/CMakeLists.txt @@ -13,8 +13,10 @@ contractors/codac2_py_Ctc.h contractors/codac2_py_CtcAction.cpp contractors/codac2_py_CtcCartProd.cpp + contractors/codac2_py_CtcEmpty.cpp contractors/codac2_py_CtcFixpoint.cpp contractors/codac2_py_CtcInnerOuter.cpp + contractors/codac2_py_CtcIdentity.cpp contractors/codac2_py_CtcInter.cpp contractors/codac2_py_CtcInverse.h contractors/codac2_py_CtcInverseNotIn.h diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index 8d2bcfc6..6595814a 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -31,7 +31,9 @@ void export_OctaSym(py::module& m); py::class_,pyCtcIntervalVector> export_CtcIntervalVector(py::module& m/*, py::class_& py_ctc*/); void export_CtcAction(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcCartProd(py::module& m, py::class_,pyCtcIntervalVector>& ctc); +void export_CtcEmpty(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcFixpoint(py::module& m, py::class_,pyCtcIntervalVector>& ctc); +void export_CtcIdentity(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcInnerOuter(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcInter(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcLazy(py::module& m, py::class_,pyCtcIntervalVector>& ctc); @@ -121,7 +123,9 @@ PYBIND11_MODULE(_core, m) auto py_ctc_iv = export_CtcIntervalVector(m/*,py_ctc*/); export_CtcAction(m, py_ctc_iv); export_CtcCartProd(m, py_ctc_iv); + export_CtcEmpty(m, py_ctc_iv); export_CtcFixpoint(m, py_ctc_iv); + export_CtcIdentity(m, py_ctc_iv); export_CtcInnerOuter(m, py_ctc_iv); export_CtcInter(m, py_ctc_iv); export_CtcInverse(m,"CtcInverse_Interval",py_ctc_iv); diff --git a/python/src/core/contractors/codac2_py_CtcEmpty.cpp b/python/src/core/contractors/codac2_py_CtcEmpty.cpp new file mode 100644 index 00000000..cb07b849 --- /dev/null +++ b/python/src/core/contractors/codac2_py_CtcEmpty.cpp @@ -0,0 +1,35 @@ +/** + * Codac binding (core) + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include "codac2_py_Ctc.h" +#include "codac2_py_CtcEmpty_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py): + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +void export_CtcEmpty(py::module& m, py::class_,pyCtcIntervalVector>& pyctc) +{ + py::class_ exported(m, "CtcEmpty", pyctc, CTCEMPTY_MAIN); + exported + + .def(py::init(), + CTCEMPTY_CTCEMPTY_SIZET + "n"_a) + + .def(CONTRACT_BOX_METHOD(CtcEmpty, + VOID_CTCEMPTY_CONTRACT_INTERVALVECTOR_REF_CONST)) + + ; +} \ No newline at end of file diff --git a/python/src/core/contractors/codac2_py_CtcIdentity.cpp b/python/src/core/contractors/codac2_py_CtcIdentity.cpp new file mode 100644 index 00000000..c39cd587 --- /dev/null +++ b/python/src/core/contractors/codac2_py_CtcIdentity.cpp @@ -0,0 +1,35 @@ +/** + * Codac binding (core) + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include "codac2_py_Ctc.h" +#include "codac2_py_CtcIdentity_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py): + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +void export_CtcIdentity(py::module& m, py::class_,pyCtcIntervalVector>& pyctc) +{ + py::class_ exported(m, "CtcIdentity", pyctc, CTCIDENTITY_MAIN); + exported + + .def(py::init(), + CTCIDENTITY_CTCIDENTITY_SIZET + "n"_a) + + .def(CONTRACT_BOX_METHOD(CtcIdentity, + VOID_CTCIDENTITY_CONTRACT_INTERVALVECTOR_REF_CONST)) + + ; +} \ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5c1c9e6c..fd648439 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -19,8 +19,12 @@ ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcDist.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcEllipse.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcEllipse.h + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcEmpty.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcEmpty.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcFixpoint.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcFixpoint.h + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcIdentity.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcIdentity.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcInnerOuter.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcInter.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcInverse.h diff --git a/src/core/contractors/codac2_CtcEmpty.cpp b/src/core/contractors/codac2_CtcEmpty.cpp new file mode 100644 index 00000000..3ed1e9c9 --- /dev/null +++ b/src/core/contractors/codac2_CtcEmpty.cpp @@ -0,0 +1,22 @@ +/** + * codac2_CtcEmpty.cp + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_CtcEmpty.h" + +using namespace std; +using namespace codac2; + +CtcEmpty::CtcEmpty(size_t n) + : Ctc(n) +{ } + +void CtcEmpty::contract(IntervalVector& x) const +{ + x.set_empty(); +} \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcEmpty.h b/src/core/contractors/codac2_CtcEmpty.h new file mode 100644 index 00000000..11212f88 --- /dev/null +++ b/src/core/contractors/codac2_CtcEmpty.h @@ -0,0 +1,25 @@ +/** + * \file codac2_CtcEmpty.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include "codac2_CtcWrapper.h" +#include "codac2_IntervalVector.h" + +namespace codac2 +{ + class CtcEmpty : public Ctc + { + public: + + CtcEmpty(size_t n); + + void contract(IntervalVector& x) const; + }; +} \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcFixpoint.h b/src/core/contractors/codac2_CtcFixpoint.h index d84ab33a..785693a4 100644 --- a/src/core/contractors/codac2_CtcFixpoint.h +++ b/src/core/contractors/codac2_CtcFixpoint.h @@ -2,7 +2,7 @@ * \file codac2_CtcFixpoint.h * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou + * \author Simon Rohou, Luc Jaulin * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ diff --git a/src/core/contractors/codac2_CtcIdentity.cpp b/src/core/contractors/codac2_CtcIdentity.cpp new file mode 100644 index 00000000..e506819a --- /dev/null +++ b/src/core/contractors/codac2_CtcIdentity.cpp @@ -0,0 +1,20 @@ +/** + * codac2_CtcIdentity.cp + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_CtcIdentity.h" + +using namespace std; +using namespace codac2; + +CtcIdentity::CtcIdentity(size_t n) + : Ctc(n) +{ } + +void CtcIdentity::contract(IntervalVector& x) const +{ } \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcIdentity.h b/src/core/contractors/codac2_CtcIdentity.h new file mode 100644 index 00000000..cdb18973 --- /dev/null +++ b/src/core/contractors/codac2_CtcIdentity.h @@ -0,0 +1,25 @@ +/** + * \file codac2_CtcIdentity.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include "codac2_CtcWrapper.h" +#include "codac2_IntervalVector.h" + +namespace codac2 +{ + class CtcIdentity : public Ctc + { + public: + + CtcIdentity(size_t n); + + void contract(IntervalVector& x) const; + }; +} \ No newline at end of file From ec9b374b43e68213d98dc2865e295ce7e0ab8252 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 22 Oct 2024 15:01:18 +0200 Subject: [PATCH 007/102] [graphics] added example for html color --- examples/00_graphics/graphic_examples.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index c333a826..97777710 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -44,4 +44,5 @@ fig2.draw_polygone([[2,4.5],[4,4.5],[4.2,3.5],[3.5,3]], [Color.none(),Color.green(0.5)]) fig2.draw_polyline([[-0.8,0],[0,1.5]], 0.2, [Color.red(),Color.black(0.3)]) fig2.draw_ellipse([1,1],[0.5,2], 0.2, [Color.blue(),Color.blue(0.3)]) -fig2.draw_point([2,2], [Color.red(),Color.yellow(0.5)]) \ No newline at end of file +fig2.draw_point([2,2], [Color.red(),Color.yellow(0.5)]) +fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) \ No newline at end of file From 43c2b1986c31516095df8e8f6b769a4c92eaf014 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Wed, 23 Oct 2024 09:59:29 +0200 Subject: [PATCH 008/102] [ctc] added CtcInter(size_t n) constructor + binding --- python/src/core/contractors/codac2_py_CtcInter.cpp | 4 ++++ python/src/core/contractors/codac2_py_CtcUnion.cpp | 4 ++++ src/core/contractors/codac2_CtcInter.h | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/python/src/core/contractors/codac2_py_CtcInter.cpp b/python/src/core/contractors/codac2_py_CtcInter.cpp index 5d1f02ab..a8211a26 100644 --- a/python/src/core/contractors/codac2_py_CtcInter.cpp +++ b/python/src/core/contractors/codac2_py_CtcInter.cpp @@ -24,6 +24,10 @@ void export_CtcInter(py::module& m, py::class_,pyCtcInte py::class_> exported(m, "CtcInter", pyctc, CTCINTER_MAIN); exported + .def(py::init(), + CTCINTER_X_CTCINTER_SIZET, + "n"_a) + .def(py::init( [](const CtcBase& c) { diff --git a/python/src/core/contractors/codac2_py_CtcUnion.cpp b/python/src/core/contractors/codac2_py_CtcUnion.cpp index 9282c873..fcb1e4a8 100644 --- a/python/src/core/contractors/codac2_py_CtcUnion.cpp +++ b/python/src/core/contractors/codac2_py_CtcUnion.cpp @@ -24,6 +24,10 @@ void export_CtcUnion(py::module& m, py::class_,pyCtcInte py::class_> exported(m, "CtcUnion", pyctc, CTCUNION_MAIN); exported + .def(py::init(), + CTCUNION_X_CTCUNION_SIZET, + "n"_a) + .def(py::init( [](const CtcBase& c) { diff --git a/src/core/contractors/codac2_CtcInter.h b/src/core/contractors/codac2_CtcInter.h index 77e89d12..a8718698 100644 --- a/src/core/contractors/codac2_CtcInter.h +++ b/src/core/contractors/codac2_CtcInter.h @@ -21,6 +21,15 @@ namespace codac2 { public: + explicit CtcInter(size_t n) + : Ctc,X>(n) + { + if constexpr(std::is_same_v) + { + assert(n == 1); + } + } + template requires (IsCtcBaseOrPtr && !std::is_same_v,C>) CtcInter(const C& c) From da4e041c3d2a50d2ba56824e73829b36fea76739 Mon Sep 17 00:00:00 2001 From: godardma Date: Thu, 24 Oct 2024 16:11:53 +0200 Subject: [PATCH 009/102] [graphics] early ColorMap structure --- src/graphics/CMakeLists.txt | 2 ++ src/graphics/styles/codac2_ColorMap.cpp | 10 +++++++++ src/graphics/styles/codac2_ColorMap.h | 29 +++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 src/graphics/styles/codac2_ColorMap.cpp create mode 100644 src/graphics/styles/codac2_ColorMap.h diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt index 7b38751b..c18ba4b8 100644 --- a/src/graphics/CMakeLists.txt +++ b/src/graphics/CMakeLists.txt @@ -22,6 +22,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_Color.cpp ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_Color.h + ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.h ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_StyleProperties.cpp ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_StyleProperties.h ) diff --git a/src/graphics/styles/codac2_ColorMap.cpp b/src/graphics/styles/codac2_ColorMap.cpp new file mode 100644 index 00000000..c10a8007 --- /dev/null +++ b/src/graphics/styles/codac2_ColorMap.cpp @@ -0,0 +1,10 @@ +/** + * codac2_ColorMap.cpp + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Maël Godard + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_ColorMap.h" \ No newline at end of file diff --git a/src/graphics/styles/codac2_ColorMap.h b/src/graphics/styles/codac2_ColorMap.h new file mode 100644 index 00000000..9244579f --- /dev/null +++ b/src/graphics/styles/codac2_ColorMap.h @@ -0,0 +1,29 @@ +/** + * \file codac2_ColorMap.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Maël Godard + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include +#include "codac2_Color.h" + +namespace codac2 +{ + /** + * \struct ColorMap + * \brief Represents a set of RGB values + */ + struct ColorMap + { + std::map m_colormap; //!< map of colors + + void add_color_point(Color color, float index); + + static ColorMap haxby(); + }; +} \ No newline at end of file From 8d50269d1be52f6db0f3f21a3c619763b6cd416e Mon Sep 17 00:00:00 2001 From: godardma Date: Thu, 24 Oct 2024 17:22:31 +0200 Subject: [PATCH 010/102] [graphics] HAXBY ColorMap + Binding + example --- examples/00_graphics/graphic_examples.py | 12 +++- python/src/graphics/CMakeLists.txt | 1 + python/src/graphics/codac2_py_graphics.cpp | 2 + .../src/graphics/styles/codac2_py_Color.cpp | 3 + .../graphics/styles/codac2_py_ColorMap.cpp | 45 ++++++++++++ src/graphics/styles/codac2_Color.cpp | 4 ++ src/graphics/styles/codac2_Color.h | 1 + src/graphics/styles/codac2_ColorMap.cpp | 69 ++++++++++++++++++- src/graphics/styles/codac2_ColorMap.h | 12 +++- 9 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 python/src/graphics/styles/codac2_py_ColorMap.cpp diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index 97777710..cdaeba17 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -45,4 +45,14 @@ fig2.draw_polyline([[-0.8,0],[0,1.5]], 0.2, [Color.red(),Color.black(0.3)]) fig2.draw_ellipse([1,1],[0.5,2], 0.2, [Color.blue(),Color.blue(0.3)]) fig2.draw_point([2,2], [Color.red(),Color.yellow(0.5)]) -fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) \ No newline at end of file +fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) + +fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) +fig3.set_axes(axis(0,[-1,21]), axis(1,[-0.5,1.5])) +fig3.set_window_properties([250,250],[500,500]) + +cmap=ColorMap.HAXBY + +for i in range (20): + ratio=i/20 + fig3.draw_box([[i,i+1],[0,1]],[cmap.color(ratio),cmap.color(ratio)]) \ No newline at end of file diff --git a/python/src/graphics/CMakeLists.txt b/python/src/graphics/CMakeLists.txt index 29bd2047..8b5add11 100644 --- a/python/src/graphics/CMakeLists.txt +++ b/python/src/graphics/CMakeLists.txt @@ -12,6 +12,7 @@ paver/codac2_py_drawwhilepaving.cpp styles/codac2_py_Color.cpp + styles/codac2_py_ColorMap.cpp styles/codac2_py_StyleProperties.cpp ) diff --git a/python/src/graphics/codac2_py_graphics.cpp b/python/src/graphics/codac2_py_graphics.cpp index 5ae28b1d..c5f9b520 100644 --- a/python/src/graphics/codac2_py_graphics.cpp +++ b/python/src/graphics/codac2_py_graphics.cpp @@ -22,6 +22,7 @@ void export_drawwhilepaving(py::module& m); // styles void export_Color(py::module& m); +void export_ColorMap(py::module& m); void export_StyleProperties(py::module& m); @@ -31,6 +32,7 @@ PYBIND11_MODULE(_graphics, m) // styles export_Color(m); + export_ColorMap(m); export_StyleProperties(m); // figures diff --git a/python/src/graphics/styles/codac2_py_Color.cpp b/python/src/graphics/styles/codac2_py_Color.cpp index f86cfdec..1f6abda7 100644 --- a/python/src/graphics/styles/codac2_py_Color.cpp +++ b/python/src/graphics/styles/codac2_py_Color.cpp @@ -30,6 +30,9 @@ void export_Color(py::module& m) .def_readwrite("alpha", &Color::alpha) .def_readwrite("hex_str", &Color::hex_str) + .def(py::init<>(), + COLOR_COLOR) + .def(py::init(), COLOR_COLOR_INT_INT_INT_INT, "r"_a, "g"_a, "b"_a, "alpha"_a=255) diff --git a/python/src/graphics/styles/codac2_py_ColorMap.cpp b/python/src/graphics/styles/codac2_py_ColorMap.cpp new file mode 100644 index 00000000..2a955fdb --- /dev/null +++ b/python/src/graphics/styles/codac2_py_ColorMap.cpp @@ -0,0 +1,45 @@ +/** + * Codac binding (core) + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Maël Godard + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include "codac2_py_ColorMap_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py): + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +void export_ColorMap(py::module& m) +{ + py::class_ exported_colormap(m, "ColorMap", COLORMAP_MAIN); + exported_colormap + + .def_readwrite("colormap", &ColorMap::colormap) + + .def(py::init<>(), + COLORMAP_COLORMAP) + + .def("add_color_point", &ColorMap::add_color_point, + VOID_COLORMAP_ADD_COLOR_POINT_COLOR_FLOAT, + "color"_a, "index"_a) + + .def("color", &ColorMap::color, + COLOR_COLORMAP_COLOR_FLOAT_CONST, + "r"_a) + + // Predifined color maps + + .def_readonly_static("HAXBY", &ColorMap::HAXBY, + CONST_COLORMAP_COLORMAP_HAXBY) + + ; +} \ No newline at end of file diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index 05a09905..2d967b10 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -12,6 +12,10 @@ using namespace std; using namespace codac2; +Color::Color() + : r(1.), g(1.), b(1.), alpha(1.), hex_str("#FFFFFF") +{} + Color::Color(float r_, float g_, float b_, float alpha_) : r(r_), g(g_), b(b_), alpha(alpha_), hex_str([&] diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index dee7addd..b5fa0481 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -27,6 +27,7 @@ namespace codac2 float alpha = 1.; ///< opacity, value between 0. (transparent) and 1. (opaque) std::string hex_str; ///< represents an RGB value in a HTML standard + explicit Color(); explicit Color(float r_, float g_, float b_, float alpha_ = 1.); explicit Color(int r_, int g_, int b_, int alpha_ = 255); explicit Color(const std::string& hex_str_); diff --git a/src/graphics/styles/codac2_ColorMap.cpp b/src/graphics/styles/codac2_ColorMap.cpp index c10a8007..46719ce0 100644 --- a/src/graphics/styles/codac2_ColorMap.cpp +++ b/src/graphics/styles/codac2_ColorMap.cpp @@ -7,4 +7,71 @@ * \license GNU Lesser General Public License (LGPL) */ -#include "codac2_ColorMap.h" \ No newline at end of file +#include "codac2_ColorMap.h" + +using namespace std; +using namespace codac2; + + +ColorMap::ColorMap() + : colormap() +{} + +void ColorMap::add_color_point(Color color, float index) +{ + colormap[index] = color; +} + +Color ColorMap::color(float r) const +{ + assert (colormap.size() >= 2); + if(std::isnan(r)) // undefined ratio + return Color((float)0.5, 0.5, 0.5); + assert(Interval(0.,1.).contains(r)); + + Interval map_domain = Interval(colormap.begin()->first,prev(colormap.end())->first); + float real_index = map_domain.lb() + r*map_domain.diam(); + + if(colormap.find(real_index) == colormap.end()) // color interpolation + { + typename map::const_iterator it_ub; + it_ub = colormap.lower_bound(real_index); + Color color_lb = prev(it_ub)->second; + Color color_ub = it_ub->second; + + float local_ratio = (real_index - prev(it_ub)->first) / (it_ub->first - prev(it_ub)->first); + + return Color((float)(color_lb.r + (color_ub.r - color_lb.r) * local_ratio), + (float)(color_lb.g + (color_ub.g - color_lb.g) * local_ratio), + (float)(color_lb.b + (color_ub.b - color_lb.b) * local_ratio), + (float)(color_lb.alpha + (color_ub.alpha - color_lb.alpha) * local_ratio)); + + } + + else // color key + return colormap.at(real_index); +} + +ColorMap make_haxby() + { + ColorMap map; + map.add_color_point(Color(39,90,211), 0); + map.add_color_point(Color(40,123,245), 1); + map.add_color_point(Color(45,155,253), 2); + map.add_color_point(Color(73,209,255), 3); + map.add_color_point(Color(100,230,254), 4); + map.add_color_point(Color(118,235,226), 5); + map.add_color_point(Color(135,236,187), 6); + map.add_color_point(Color(194,252,165), 7); + map.add_color_point(Color(217,251,151), 8); + map.add_color_point(Color(233,241,131), 9); + map.add_color_point(Color(252,201,96), 10); + map.add_color_point(Color(255,184,84), 11); + map.add_color_point(Color(255,170,75), 12); + map.add_color_point(Color(255,167,83), 13); + map.add_color_point(Color(255,200,158), 14); + map.add_color_point(Color(255,233,217), 15); + return map; + } + +const ColorMap ColorMap::HAXBY = make_haxby(); \ No newline at end of file diff --git a/src/graphics/styles/codac2_ColorMap.h b/src/graphics/styles/codac2_ColorMap.h index 9244579f..e087f4c0 100644 --- a/src/graphics/styles/codac2_ColorMap.h +++ b/src/graphics/styles/codac2_ColorMap.h @@ -10,7 +10,10 @@ #pragma once #include +#include #include "codac2_Color.h" +#include "codac2_Interval.h" +#include"codac2_assert.h" namespace codac2 { @@ -20,10 +23,15 @@ namespace codac2 */ struct ColorMap { - std::map m_colormap; //!< map of colors + + ColorMap(); + + std::map colormap; //!< map of colors void add_color_point(Color color, float index); - static ColorMap haxby(); + Color color (float r) const; + + static const ColorMap HAXBY; }; } \ No newline at end of file From 147517e909f6e3d6e530d0d18b815fe233ef7908 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 24 Oct 2024 20:19:58 +0200 Subject: [PATCH 011/102] [ctc] added CtcCtcBoundary, CtcPolygon + binding + tests --- python/src/core/CMakeLists.txt | 2 + python/src/core/codac2_py_core.cpp | 4 + .../contractors/codac2_py_CtcCtcBoundary.cpp | 41 ++++++++ .../core/contractors/codac2_py_CtcPolygon.cpp | 38 ++++++++ src/core/CMakeLists.txt | 4 + .../contractors/codac2_CtcCtcBoundary.cpp | 52 +++++++++++ src/core/contractors/codac2_CtcCtcBoundary.h | 38 ++++++++ src/core/contractors/codac2_CtcPolygon.cpp | 45 +++++++++ src/core/contractors/codac2_CtcPolygon.h | 25 +++++ src/core/separators/codac2_SepPolygon.cpp | 1 + src/core/separators/codac2_SepPolygon.h | 1 - tests/CMakeLists.txt | 2 + .../codac2_tests_CtcCtcBoundary.cpp | 58 ++++++++++++ .../codac2_tests_CtcCtcBoundary.py | 48 ++++++++++ .../contractors/codac2_tests_CtcPolygon.cpp | 93 +++++++++++++++++++ .../contractors/codac2_tests_CtcPolygon.py | 91 ++++++++++++++++++ .../codac2_tests_SepCtcBoundary.cpp | 6 +- .../separators/codac2_tests_SepCtcBoundary.py | 6 +- 18 files changed, 548 insertions(+), 7 deletions(-) create mode 100644 python/src/core/contractors/codac2_py_CtcCtcBoundary.cpp create mode 100644 python/src/core/contractors/codac2_py_CtcPolygon.cpp create mode 100644 src/core/contractors/codac2_CtcCtcBoundary.cpp create mode 100644 src/core/contractors/codac2_CtcCtcBoundary.h create mode 100644 src/core/contractors/codac2_CtcPolygon.cpp create mode 100644 src/core/contractors/codac2_CtcPolygon.h create mode 100644 tests/core/contractors/codac2_tests_CtcCtcBoundary.cpp create mode 100644 tests/core/contractors/codac2_tests_CtcCtcBoundary.py create mode 100644 tests/core/contractors/codac2_tests_CtcPolygon.cpp create mode 100644 tests/core/contractors/codac2_tests_CtcPolygon.py diff --git a/python/src/core/CMakeLists.txt b/python/src/core/CMakeLists.txt index 3b632b38..d114d4ea 100644 --- a/python/src/core/CMakeLists.txt +++ b/python/src/core/CMakeLists.txt @@ -13,6 +13,7 @@ contractors/codac2_py_Ctc.h contractors/codac2_py_CtcAction.cpp contractors/codac2_py_CtcCartProd.cpp + contractors/codac2_py_CtcCtcBoundary.cpp contractors/codac2_py_CtcEmpty.cpp contractors/codac2_py_CtcFixpoint.cpp contractors/codac2_py_CtcInnerOuter.cpp @@ -23,6 +24,7 @@ contractors/codac2_py_CtcLazy.cpp contractors/codac2_py_CtcNot.cpp contractors/codac2_py_CtcPolar.cpp + contractors/codac2_py_CtcPolygon.cpp contractors/codac2_py_CtcProj.cpp contractors/codac2_py_CtcSegment.cpp contractors/codac2_py_CtcUnion.cpp diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index 6595814a..fbee9d6d 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -31,6 +31,7 @@ void export_OctaSym(py::module& m); py::class_,pyCtcIntervalVector> export_CtcIntervalVector(py::module& m/*, py::class_& py_ctc*/); void export_CtcAction(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcCartProd(py::module& m, py::class_,pyCtcIntervalVector>& ctc); +void export_CtcCtcBoundary(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcEmpty(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcFixpoint(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcIdentity(py::module& m, py::class_,pyCtcIntervalVector>& ctc); @@ -39,6 +40,7 @@ void export_CtcInter(py::module& m, py::class_,pyCtcInte void export_CtcLazy(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcNot(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcPolar(py::module& m, py::class_,pyCtcIntervalVector>& ctc); +void export_CtcPolygon(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcProj(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcSegment(py::module& m, py::class_,pyCtcIntervalVector>& ctc); void export_CtcUnion(py::module& m, py::class_,pyCtcIntervalVector>& ctc); @@ -123,6 +125,7 @@ PYBIND11_MODULE(_core, m) auto py_ctc_iv = export_CtcIntervalVector(m/*,py_ctc*/); export_CtcAction(m, py_ctc_iv); export_CtcCartProd(m, py_ctc_iv); + export_CtcCtcBoundary(m, py_ctc_iv); export_CtcEmpty(m, py_ctc_iv); export_CtcFixpoint(m, py_ctc_iv); export_CtcIdentity(m, py_ctc_iv); @@ -135,6 +138,7 @@ PYBIND11_MODULE(_core, m) export_CtcLazy(m, py_ctc_iv); export_CtcNot(m, py_ctc_iv); export_CtcPolar(m, py_ctc_iv); + export_CtcPolygon(m, py_ctc_iv); export_CtcProj(m, py_ctc_iv); export_CtcSegment(m, py_ctc_iv); export_CtcUnion(m, py_ctc_iv); diff --git a/python/src/core/contractors/codac2_py_CtcCtcBoundary.cpp b/python/src/core/contractors/codac2_py_CtcCtcBoundary.cpp new file mode 100644 index 00000000..fdd42b41 --- /dev/null +++ b/python/src/core/contractors/codac2_py_CtcCtcBoundary.cpp @@ -0,0 +1,41 @@ +/** + * Codac binding (core) + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include +#include +#include "codac2_py_Ctc.h" +#include "codac2_py_CtcCtcBoundary_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py): + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +void export_CtcCtcBoundary(py::module& m, py::class_,pyCtcIntervalVector>& pyctc) +{ + py::class_ exported(m, "CtcCtcBoundary", pyctc, CTCCTCBOUNDARY_MAIN); + exported + + .def(py::init( + [](const CtcBase& ctc_boundary, const std::function& inside_test) + { + return std::make_unique(ctc_boundary.copy(),inside_test); + }), + CTCCTCBOUNDARY_CTCCTCBOUNDARY_CONST_C_REF_CONST_FUNCTION_BOOLINTERVAL_CONST_VECTOR_REF__REF, + "ctc_boundary"_a, "inside_test"_a) + + .def(CONTRACT_BOX_METHOD(CtcCtcBoundary, + VOID_CTCCTCBOUNDARY_CONTRACT_INTERVALVECTOR_REF_CONST)) + + ; +} \ No newline at end of file diff --git a/python/src/core/contractors/codac2_py_CtcPolygon.cpp b/python/src/core/contractors/codac2_py_CtcPolygon.cpp new file mode 100644 index 00000000..8ce08d8b --- /dev/null +++ b/python/src/core/contractors/codac2_py_CtcPolygon.cpp @@ -0,0 +1,38 @@ +/** + * Codac binding (core) + * ---------------------------------------------------------------------------- + * \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_Ctc.h" +#include "codac2_py_CtcPolygon_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py): + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +void export_CtcPolygon(py::module& m, py::class_,pyCtcIntervalVector>& pyctc) +{ + py::class_ exported(m, "CtcPolygon", pyctc, CTCPOLYGON_MAIN); + exported + + .def(py::init(), + CTCPOLYGON_CTCPOLYGON_CONST_POLYGON_REF, + "p"_a) + + .def(CONTRACT_BOX_METHOD(CtcPolygon, + VOID_CTCPOLYGON_CONTRACT_INTERVALVECTOR_REF_CONST)) + + ; + + py::implicitly_convertible(); +} \ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e1e96034..db305b75 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -15,6 +15,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcAction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcAction.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcCartProd.h + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcCtcBoundary.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcCtcBoundary.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcDist.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcDist.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcEllipse.cpp @@ -35,6 +37,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcUnion.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcPolar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcPolar.h + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcPolygon.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcPolygon.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcProj.cpp ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcProj.h ${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcSegment.cpp diff --git a/src/core/contractors/codac2_CtcCtcBoundary.cpp b/src/core/contractors/codac2_CtcCtcBoundary.cpp new file mode 100644 index 00000000..ae8fba92 --- /dev/null +++ b/src/core/contractors/codac2_CtcCtcBoundary.cpp @@ -0,0 +1,52 @@ +/** + * codac2_CtcCtcBoundary.cpp + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Benoit Desrochers + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_CtcCtcBoundary.h" + +using namespace std; +using namespace codac2; + +void CtcCtcBoundary::contract(IntervalVector& x) const +{ + assert_release(x.size() == this->size()); + + size_t attempt_nb = 5; + IntervalVector prev_x(x); + _ctc_boundary.front().contract(x); + + for(const auto& b : prev_x.diff(x,false)) + { + if(b.is_empty()) + continue; + + Vector m = b.mid(); // first try: midpoint of the box + BoolInterval d; + size_t k = 0; + + do + { + d = _inside_test(m); + if(d == BoolInterval::UNKNOWN) + m = b.rand(); // now, trying a random vector in the box + } while(d == BoolInterval::UNKNOWN && k++ < attempt_nb); + + switch(d) + { + case BoolInterval::TRUE: + case BoolInterval::UNKNOWN: + x |= b; + break; + case BoolInterval::FALSE: + break; + case BoolInterval::EMPTY: + assert(false && "BoolInterval::EMPTY should not happen"); + break; + } + } +} \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcCtcBoundary.h b/src/core/contractors/codac2_CtcCtcBoundary.h new file mode 100644 index 00000000..b22c3383 --- /dev/null +++ b/src/core/contractors/codac2_CtcCtcBoundary.h @@ -0,0 +1,38 @@ +/** + * \file codac2_CtcCtcBoundary.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Benoit Desrochers + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include +#include "codac2_Ctc.h" +#include "codac2_IntervalVector.h" +#include "codac2_Collection.h" +#include "codac2_BoolInterval.h" +#include "codac2_template_tools.h" + +namespace codac2 +{ + class CtcCtcBoundary : public Ctc + { + public: + + template + requires IsCtcBaseOrPtr + CtcCtcBoundary(const C& ctc_boundary, const std::function& inside_test) + : Ctc(size_of(ctc_boundary)), _ctc_boundary(ctc_boundary), _inside_test(inside_test) + { } + + void contract(IntervalVector& x) const; + + protected: + + const Collection> _ctc_boundary; + const std::function _inside_test; + }; +} \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcPolygon.cpp b/src/core/contractors/codac2_CtcPolygon.cpp new file mode 100644 index 00000000..e775b8d8 --- /dev/null +++ b/src/core/contractors/codac2_CtcPolygon.cpp @@ -0,0 +1,45 @@ +/** + * CtcPolygon.cpp + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Benoit Desrochers + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include "codac2_CtcPolygon.h" +#include "codac2_CtcUnion.h" +#include "codac2_CtcSegment.h" +#include "codac2_geometry.h" + +using namespace std; + +namespace codac2 +{ + CtcPolygon::CtcPolygon(const Polygon& p) + : CtcCtcBoundary( + + // Contractor on the boundary + [p] + { + CtcUnion ctc_segments(2); + for(const auto& edge_i : p.edges()) + ctc_segments |= CtcSegment(edge_i[0],edge_i[1]); + return ctc_segments; + }(), + + // Tests if a point of a box is inside the polygon + [p](const Vector& x) -> BoolInterval + { + assert_release(x.size() == 2); + return p.contains(x); + } + ) + { } + + void CtcPolygon::contract(IntervalVector& x) const + { + CtcCtcBoundary::contract(x); + } +} \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcPolygon.h b/src/core/contractors/codac2_CtcPolygon.h new file mode 100644 index 00000000..eeb632f8 --- /dev/null +++ b/src/core/contractors/codac2_CtcPolygon.h @@ -0,0 +1,25 @@ +/** + * \file codac2_CtcPolygon.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Benoit Desrochers + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include "codac2_Polygon.h" +#include "codac2_CtcCtcBoundary.h" +#include "codac2_CtcUnion.h" + +namespace codac2 +{ + class CtcPolygon : public CtcCtcBoundary + { + public: + + CtcPolygon(const Polygon& p); + void contract(IntervalVector& x) const; + }; +} \ No newline at end of file diff --git a/src/core/separators/codac2_SepPolygon.cpp b/src/core/separators/codac2_SepPolygon.cpp index 4fb832ea..302dc16c 100644 --- a/src/core/separators/codac2_SepPolygon.cpp +++ b/src/core/separators/codac2_SepPolygon.cpp @@ -9,6 +9,7 @@ #include #include "codac2_SepPolygon.h" +#include "codac2_CtcUnion.h" #include "codac2_CtcSegment.h" #include "codac2_geometry.h" diff --git a/src/core/separators/codac2_SepPolygon.h b/src/core/separators/codac2_SepPolygon.h index 39f43732..ded41190 100644 --- a/src/core/separators/codac2_SepPolygon.h +++ b/src/core/separators/codac2_SepPolygon.h @@ -11,7 +11,6 @@ #include "codac2_Polygon.h" #include "codac2_SepCtcBoundary.h" -#include "codac2_CtcUnion.h" namespace codac2 { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 94c7d1b7..c976643a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,10 +28,12 @@ list(APPEND SRC_TESTS # listing files without extension core/contractors/codac2_tests_CtcAction core/contractors/codac2_tests_CtcCartProd + core/contractors/codac2_tests_CtcCtcBoundary core/contractors/codac2_tests_CtcFixpoint core/contractors/codac2_tests_CtcInverse core/contractors/codac2_tests_CtcInverseNotIn core/contractors/codac2_tests_CtcLazy + core/contractors/codac2_tests_CtcPolygon core/contractors/codac2_tests_CtcSegment core/contractors/codac2_tests_linear_ctc diff --git a/tests/core/contractors/codac2_tests_CtcCtcBoundary.cpp b/tests/core/contractors/codac2_tests_CtcCtcBoundary.cpp new file mode 100644 index 00000000..d9e95480 --- /dev/null +++ b/tests/core/contractors/codac2_tests_CtcCtcBoundary.cpp @@ -0,0 +1,58 @@ +/** + * Codac tests + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace codac2; + +BoolInterval test_inside_diamond(const Vector& x) +{ + if((x[1] < x[0]+1) && (x[1] > x[0]-1) && (x[1] < -x[0]+1) && (x[1] > -x[0]-1)) + return BoolInterval::TRUE; + else if(!(x[1] < x[0]+1) || !(x[1] > x[0]-1) || !(x[1] < -x[0]+1) || !(x[1] > -x[0]-1)) + return BoolInterval::FALSE; + else + return BoolInterval::UNKNOWN; +} + +TEST_CASE("CtcCtcBoundary") +{ + auto ctc_bound_diamond = CtcSegment({{-1},{0}}, {{0},{-1}}) | CtcSegment({{0},{-1}}, {{1},{0}}) + | CtcSegment({{1},{0}}, {{0},{1}}) | CtcSegment({{0},{1}}, {{-1},{0}}); + + CtcCtcBoundary ctc_diamond(ctc_bound_diamond,test_inside_diamond); + + //draw_while_paving(IntervalVector({{-2,2},{-2,2}}), ctc_diamond, 0.1); + + IntervalVector x(2); + ctc_diamond.contract(x); + //DefaultView::draw_box(x,Color::dark_green()); + CHECK(x == IntervalVector({{-1,1},{-1,1}})); + + x = IntervalVector({{0,10},{0,10}}); + ctc_diamond.contract(x); + //DefaultView::draw_box(x,Color::blue()); + CHECK(x == IntervalVector({{0,1},{0,1}})); + + x = IntervalVector({{0.2,10},{0.2,10}}); + ctc_diamond.contract(x); + //DefaultView::draw_box(x,Color::blue()); + CHECK(x == IntervalVector({{0.2,0.8},{0.2,0.8}})); + + x = IntervalVector({{0.5,10},{0.5,10}}); + ctc_diamond.contract(x); + //DefaultView::draw_box(x,Color::blue()); + CHECK(x == IntervalVector({{0.5},{0.5}})); +} \ No newline at end of file diff --git a/tests/core/contractors/codac2_tests_CtcCtcBoundary.py b/tests/core/contractors/codac2_tests_CtcCtcBoundary.py new file mode 100644 index 00000000..680ac875 --- /dev/null +++ b/tests/core/contractors/codac2_tests_CtcCtcBoundary.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Codac tests +# ---------------------------------------------------------------------------- +# \date 2024 +# \author Simon Rohou +# \copyright Copyright 2024 Codac Team +# \license GNU Lesser General Public License (LGPL) + +import unittest +from codac import * + +def test_inside_diamond(x): + if (x[1] < x[0]+1) and (x[1] > x[0]-1) and (x[1] < -x[0]+1) and (x[1] > -x[0]-1): + return BoolInterval.TRUE + elif not(x[1] < x[0]+1) or not(x[1] > x[0]-1) or not(x[1] < -x[0]+1) or not(x[1] > -x[0]-1): + return BoolInterval.FALSE + else: + return BoolInterval.UNKNOWN + +class TestCtcCtcBoundary(unittest.TestCase): + + def tests_CtcCtcBoundary(self): + + ctc_bound_diamond = CtcSegment([[-1],[0]], [[0],[-1]]) | CtcSegment([[0],[-1]], [[1],[0]]) \ + | CtcSegment([[1],[0]], [[0],[1]]) | CtcSegment([[0],[1]], [[-1],[0]]) + + ctc_diamond = CtcCtcBoundary(ctc_bound_diamond,test_inside_diamond) + #draw_while_paving(IntervalVector([[-2,2],[-2,2]]), ctc_diamond, 0.1) + + x = IntervalVector(2) + ctc_diamond.contract(x) + #self.assertTrue(x == IntervalVector([[-1,1],[-1,1]])) + + x = IntervalVector([[0,10],[0,10]]) + ctc_diamond.contract(x) + #self.assertTrue(x == IntervalVector([[0,1],[0,1]])) + + x = IntervalVector([[0.2,10],[0.2,10]]) + ctc_diamond.contract(x) + #self.assertTrue(x == IntervalVector([[0.2,0.8],[0.2,0.8]])) + + x = IntervalVector([[0.5,10],[0.5,10]]) + ctc_diamond.contract(x) + #self.assertTrue(x == IntervalVector([[0.5],[0.5]])) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/core/contractors/codac2_tests_CtcPolygon.cpp b/tests/core/contractors/codac2_tests_CtcPolygon.cpp new file mode 100644 index 00000000..ee23daa8 --- /dev/null +++ b/tests/core/contractors/codac2_tests_CtcPolygon.cpp @@ -0,0 +1,93 @@ +/** + * Codac tests + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include + +using namespace std; +using namespace codac2; + +TEST_CASE("CtcPolygon") +{ + CtcPolygon c({{3,-1},{3,4},{5,6},{-1,1}}); + + IntervalVector x(2); + c.contract(x); + CHECK(x == IntervalVector({{-1,5},{-1,6}})); + + x = IntervalVector({{3.02,3.16},{2.5,3.2}}); // possible bug + c.contract(x); + CHECK(x.is_empty()); +} + +TEST_CASE("CtcPolygon - tests from Codac1") +{ + // Polygone with hole + { + CtcPolygon c({ + // external border + {{6,-6},{7,9}}, + {{7,9},{0,5}}, + {{0,5},{-9,8}}, + {{-9,8},{-8,-9}}, + {{-8,-9},{6,-6}}, + // hole + {{-2,3},{3.5,2}}, + {{3.5,2},{1.5,0.5}}, + {{1.5,0.5},{3,-4}}, + {{3,-4},{-3,-3}}, + {{-3,-3},{-2,3}} + }); + + //draw_while_paving(IntervalVector({{-10,10},{-10,10}}), c, 0.1); + + // Check a box inside the hole + { + IntervalVector x = IntervalVector({{0},{0}}).inflate(0.5); + //DefaultView::draw_box(x,Color::purple()); + c.contract(x); + CHECK(x.is_empty()); + } + + // Check a box inside the polygon + { + IntervalVector x = IntervalVector({{5},{-5}}).inflate(0.5), _x(x); + //DefaultView::draw_box(x,Color::purple()); + c.contract(x); + CHECK(x == _x); + } + + // Check a box outside the polygon + { + IntervalVector x = IntervalVector({{-1},{8}}).inflate(0.5); + //DefaultView::draw_box(x,Color::purple()); + c.contract(x); + CHECK(x.is_empty()); + } + } + + { + CtcPolygon c({{6,-6},{7,9},{0,5},{-9,8},{-8,-9}}); + + // Check a box inside the polygon + { + IntervalVector x = IntervalVector({{5},{-5}}).inflate(0.5), _x(x); + c.contract(x); + CHECK(x == _x); + } + + // Check a box outside the polygon + { + IntervalVector x = IntervalVector({{-1},{8}}).inflate(0.5); + c.contract(x); + CHECK(x.is_empty()); + } + } +} \ No newline at end of file diff --git a/tests/core/contractors/codac2_tests_CtcPolygon.py b/tests/core/contractors/codac2_tests_CtcPolygon.py new file mode 100644 index 00000000..34810594 --- /dev/null +++ b/tests/core/contractors/codac2_tests_CtcPolygon.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python + +# Codac tests +# ---------------------------------------------------------------------------- +# \date 2024 +# \author Simon Rohou +# \copyright Copyright 2024 Codac Team +# \license GNU Lesser General Public License (LGPL) + +import unittest +from codac import * + +class TestCtcPolygon(unittest.TestCase): + + def tests_CtcPolygon(self): + + # Polygon, defined as a list of vertices + c = CtcPolygon([[3,-1],[3,4],[5,6],[-1,1]]) + + x = IntervalVector(2) + c.contract(x) + self.assertTrue(x == IntervalVector([[-1,5],[-1,6]])) + + x = IntervalVector([[3.02,3.16],[2.5,3.2]]) # possible bug + c.contract(x) + self.assertTrue(x.is_empty()) + + def tests_CtcPolygon_fromCodac1(self): + + # Polygone with hole, defined as a list of edges + + c = CtcPolygon([ + # external border + [[6,-6], [7,9]], + [[7,9], [0,5]], + [[0,5], [-9,8]], + [[-9,8], [-8,-9]], + [[-8,-9], [6,-6]], + # hole + [[-2,3], [3.5,2]], + [[3.5,2], [1.5,0.5]], + [[1.5,0.5], [3,-4]], + [[3,-4], [-3,-3]], + [[-3,-3], [-2,3]] + ]) + + #draw_while_paving(IntervalVector([[-10,10],[-10,10]]), c, 0.1) + + # Check a box inside the hole + + x = IntervalVector([[0],[0]]).inflate(0.5) + #DefaultView.draw_box(x,Color::purple()) + c.contract(x) + self.assertTrue(x.is_empty()) + + # Check a box inside the polygon + + x = IntervalVector([[5],[-5]]).inflate(0.5) + _x = IntervalVector(x) + #DefaultView.draw_box(x,Color::purple()) + c.contract(x) + self.assertTrue(x == _x) + + # Check a box outside the polygon + + x = IntervalVector([[-1],[8]]).inflate(0.5) + #DefaultView.draw_box(x,Color::purple()) + c.contract(x) + self.assertTrue(x.is_empty()) + + + # Other polygon, defined as a list of vertices + + c = CtcPolygon([[6,-6],[7,9],[0,5],[-9,8],[-8,-9]]) + + # Check a box inside the polygon + + x = IntervalVector([[5],[-5]]).inflate(0.5) + _x = IntervalVector(x) + c.contract(x) + self.assertTrue(x == _x) + + # Check a box outside the polygon + + x = IntervalVector([[-1],[8]]).inflate(0.5) + c.contract(x) + self.assertTrue(x.is_empty()) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/core/separators/codac2_tests_SepCtcBoundary.cpp b/tests/core/separators/codac2_tests_SepCtcBoundary.cpp index 6c668c22..23c71178 100644 --- a/tests/core/separators/codac2_tests_SepCtcBoundary.cpp +++ b/tests/core/separators/codac2_tests_SepCtcBoundary.cpp @@ -28,12 +28,12 @@ BoolInterval test_inside_diamond(const Vector& x) TEST_CASE("SepCtcBoundary") { - auto ctc_diamond = CtcSegment({{-1},{0}}, {{0},{-1}}) | CtcSegment({{0},{-1}}, {{1},{0}}) + auto ctc_bound_diamond = CtcSegment({{-1},{0}}, {{0},{-1}}) | CtcSegment({{0},{-1}}, {{1},{0}}) | CtcSegment({{1},{0}}, {{0},{1}}) | CtcSegment({{0},{1}}, {{-1},{0}}); - SepCtcBoundary sep_diamond(ctc_diamond,test_inside_diamond); + SepCtcBoundary sep_diamond(ctc_bound_diamond,test_inside_diamond); - //pave(IntervalVector({{-2,2},{-2,2}}), sep_diamond, 0.1); + //draw_while_paving(IntervalVector({{-2,2},{-2,2}}), sep_diamond, 0.1); IntervalVector x(2); auto xs = sep_diamond.separate(IntervalVector(2)); diff --git a/tests/core/separators/codac2_tests_SepCtcBoundary.py b/tests/core/separators/codac2_tests_SepCtcBoundary.py index cb0c4c49..830ea70c 100644 --- a/tests/core/separators/codac2_tests_SepCtcBoundary.py +++ b/tests/core/separators/codac2_tests_SepCtcBoundary.py @@ -22,11 +22,11 @@ class TestSepCtcBoundary(unittest.TestCase): def tests_SepCtcBoundary(self): - ctc_diamond = CtcSegment([[-1],[0]], [[0],[-1]]) | CtcSegment([[0],[-1]], [[1],[0]]) \ + ctc_bound_diamond = CtcSegment([[-1],[0]], [[0],[-1]]) | CtcSegment([[0],[-1]], [[1],[0]]) \ | CtcSegment([[1],[0]], [[0],[1]]) | CtcSegment([[0],[1]], [[-1],[0]]) - sep_diamond = SepCtcBoundary(ctc_diamond,test_inside_diamond) - #pave(IntervalVector([[-2,2],[-2,2]]), sep_diamond, 0.1) + sep_diamond = SepCtcBoundary(ctc_bound_diamond,test_inside_diamond) + #draw_while_paving(IntervalVector([[-2,2],[-2,2]]), sep_diamond, 0.1) x = IntervalVector(2) inner,outer = sep_diamond.separate(IntervalVector(2)) From 4e5d21ded7f4d397cb660d9b835a4880f5408046 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Fri, 25 Oct 2024 08:46:11 +0200 Subject: [PATCH 012/102] [graphics] Color class, added a comment --- python/src/graphics/styles/codac2_py_Color.cpp | 2 +- src/graphics/styles/codac2_Color.cpp | 6 ++++-- src/graphics/styles/codac2_Color.h | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/python/src/graphics/styles/codac2_py_Color.cpp b/python/src/graphics/styles/codac2_py_Color.cpp index f86cfdec..2227835e 100644 --- a/python/src/graphics/styles/codac2_py_Color.cpp +++ b/python/src/graphics/styles/codac2_py_Color.cpp @@ -38,7 +38,7 @@ void export_Color(py::module& m) COLOR_COLOR_FLOAT_FLOAT_FLOAT_FLOAT, "r"_a, "g"_a, "b"_a, "alpha"_a=1.) - .def(py::init(), + .def(py::init(), COLOR_COLOR_CONST_STRING_REF, "hex_str"_a) diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index 05a09905..8e6c6a78 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -38,6 +38,7 @@ Color::Color(const std::string& hex_str_) { assert(hex_str_.size() == 7 || hex_str_.size() == 9); assert(hex_str_[0] == '#'); + int red,green,blue,a; std::istringstream(hex_str_.substr(1,2)) >> std::hex >> red; std::istringstream(hex_str_.substr(3,2)) >> std::hex >> green; @@ -45,11 +46,12 @@ Color::Color(const std::string& hex_str_) r = (float)red/255.; g = (float)green/255.; b = (float)blue/255.; + + // Alpha (transparency) component may be appended to the #hexa notation. + // Value is '1' (max opacity) by default. if(hex_str_.size() == 9) { std::istringstream(hex_str_.substr(7,2)) >> std::hex >> a; alpha = (float)a/255.; } - else - alpha = 1.; } \ No newline at end of file diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index dee7addd..b3e3efd4 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -27,9 +27,9 @@ namespace codac2 float alpha = 1.; ///< opacity, value between 0. (transparent) and 1. (opaque) std::string hex_str; ///< represents an RGB value in a HTML standard - explicit Color(float r_, float g_, float b_, float alpha_ = 1.); - explicit Color(int r_, int g_, int b_, int alpha_ = 255); - explicit Color(const std::string& hex_str_); + explicit Color(float r, float g, float b, float alpha = 1.); + explicit Color(int r, int g, int b, int alpha = 255); + explicit Color(const std::string& hex_str); static Color none() { return Color(255, 255, 255, 0 ); }; static Color black(float alpha = 1) { return Color(0, 0, 0, (int)(alpha*255)); }; From 7b5a463b21d5a4c597078405b5fb09212e4508c7 Mon Sep 17 00:00:00 2001 From: godardma Date: Fri, 25 Oct 2024 17:41:27 +0200 Subject: [PATCH 013/102] [graphics] added BLUE_TUBE and RED_TUBE colormaps --- examples/00_graphics/graphic_examples.py | 10 ++++++--- .../graphics/styles/codac2_py_ColorMap.cpp | 7 ++++++ src/graphics/styles/codac2_ColorMap.cpp | 22 ++++++++++++++++++- src/graphics/styles/codac2_ColorMap.h | 2 ++ 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index cdaeba17..6439ef51 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -48,11 +48,15 @@ fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) -fig3.set_axes(axis(0,[-1,21]), axis(1,[-0.5,1.5])) +fig3.set_axes(axis(0,[-1,21]), axis(1,[-0.5,3.5])) fig3.set_window_properties([250,250],[500,500]) -cmap=ColorMap.HAXBY +cmap_haxby=ColorMap.HAXBY +cmap_blue_tube=ColorMap.BLUE_TUBE +cmap_red_tube=ColorMap.RED_TUBE for i in range (20): ratio=i/20 - fig3.draw_box([[i,i+1],[0,1]],[cmap.color(ratio),cmap.color(ratio)]) \ No newline at end of file + fig3.draw_box([[i,i+1],[0,1]],[Color.black(),cmap_haxby.color(ratio)]) + fig3.draw_box([[i,i+1],[1,2]],[Color.black(),cmap_blue_tube.color(ratio)]) + fig3.draw_box([[i,i+1],[2,3]],[Color.black(),cmap_red_tube.color(ratio)]) \ No newline at end of file diff --git a/python/src/graphics/styles/codac2_py_ColorMap.cpp b/python/src/graphics/styles/codac2_py_ColorMap.cpp index 2a955fdb..773b9564 100644 --- a/python/src/graphics/styles/codac2_py_ColorMap.cpp +++ b/python/src/graphics/styles/codac2_py_ColorMap.cpp @@ -41,5 +41,12 @@ void export_ColorMap(py::module& m) .def_readonly_static("HAXBY", &ColorMap::HAXBY, CONST_COLORMAP_COLORMAP_HAXBY) + .def_readonly_static("BLUE_TUBE", &ColorMap::BLUE_TUBE, + CONST_COLORMAP_COLORMAP_BLUE_TUBE) + + .def_readonly_static("RED_TUBE", &ColorMap::RED_TUBE, + CONST_COLORMAP_COLORMAP_RED_TUBE) + + ; } \ No newline at end of file diff --git a/src/graphics/styles/codac2_ColorMap.cpp b/src/graphics/styles/codac2_ColorMap.cpp index 46719ce0..42ea0410 100644 --- a/src/graphics/styles/codac2_ColorMap.cpp +++ b/src/graphics/styles/codac2_ColorMap.cpp @@ -74,4 +74,24 @@ ColorMap make_haxby() return map; } -const ColorMap ColorMap::HAXBY = make_haxby(); \ No newline at end of file +const ColorMap ColorMap::HAXBY = make_haxby(); + +ColorMap make_blue_tube() +{ + ColorMap map; + map.add_color_point(Color(76,110,127), 0.); + map.add_color_point(Color(136,197,228), 1.); + return map; +} + +const ColorMap ColorMap::BLUE_TUBE = make_blue_tube(); + +ColorMap make_red_tube() +{ + ColorMap map; + map.add_color_point(Color(169,55,0), 0.); + map.add_color_point(Color(241,140,54), 1.); + return map; +} + +const ColorMap ColorMap::RED_TUBE = make_red_tube(); \ No newline at end of file diff --git a/src/graphics/styles/codac2_ColorMap.h b/src/graphics/styles/codac2_ColorMap.h index e087f4c0..e11f2d0a 100644 --- a/src/graphics/styles/codac2_ColorMap.h +++ b/src/graphics/styles/codac2_ColorMap.h @@ -33,5 +33,7 @@ namespace codac2 Color color (float r) const; static const ColorMap HAXBY; + static const ColorMap BLUE_TUBE; + static const ColorMap RED_TUBE; }; } \ No newline at end of file From c233a680fc90eddf081a3da1bfbc7b3a4b43b01f Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sun, 20 Oct 2024 19:43:19 +0200 Subject: [PATCH 014/102] Attempt to enable all tests for armhf, like all other configurations --- packages/temporary/gennewcodacpi_armhf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/temporary/gennewcodacpi_armhf.sh b/packages/temporary/gennewcodacpi_armhf.sh index e81115b5..9001490a 100644 --- a/packages/temporary/gennewcodacpi_armhf.sh +++ b/packages/temporary/gennewcodacpi_armhf.sh @@ -61,7 +61,7 @@ sudo apt-get -y install libatlas3-base || true && \ 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 && \ -#python3 -m unittest discover codac.tests && \\ +python3 -m unittest discover codac.tests && \ \ if [ \"\$(lsb_release -cs)\" = \"buster\" ]; then \ echo \"TESTS DISABLED FOR BUSTER DUE TO CATCH2\" ; \ From 8433469faaea167de4e9bf7c3d6a032de4302260 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sat, 26 Oct 2024 19:08:21 +0200 Subject: [PATCH 015/102] Branches management --- .github/workflows/dockercentos.yml | 13 +++--- .github/workflows/dockermatrix.yml | 12 +++-- .github/workflows/macosmatrix.yml | 9 ++-- .github/workflows/tests.yml | 4 +- .github/workflows/unixmatrix.yml | 10 ++--- .github/workflows/vcmatrix.yml | 9 ++-- .../docker/build_pybinding_codac4matlab.sh | 44 +++++++++++++++++++ 7 files changed, 79 insertions(+), 22 deletions(-) create mode 100644 scripts/docker/build_pybinding_codac4matlab.sh diff --git a/.github/workflows/dockercentos.yml b/.github/workflows/dockercentos.yml index e1f1a799..770f2b30 100644 --- a/.github/workflows/dockercentos.yml +++ b/.github/workflows/dockercentos.yml @@ -2,8 +2,9 @@ on: push: branches: - - codac2 - - codac2_codac4matlab + - codac1 + - codac2 + - codac2_codac4matlab tags: '' # Restrict to blank tags pull_request: @@ -32,8 +33,10 @@ jobs: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes if: (matrix.cfg.arch!='x86_64')&&(matrix.cfg.arch!='i386') - run: | - chmod a+x scripts/docker/build_pybinding.sh - docker run ${{ matrix.cfg.docker_flags }} --rm -v `pwd`:/io ${{ matrix.cfg.img }} /io/scripts/docker/build_pybinding.sh + chmod a+x scripts/docker/*.sh + if [ ${{ github.ref_name }} = 'codac2_codac4matlab' ] || [ ${{ github.event.pull_request.base.ref }} = 'codac2_codac4matlab' ]; then docker run ${{ matrix.cfg.docker_flags }} --rm -v `pwd`:/io ${{ matrix.cfg.img }} /io/scripts/docker/build_pybinding_codac4matlab.sh + else docker run ${{ matrix.cfg.docker_flags }} --rm -v `pwd`:/io ${{ matrix.cfg.img }} /io/scripts/docker/build_pybinding.sh + fi ls wheelhouse - uses: xresloader/upload-to-github-release@v1 env: @@ -42,4 +45,4 @@ jobs: file: "wheelhouse/*.whl" overwrite: true tag_name: autotagname-${{ github.sha }} - if: (github.event_name!='pull_request')&&((github.ref_name=='codac2')||(github.ref_name=='codac2_codac4matlab')) + if: (github.event_name!='pull_request')&&((github.ref_name=='codac1')||(github.ref_name=='codac2')||(github.ref_name=='codac2_codac4matlab')) diff --git a/.github/workflows/dockermatrix.yml b/.github/workflows/dockermatrix.yml index fcb20b5d..8232472e 100644 --- a/.github/workflows/dockermatrix.yml +++ b/.github/workflows/dockermatrix.yml @@ -1,10 +1,16 @@ # This file checks that the lib runs on ARM on: push: - branches: 'codac2' + branches: + - codac1 + - codac2 + # The following is implied by above selection... + #branches-ignore: + #- codac2_codac4matlab tags: '' # Restrict to blank tags pull_request: - branches: 'codac2' + branches-ignore: + - codac2_codac4matlab jobs: dockermatrix: @@ -112,4 +118,4 @@ jobs: file: "*.zip;*.deb" overwrite: true tag_name: autotagname-${{ github.sha }} - if: (github.event_name != 'pull_request') + if: (github.event_name!='pull_request')&&((github.ref_name=='codac1')||(github.ref_name=='codac2')||(github.ref_name=='codac2_codac4matlab')) diff --git a/.github/workflows/macosmatrix.yml b/.github/workflows/macosmatrix.yml index 5cfe061a..f069f9d9 100644 --- a/.github/workflows/macosmatrix.yml +++ b/.github/workflows/macosmatrix.yml @@ -2,8 +2,9 @@ on: push: branches: - - codac2 - - codac2_codac4matlab + - codac1 + - codac2 + - codac2_codac4matlab tags: '' # Restrict to blank tags pull_request: @@ -78,7 +79,7 @@ jobs: file: "*.whl" overwrite: true tag_name: autotagname-${{ github.sha }} - if: (github.event_name!='pull_request')&&((github.ref_name=='codac2')||(github.ref_name=='codac2_codac4matlab')) + if: (github.event_name!='pull_request')&&((github.ref_name=='codac1')||(github.ref_name=='codac2')||(github.ref_name=='codac2_codac4matlab')) - run: | pip install --no-deps --no-index *.whl python -c "import sys; print(sys.version)" ; python examples/02_centered_form/main.py @@ -87,4 +88,4 @@ jobs: cd build && ctest -C Release -V --output-on-failure cd .. shell: bash - if: (matrix.cfg.cross!=true) && (github.ref_name!='codac2_codac4matlab') && (github.event_name!='pull_request') \ No newline at end of file + if: (matrix.cfg.cross!=true)&&(github.ref_name!='codac2_codac4matlab')&&(github.event.pull_request.base.ref!='codac2_codac4matlab') diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f9b03791..931ef953 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,9 +2,11 @@ on: push: branches-ignore: - - codac2_codac4matlab + - codac2_codac4matlab tags: '' # Restrict to blank tags pull_request: + branches-ignore: + - codac2_codac4matlab jobs: tests: diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index 5939ecb0..ed03a82d 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -6,9 +6,9 @@ on: pull_request: jobs: - # This job may be commented if a new release should not be created... deploy: runs-on: ubuntu-latest + if: (github.event_name!='pull_request')&&((github.ref_name=='codac1')||(github.ref_name=='codac2')||(github.ref_name=='codac2_codac4matlab')) steps: - uses: softprops/action-gh-release@v2 id: create_release @@ -17,10 +17,10 @@ jobs: with: draft: true tag_name: autotagname-${{ github.sha }} - if: (github.event_name != 'pull_request')&&(github.ref_name == 'codac2') unixmatrix: runs-on: ${{ matrix.cfg.os }} + if: (github.ref_name!='codac2_codac4matlab')&&(github.event.pull_request.base.ref!='codac2_codac4matlab') defaults: run: shell: ${{ matrix.cfg.shell }} @@ -181,7 +181,7 @@ jobs: ./${{ matrix.cfg.test_config }}my_project cd ../.. shell: bash - if: (matrix.cfg.cross!=true) && (github.ref_name!='codac2_codac4matlab') && (github.event_name!='pull_request') + if: (matrix.cfg.cross!=true) - run: | source ~/refreshenv.bashrc ; refreshenv ; export PATH=$BASHMINGWPATH:$PATH cd packages/choco @@ -222,7 +222,7 @@ jobs: file: "*.zip;*.nupkg;*.deb" overwrite: true tag_name: autotagname-${{ github.sha }} - if: (github.event_name != 'pull_request')&&(github.ref_name == 'codac2') + if: (github.event_name!='pull_request')&&((github.ref_name=='codac1')||(github.ref_name=='codac2')||(github.ref_name=='codac2_codac4matlab')) - run: | if [ ${{ runner.os }} = Windows ]; then source ~/refreshenv.bashrc ; refreshenv ; export PATH=$BASHMINGWPATH:$PATH ; fi rm -Rf codac @@ -233,4 +233,4 @@ jobs: ./${{ matrix.cfg.test_config }}my_project cd ../.. shell: bash - if: (matrix.cfg.cross!=true) && (github.ref_name!='codac2_codac4matlab') && (github.event_name!='pull_request') + if: (matrix.cfg.cross!=true) diff --git a/.github/workflows/vcmatrix.yml b/.github/workflows/vcmatrix.yml index 5a2a8040..ff2cf5ae 100644 --- a/.github/workflows/vcmatrix.yml +++ b/.github/workflows/vcmatrix.yml @@ -2,8 +2,9 @@ on: push: branches: - - codac2 - - codac2_codac4matlab + - codac1 + - codac2 + - codac2_codac4matlab tags: '' # Restrict to blank tags pull_request: @@ -79,7 +80,7 @@ jobs: file: "*.whl" overwrite: true tag_name: autotagname-${{ github.sha }} - if: (github.event_name!='pull_request')&&((github.ref_name=='codac2')||(github.ref_name=='codac2_codac4matlab')) + if: (github.event_name!='pull_request')&&((github.ref_name=='codac1')||(github.ref_name=='codac2')||(github.ref_name=='codac2_codac4matlab')) - run: | pip install --no-deps --no-index *.whl python -c "import sys; print(sys.version)" ; python examples/02_centered_form/main.py @@ -88,4 +89,4 @@ jobs: cd build && ctest -C Release -V --output-on-failure cd .. shell: bash - if: (github.ref_name!='codac2_codac4matlab') && (github.event_name!='pull_request') + if: (github.ref_name!='codac2_codac4matlab')&&(github.event.pull_request.base.ref!='codac2_codac4matlab') diff --git a/scripts/docker/build_pybinding_codac4matlab.sh b/scripts/docker/build_pybinding_codac4matlab.sh new file mode 100644 index 00000000..157d285b --- /dev/null +++ b/scripts/docker/build_pybinding_codac4matlab.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +set -e -x + +wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex_$(uname -m)_manylinux2014.zip --no-check-certificate -nv +unzip -q ibex_$(uname -m)_manylinux2014.zip +rm -Rf ibex_$(uname -m)_manylinux2014.zip +sudo cp -Rf ibex/* /usr/local/ + +git config --global --add safe.directory /io +cd /io +for PYBIN in /opt/python/cp3*/bin; do + + #if [ "${PYBIN}" = "/opt/python/cp310-cp310/bin" ]; then + # continue + #fi + + "${PYBIN}/python" -m pip install --upgrade pip + "${PYBIN}/python" -m pip install --upgrade wheel setuptools + mkdir -p build_dir && cd build_dir + cmake -E env CXXFLAGS="-fPIC" CFLAGS="-fPIC" cmake -DPYTHON_EXECUTABLE=${PYBIN}/python -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -DWITH_CAPD=OFF -DWITH_PYTHON=ON .. + make -j4 + + make pip_package + echo "copy wheel and clean build_dir" + for whl in *.whl; do + auditwheel repair "$whl" -w /io/wheelhouse/ + done + + "${PYBIN}/python" -m pip install codac4matlab --no-deps --no-index -f /io/wheelhouse + "${PYBIN}/python" -c "import sys; print(sys.version); import codac4matlab; print(codac4matlab.__version__); from codac4matlab import *; print(IntervalVector([[-0.1],[0],[0.2]]))" + #"${PYBIN}/python" ../examples/02_centered_form/main.py + #"${PYBIN}/python" -m pip install numpy --prefer-binary + #"${PYBIN}/python" -m unittest discover codac.tests + + #make test ARGS="-V --output-on-failure" + #echo "start of Testing/Temporary/LastTest.log" + #cat Testing/Temporary/LastTest.log + #echo "end of Testing/Temporary/LastTest.log" + + cd /io + rm -fr build_dir + +done From 22c2e74c738e7da016b57bc447723f4d1abb1be4 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sun, 20 Oct 2024 15:45:35 +0200 Subject: [PATCH 016/102] macOS Monterey EOL --- .github/workflows/macosmatrix.yml | 26 +++++++++++++------------- .github/workflows/unixmatrix.yml | 2 -- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/.github/workflows/macosmatrix.yml b/.github/workflows/macosmatrix.yml index f069f9d9..941ec5b3 100644 --- a/.github/workflows/macosmatrix.yml +++ b/.github/workflows/macosmatrix.yml @@ -24,19 +24,19 @@ jobs: - { 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-12, shell: bash, arch: arm64, runtime: monterey, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: '-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 10, cross: true, desc: 'macOS Monterey Python 3.10 arm64 (cross)' } - - { os: macos-12, shell: bash, arch: arm64, runtime: monterey, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: '-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 9, cross: true, desc: 'macOS Monterey Python 3.9 arm64 (cross)' } - - { os: macos-12, shell: bash, arch: arm64, runtime: monterey, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: '-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 8, cross: true, desc: 'macOS Monterey Python 3.8 arm64 (cross)' } - - { os: macos-12, shell: bash, arch: arm64, runtime: monterey, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: 'm-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 7, cross: true, desc: 'macOS Monterey Python 3.7 arm64 (cross)' } - - { os: macos-12, shell: bash, arch: arm64, runtime: monterey, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: 'm-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 6, cross: true, desc: 'macOS Monterey Python 3.6 arm64 (cross)' } - - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 13, desc: 'macOS Monterey Python 3.13 x86_64' } - - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 12, desc: 'macOS Monterey Python 3.12 x86_64' } - - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 11, desc: 'macOS Monterey Python 3.11 x86_64' } - - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 10, desc: 'macOS Monterey Python 3.10 x86_64' } - - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 9, desc: 'macOS Monterey Python 3.9 x86_64' } - - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 8, desc: 'macOS Monterey Python 3.8 x86_64' } - - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: 'm-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 7, desc: 'macOS Monterey Python 3.7 x86_64' } - - { os: macos-12, shell: bash, arch: x86_64, runtime: monterey, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: 'm-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 6, desc: 'macOS Monterey Python 3.6 x86_64' } # Was 10.14 because of error $MACOSX_DEPLOYMENT_TARGET mismatch: now "10.9" but "10.14" during configure. Now 10.16 due to C++20 problems... + - { os: macos-13, shell: bash, arch: arm64, runtime: ventura, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: '-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 10, cross: true, desc: 'macOS Ventura Python 3.10 arm64 (cross)' } + - { os: macos-13, shell: bash, arch: arm64, runtime: ventura, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: '-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 9, cross: true, desc: 'macOS Ventura Python 3.9 arm64 (cross)' } + - { os: macos-13, shell: bash, arch: arm64, runtime: ventura, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: '-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 8, cross: true, desc: 'macOS Ventura Python 3.8 arm64 (cross)' } + - { os: macos-13, shell: bash, arch: arm64, runtime: ventura, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: 'm-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 7, cross: true, desc: 'macOS Ventura Python 3.7 arm64 (cross)' } + - { os: macos-13, shell: bash, arch: arm64, runtime: ventura, cmake_flags: '-fPIC', trgt: '11.0', cpcfg: 'm-macosx_11_0_arm64', py_v_maj: 3, py_v_min: 6, cross: true, desc: 'macOS Ventura Python 3.6 arm64 (cross)' } + - { os: macos-13, shell: bash, arch: x86_64, runtime: ventura, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 13, desc: 'macOS Ventura Python 3.13 x86_64' } + - { os: macos-13, shell: bash, arch: x86_64, runtime: ventura, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 12, desc: 'macOS Ventura Python 3.12 x86_64' } + - { os: macos-13, shell: bash, arch: x86_64, runtime: ventura, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 11, desc: 'macOS Ventura Python 3.11 x86_64' } + - { os: macos-13, shell: bash, arch: x86_64, runtime: ventura, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 10, desc: 'macOS Ventura Python 3.10 x86_64' } + - { os: macos-13, shell: bash, arch: x86_64, runtime: ventura, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 9, desc: 'macOS Ventura Python 3.9 x86_64' } + - { os: macos-13, shell: bash, arch: x86_64, runtime: ventura, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: '-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 8, desc: 'macOS Ventura Python 3.8 x86_64' } + - { os: macos-13, shell: bash, arch: x86_64, runtime: ventura, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: 'm-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 7, desc: 'macOS Ventura Python 3.7 x86_64' } + - { os: macos-13, shell: bash, arch: x86_64, runtime: ventura, cmake_flags: '-fPIC', trgt: '10.16', cpcfg: 'm-macosx_10_16_x86_64', py_v_maj: 3, py_v_min: 6, desc: 'macOS Ventura Python 3.6 x86_64' } # Was 10.14 because of error $MACOSX_DEPLOYMENT_TARGET mismatch: now "10.9" but "10.14" during configure. Now 10.16 due to C++20 problems... name: ${{ matrix.cfg.desc }} steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index ed03a82d..801f6c85 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -56,8 +56,6 @@ jobs: - { 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', cmake_flags: '-fPIC', cross: true, desc: 'macOS Sonoma x86_64 (cross)' } - { os: macos-13, shell: bash, arch: arm64, bitness: 64, runtime: ventura, cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=arm64', cmake_flags: '-fPIC', cross: true, desc: 'macOS Ventura arm64 (cross)' } - { os: macos-13, shell: bash, arch: x86_64, bitness: 64, runtime: ventura, cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=x86_64', cmake_flags: '-fPIC', desc: 'macOS Ventura x86_64' } - - { os: macos-12, shell: bash, arch: arm64, bitness: 64, runtime: monterey, cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=arm64', cmake_flags: '-fPIC', cross: true, desc: 'macOS Monterey arm64 (cross)' } - - { os: macos-12, shell: bash, arch: x86_64, bitness: 64, runtime: monterey, cmake_params: '-D CMAKE_SYSTEM_NAME=Darwin -D CMAKE_OSX_ARCHITECTURES=x86_64', cmake_flags: '-fPIC', desc: 'macOS Monterey x86_64' } name: ${{ matrix.cfg.desc }} steps: - uses: actions/checkout@v4 From 6277f7a582b046a4b4c481534f3c8d51a0fc3de5 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sun, 27 Oct 2024 16:37:20 +0100 Subject: [PATCH 017/102] Temporary fix related to codac2::pi --- src/core/tools/codac2_math.h | 5 +++-- tests/core/domains/interval/codac2_tests_Interval_bwd.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/tools/codac2_math.h b/src/core/tools/codac2_math.h index cb895966..ba4cae14 100644 --- a/src/core/tools/codac2_math.h +++ b/src/core/tools/codac2_math.h @@ -9,8 +9,9 @@ #pragma once +#include + namespace codac2 { - constexpr double pi = 3.141592653589793238462643383279; - // To be replaced by C++20 implementation providing portable pi value. + constexpr double pi = std::numbers::pi; // Need C++20 } \ No newline at end of file diff --git a/tests/core/domains/interval/codac2_tests_Interval_bwd.cpp b/tests/core/domains/interval/codac2_tests_Interval_bwd.cpp index 92453556..c814dd7b 100644 --- a/tests/core/domains/interval/codac2_tests_Interval_bwd.cpp +++ b/tests/core/domains/interval/codac2_tests_Interval_bwd.cpp @@ -16,12 +16,13 @@ #include #include #include +#include #include using namespace std; using namespace codac2; -#define PI 3.1415926535897932384626433832795028L // todo: use std::numbers::pi with C++20 +#define PI codac2::pi const double MAX_DOUBLE = std::numeric_limits::max(); From f6cbfd1924f36a913c64b5a93652475854e4233f Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 28 Oct 2024 13:35:00 +0100 Subject: [PATCH 018/102] [graphics] early drawAUV for IPE --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 23 ++++++++++++++++++++ src/graphics/3rd/ipe/codac2_Figure2D_IPE.h | 1 + 2 files changed, 24 insertions(+) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index f75191c7..b035b09c 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -8,6 +8,7 @@ */ #include +#include #include "codac2_Figure2D_IPE.h" using namespace std; @@ -89,6 +90,22 @@ void Figure2D_IPE::begin_path(const StyleProperties& s) pen=\"normal\"> \n "; } +void Figure2D_IPE::begin_path_with_matrix(const StyleProperties& s) +{ + // substr is needed to remove the "#" at the beginning of hex_str (deprecated by IPE) + _colors.emplace(s.stroke_color.hex_str.substr(1), s.stroke_color); + _colors.emplace(s.fill_color.hex_str.substr(1), s.fill_color); + + _f_temp_content << "\n \ + "; + + } double Figure2D_IPE::scale_x(double x) const diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h index a882a3d9..0ca420c8 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h @@ -29,6 +29,7 @@ namespace codac2 void update_window_properties(); void center_viewbox(const Vector& c, const Vector& r); void begin_path(const StyleProperties& s); + void begin_path_with_matrix(const StyleProperties& s); // Geometric shapes void draw_point(const Vector& c, const StyleProperties& s = StyleProperties()); From 55a85fc7053a52c279c0d74e4cb935509c9cccdc Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 28 Oct 2024 15:02:32 +0100 Subject: [PATCH 019/102] [graphics] draw_AUV for IPE --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 48 +++++++++++++++++--- src/graphics/3rd/ipe/codac2_Figure2D_IPE.h | 2 +- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index b035b09c..5727b476 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -8,8 +8,8 @@ */ #include -#include #include "codac2_Figure2D_IPE.h" +#include "codac2_math.h" using namespace std; using namespace codac2; @@ -90,7 +90,7 @@ void Figure2D_IPE::begin_path(const StyleProperties& s) pen=\"normal\"> \n "; } -void Figure2D_IPE::begin_path_with_matrix(const StyleProperties& s) +void Figure2D_IPE::begin_path_with_matrix(const Vector& x, float length, const StyleProperties& s) { // substr is needed to remove the "#" at the beginning of hex_str (deprecated by IPE) _colors.emplace(s.stroke_color.hex_str.substr(1), s.stroke_color); @@ -104,6 +104,11 @@ void Figure2D_IPE::begin_path_with_matrix(const StyleProperties& s) stroke-opacity=\"" << (int)(10*round(10.*s.stroke_color.alpha)) << "%\" \n \ pen=\"normal\" \n \ matrix="; + + // Matrix is composed of the 4 components of the 2D transformation matrix and the translation vector + _f_temp_content << "\"" << scale_length(length) * cos(x[j()+1]).mid() << " " << scale_length(length) * sin(x[j()+1]).mid() << " " + << - scale_length(length) * sin(x[j()+1]).mid() << " " << scale_length(length) * cos(x[j()+1]).mid() << " " + << scale_x(x[i()]) << " " << scale_y(x[j()]) << "\">\n"; } void Figure2D_IPE::draw_point(const Vector& c, const StyleProperties& s) @@ -206,11 +211,42 @@ void Figure2D_IPE::draw_AUV(const Vector& x, float size, const StyleProperties& assert(_fig.size() <= x.size()+1); assert(j()+1 < x.size()); assert(size >= 0.); - // Not implemented yet - begin_path_with_matrix(s); //cos sin -sin cos - _f_temp_content<<"\""<"; + float length=size/7.0; + + _f_temp_content<<"\n"; + + // Body + + begin_path_with_matrix(x,length,s); + + _f_temp_content << -4 << " " << 0 << " m \n"; + _f_temp_content << -2 << " " << 1 << " l \n"; + _f_temp_content << 2 << " " << 1 << " l \n"; + + for (float i = 90.; i > -90.; i -= 10.) + _f_temp_content << cos(i * codac2::pi / 180.).mid() + 2.0 << " " + << sin(i * codac2::pi / 180.).mid() + 0.0 << " l \n"; + + _f_temp_content << 2 << " " << -1 << " l \n"; + _f_temp_content << -2 << " " << -1 << " l \n"; + _f_temp_content << -4 << " " << 0 << " l \n"; + + _f_temp_content << "\n"; + + // Propulsion unit + + begin_path_with_matrix(x,length,s); + + _f_temp_content << -4 << " " << 1 << " m \n"; + _f_temp_content << -3.25 << " " << 1 << " l \n"; + _f_temp_content << -3.25 << " " << -1 << " l \n"; + _f_temp_content << -4 << " " << -1 << " l \n"; + _f_temp_content << -4 << " " << 1 << " l \n"; + + _f_temp_content << "\n"; + + _f_temp_content<<""; } diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h index 0ca420c8..e4966ffd 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h @@ -29,7 +29,7 @@ namespace codac2 void update_window_properties(); void center_viewbox(const Vector& c, const Vector& r); void begin_path(const StyleProperties& s); - void begin_path_with_matrix(const StyleProperties& s); + void begin_path_with_matrix(const Vector& x, float length, const StyleProperties& s); // Geometric shapes void draw_point(const Vector& c, const StyleProperties& s = StyleProperties()); From 87bc83dd2dd2e9bd8b35fda14851b48f578c3625 Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 28 Oct 2024 15:20:12 +0100 Subject: [PATCH 020/102] [graphics] draw_tank for IPE --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 32 ++++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 5727b476..df81d80c 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -203,7 +203,33 @@ void Figure2D_IPE::draw_tank(const Vector& x, float size, const StyleProperties& assert(_fig.size() <= x.size()+1); assert(j()+1 < x.size()); assert(size >= 0.); - // Not implemented yet + + float length=size/4.0; // from VIBes : initial vehicle's length is 4 + + _f_temp_content<<"\n\n"; + + begin_path_with_matrix(x,length,s); + + // Body + _f_temp_content << 1 << " " << -1.5 << " m \n"; + _f_temp_content << -1 << " " << -1.5 << " l \n"; + _f_temp_content << 0 << " " << -1.5 << " l \n"; + _f_temp_content << 0 << " " << -1 << " l \n"; + _f_temp_content << -1 << " " << -1 << " l \n"; + _f_temp_content << -1 << " " << 1 << " l \n"; + _f_temp_content << 0 << " " << 1 << " l \n"; + _f_temp_content << 0 << " " << 1.5 << " l \n"; + _f_temp_content << -1 << " " << 1.5 << " l \n"; + _f_temp_content << 1 << " " << 1.5 << " l \n"; + _f_temp_content << 0 << " " << 1.5 << " l \n"; + _f_temp_content << 0 << " " << 1 << " l \n"; + _f_temp_content << 3 << " " << 0.5 << " l \n"; + _f_temp_content << 3 << " " << -0.5 << " l \n"; + _f_temp_content << 0 << " " << -1 << " l \n"; + _f_temp_content << 0 << " " << -1.5 << " l \n"; + + _f_temp_content << "\n"; + _f_temp_content<<""; } void Figure2D_IPE::draw_AUV(const Vector& x, float size, const StyleProperties& s) @@ -212,9 +238,9 @@ void Figure2D_IPE::draw_AUV(const Vector& x, float size, const StyleProperties& assert(j()+1 < x.size()); assert(size >= 0.); - float length=size/7.0; + float length=size/7.0; // from VIBes : initial vehicle's length is 7 - _f_temp_content<<"\n"; + _f_temp_content<<"\n\n"; // Body From 66a1ae16b76ffcf594af79669505d4bcbfa278c3 Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 28 Oct 2024 15:58:15 +0100 Subject: [PATCH 021/102] [graphics] tip in polyline for IPE --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 16 ++++++++-------- src/graphics/3rd/ipe/codac2_Figure2D_IPE.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index df81d80c..fe1dc1b8 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -75,7 +75,7 @@ void Figure2D_IPE::center_viewbox(const Vector& c, const Vector& r) assert(r.min_coeff() > 0.); } -void Figure2D_IPE::begin_path(const StyleProperties& s) +void Figure2D_IPE::begin_path(const StyleProperties& s, bool tip=false) { // substr is needed to remove the "#" at the beginning of hex_str (deprecated by IPE) _colors.emplace(s.stroke_color.hex_str.substr(1), s.stroke_color); @@ -87,7 +87,11 @@ void Figure2D_IPE::begin_path(const StyleProperties& s) fill=\"codac_color_" << s.fill_color.hex_str.substr(1) << "\" \n \ opacity=\"" << (int)(10*round(10.*s.fill_color.alpha)) << "%\" \n \ stroke-opacity=\"" << (int)(10*round(10.*s.stroke_color.alpha)) << "%\" \n \ - pen=\"normal\"> \n "; + pen=\"normal\" \n \ + "; + if (tip) + _f_temp_content << "arrow=\"normal/normal\" \n "; + _f_temp_content << "> \n"; } void Figure2D_IPE::begin_path_with_matrix(const Vector& x, float length, const StyleProperties& s) @@ -166,9 +170,8 @@ void Figure2D_IPE::draw_polyline(const std::vector& x, float tip_length, { assert(x.size() > 1); assert(tip_length >= 0.); - // todo: draw tip - begin_path(s); + begin_path(s, tip_length>2e-3*_fig.scaled_unit()); for(size_t k = 0 ; k < x.size() ; k++) { @@ -206,8 +209,6 @@ void Figure2D_IPE::draw_tank(const Vector& x, float size, const StyleProperties& float length=size/4.0; // from VIBes : initial vehicle's length is 4 - _f_temp_content<<"\n\n"; - begin_path_with_matrix(x,length,s); // Body @@ -228,8 +229,7 @@ void Figure2D_IPE::draw_tank(const Vector& x, float size, const StyleProperties& _f_temp_content << 0 << " " << -1 << " l \n"; _f_temp_content << 0 << " " << -1.5 << " l \n"; - _f_temp_content << "\n"; - _f_temp_content<<""; + _f_temp_content << ""; } void Figure2D_IPE::draw_AUV(const Vector& x, float size, const StyleProperties& s) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h index e4966ffd..f121efdc 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h @@ -28,7 +28,7 @@ namespace codac2 void update_axes(); void update_window_properties(); void center_viewbox(const Vector& c, const Vector& r); - void begin_path(const StyleProperties& s); + void begin_path(const StyleProperties& s,bool tip); void begin_path_with_matrix(const Vector& x, float length, const StyleProperties& s); // Geometric shapes From f34963fe8b86dc97584ae8a7660570b34988eb67 Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 28 Oct 2024 16:22:22 +0100 Subject: [PATCH 022/102] [graphics] minor changes for xml format --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index fe1dc1b8..f4a497d2 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -87,10 +87,10 @@ void Figure2D_IPE::begin_path(const StyleProperties& s, bool tip=false) fill=\"codac_color_" << s.fill_color.hex_str.substr(1) << "\" \n \ opacity=\"" << (int)(10*round(10.*s.fill_color.alpha)) << "%\" \n \ stroke-opacity=\"" << (int)(10*round(10.*s.stroke_color.alpha)) << "%\" \n \ - pen=\"normal\" \n \ - "; + pen=\"normal\""; if (tip) - _f_temp_content << "arrow=\"normal/normal\" \n "; + _f_temp_content << "\n \ + arrow=\"normal/normal\""; _f_temp_content << "> \n"; } @@ -129,7 +129,7 @@ void Figure2D_IPE::draw_point(const Vector& c, const StyleProperties& s) fill=\"codac_color_" << s.fill_color.hex_str.substr(1) << "\" \n \ opacity=\"" << (int)(10*round(10.*s.fill_color.alpha)) << "%\" \n \ stroke-opacity=\"" << (int)(10*round(10.*s.stroke_color.alpha)) << "%\" \n \ - size=\"normal\"/>"; + size=\"normal\"\n/>"; } void Figure2D_IPE::draw_box(const IntervalVector& x, const StyleProperties& s) From 03dead1a176235b554a0c5f9677f55935ddc7566 Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 4 Nov 2024 01:06:43 +0100 Subject: [PATCH 023/102] [graphics] draw_ellipse for IPE --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index f4a497d2..5b9e7c0f 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -198,7 +198,12 @@ void Figure2D_IPE::draw_ellipse(const Vector& c, const Vector& ab, double theta, { assert(c.size() == 2); assert(ab.size() == 2); - // Not implemented yet + + begin_path(s); + _f_temp_content << scale_length(ab[0]) * cos(theta).mid() << " " << scale_length(ab[0]) * sin(theta).mid() << " " + << - scale_length(ab[1]) * sin(theta).mid() << " " << scale_length(ab[1]) * cos(theta).mid() << " " + << scale_x(c[i()]) << " " << scale_y(c[j()]) << " e \n"; + _f_temp_content << ""; } void Figure2D_IPE::draw_tank(const Vector& x, float size, const StyleProperties& s) From a4d1b463975ec955db46909d4d826d14526cecba Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 4 Nov 2024 11:13:54 +0100 Subject: [PATCH 024/102] [graphics] draw_pie for IPE --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 5b9e7c0f..b41903f6 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -191,7 +191,20 @@ void Figure2D_IPE::draw_pie(const Vector& c, const Interval& r, const Interval& { assert(_fig.size() <= c.size()); assert(r.lb() >= 0.); - // Not implemented yet + + begin_path(s); + + _f_temp_content << scale_x(c[0] + r.lb() * cos(theta.lb()).mid()) << " " << scale_y(c[1] + r.lb() * sin(theta.lb()).mid()) << " m \n"; + _f_temp_content << scale_x(c[0] + r.ub() * cos(theta.lb()).mid()) << " " << scale_y(c[1] + r.ub() * sin(theta.lb()).mid()) << " l \n"; + _f_temp_content << scale_length(r.ub()) << " 0 0 " << scale_length(r.ub()) << " " + << scale_x(c[i()]) << " " << scale_y(c[j()]) << " " + << scale_x(c[0] + r.ub() * cos(theta.ub()).mid()) << " " << scale_y(c[1] + r.ub() * sin(theta.ub()).mid()) << " a \n"; + _f_temp_content << scale_x(c[0] + r.lb() * cos(theta.ub()).mid()) << " " << scale_y(c[1] + r.lb() * sin(theta.ub()).mid()) << " l \n"; + _f_temp_content << scale_length(r.lb()) << " 0 0 " << - scale_length(r.lb()) << " " + << scale_x(c[i()]) << " " << scale_y(c[j()]) << " " + << scale_x(c[0] + r.lb() * cos(theta.lb()).mid()) << " " << scale_y(c[1] + r.lb() * sin(theta.lb()).mid()) << " a \n"; + + _f_temp_content << ""; } void Figure2D_IPE::draw_ellipse(const Vector& c, const Vector& ab, double theta, const StyleProperties& s) From 77277c7f6669716186211f017d717d625cda7f94 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 5 Nov 2024 00:53:44 +0100 Subject: [PATCH 025/102] [graphics] minor changes --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index b41903f6..e51615ff 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -87,7 +87,7 @@ void Figure2D_IPE::begin_path(const StyleProperties& s, bool tip=false) fill=\"codac_color_" << s.fill_color.hex_str.substr(1) << "\" \n \ opacity=\"" << (int)(10*round(10.*s.fill_color.alpha)) << "%\" \n \ stroke-opacity=\"" << (int)(10*round(10.*s.stroke_color.alpha)) << "%\" \n \ - pen=\"normal\""; + pen=\"heavier\""; if (tip) _f_temp_content << "\n \ arrow=\"normal/normal\""; @@ -106,7 +106,7 @@ void Figure2D_IPE::begin_path_with_matrix(const Vector& x, float length, const S fill=\"codac_color_" << s.fill_color.hex_str.substr(1) << "\" \n \ opacity=\"" << (int)(10*round(10.*s.fill_color.alpha)) << "%\" \n \ stroke-opacity=\"" << (int)(10*round(10.*s.stroke_color.alpha)) << "%\" \n \ - pen=\"normal\" \n \ + pen=\"heavier\" \n \ matrix="; // Matrix is composed of the 4 components of the 2D transformation matrix and the translation vector From e83bcb27091b15c6e2ecbd1f027ab7d9ff7e5989 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 5 Nov 2024 11:04:23 +0100 Subject: [PATCH 026/102] [graphics] vehicule shapes in constexpr --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 40 ++++---------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index e51615ff..25649e9e 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -229,23 +229,9 @@ void Figure2D_IPE::draw_tank(const Vector& x, float size, const StyleProperties& begin_path_with_matrix(x,length,s); - // Body - _f_temp_content << 1 << " " << -1.5 << " m \n"; - _f_temp_content << -1 << " " << -1.5 << " l \n"; - _f_temp_content << 0 << " " << -1.5 << " l \n"; - _f_temp_content << 0 << " " << -1 << " l \n"; - _f_temp_content << -1 << " " << -1 << " l \n"; - _f_temp_content << -1 << " " << 1 << " l \n"; - _f_temp_content << 0 << " " << 1 << " l \n"; - _f_temp_content << 0 << " " << 1.5 << " l \n"; - _f_temp_content << -1 << " " << 1.5 << " l \n"; - _f_temp_content << 1 << " " << 1.5 << " l \n"; - _f_temp_content << 0 << " " << 1.5 << " l \n"; - _f_temp_content << 0 << " " << 1 << " l \n"; - _f_temp_content << 3 << " " << 0.5 << " l \n"; - _f_temp_content << 3 << " " << -0.5 << " l \n"; - _f_temp_content << 0 << " " << -1 << " l \n"; - _f_temp_content << 0 << " " << -1.5 << " l \n"; + constexpr char tank_shape[] = " 1 -1.5 m \n -1 -1.5 l \n 0 -1.5 l \n 0 -1 l \n -1 -1 l \n -1 1 l \n 0 1 l \n 0 1.5 l \n -1 1.5 l \n 1 1.5 l \n 0 1.5 l \n 0 1 l \n 3 0.5 l \n 3 -0.5 l \n 0 -1 l \n 0 -1.5 l \n"; + + _f_temp_content << tank_shape; _f_temp_content << ""; } @@ -264,29 +250,19 @@ void Figure2D_IPE::draw_AUV(const Vector& x, float size, const StyleProperties& begin_path_with_matrix(x,length,s); - _f_temp_content << -4 << " " << 0 << " m \n"; - _f_temp_content << -2 << " " << 1 << " l \n"; - _f_temp_content << 2 << " " << 1 << " l \n"; + constexpr char body_shape[] = " -4 0 m \n -2 1 l \n 2 1 l \n 2.17365 0.984808 l \n 2.34202 0.939693 l \n 2.5 0.866025 l \n 2.64279 0.766044 l \n 2.76604 0.642788 l \n 2.86603 0.5 l \n 2.93969 0.34202 l \n 2.98481 0.173648 l \n 3 0 l \n 2.98481 -0.173648 l \n 2.93969 -0.34202 l \n 2.86603 -0.5 l \n 2.76604 -0.642788 l \n 2.64279 -0.766044 l \n 2.5 -0.866025 l \n 2.34202 -0.939693 l \n 2.17365 -0.984808 l \n 2 -1 l \n -2 -1 l \n -4 0 l \n"; - for (float i = 90.; i > -90.; i -= 10.) - _f_temp_content << cos(i * codac2::pi / 180.).mid() + 2.0 << " " - << sin(i * codac2::pi / 180.).mid() + 0.0 << " l \n"; - - _f_temp_content << 2 << " " << -1 << " l \n"; - _f_temp_content << -2 << " " << -1 << " l \n"; - _f_temp_content << -4 << " " << 0 << " l \n"; + _f_temp_content << body_shape; _f_temp_content << "\n"; // Propulsion unit + constexpr char propeller_shape[] = " -4 1 m \n -3.25 1 l \n -3.25 -1 l \n -4 -1 l \n -4 1 l \n"; + begin_path_with_matrix(x,length,s); - _f_temp_content << -4 << " " << 1 << " m \n"; - _f_temp_content << -3.25 << " " << 1 << " l \n"; - _f_temp_content << -3.25 << " " << -1 << " l \n"; - _f_temp_content << -4 << " " << -1 << " l \n"; - _f_temp_content << -4 << " " << 1 << " l \n"; + _f_temp_content << propeller_shape; _f_temp_content << "\n"; From 275288c3bda161cddd1d1534126f70f24e99f219 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 5 Nov 2024 11:31:35 +0100 Subject: [PATCH 027/102] [graphics] minor change to draw_pie for IPE --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 25649e9e..31bbe1f6 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -194,15 +194,20 @@ void Figure2D_IPE::draw_pie(const Vector& c, const Interval& r, const Interval& begin_path(s); - _f_temp_content << scale_x(c[0] + r.lb() * cos(theta.lb()).mid()) << " " << scale_y(c[1] + r.lb() * sin(theta.lb()).mid()) << " m \n"; - _f_temp_content << scale_x(c[0] + r.ub() * cos(theta.lb()).mid()) << " " << scale_y(c[1] + r.ub() * sin(theta.lb()).mid()) << " l \n"; + Vector point1 ({r.lb() * cos(theta.lb()).mid(), r.lb() * sin(theta.lb()).mid()}); + Vector point2 ({r.ub() * cos(theta.lb()).mid(), r.ub() * sin(theta.lb()).mid()}); + Vector point3 ({r.ub() * cos(theta.ub()).mid(), r.ub() * sin(theta.ub()).mid()}); + Vector point4 ({r.lb() * cos(theta.ub()).mid(), r.lb() * sin(theta.ub()).mid()}); + + _f_temp_content << scale_x(c[0] + point1[0]) << " " << scale_y(c[1] + point1[1]) << " m \n"; + _f_temp_content << scale_x(c[0] + point2[0]) << " " << scale_y(c[1] + point2[1]) << " l \n"; _f_temp_content << scale_length(r.ub()) << " 0 0 " << scale_length(r.ub()) << " " << scale_x(c[i()]) << " " << scale_y(c[j()]) << " " - << scale_x(c[0] + r.ub() * cos(theta.ub()).mid()) << " " << scale_y(c[1] + r.ub() * sin(theta.ub()).mid()) << " a \n"; - _f_temp_content << scale_x(c[0] + r.lb() * cos(theta.ub()).mid()) << " " << scale_y(c[1] + r.lb() * sin(theta.ub()).mid()) << " l \n"; + << scale_x(c[0] + point3[0]) << " " << scale_y(c[1] + point3[1]) << " a \n"; + _f_temp_content << scale_x(c[0] + point4[0]) << " " << scale_y(c[1] + point4[1]) << " l \n"; _f_temp_content << scale_length(r.lb()) << " 0 0 " << - scale_length(r.lb()) << " " << scale_x(c[i()]) << " " << scale_y(c[j()]) << " " - << scale_x(c[0] + r.lb() * cos(theta.lb()).mid()) << " " << scale_y(c[1] + r.lb() * sin(theta.lb()).mid()) << " a \n"; + << scale_x(c[0] + point1[0]) << " " << scale_y(c[1] + point1[1]) << " a \n"; _f_temp_content << ""; } From b3785103e0cfc0fc8c8ae34a1a108b5c5a864091 Mon Sep 17 00:00:00 2001 From: damien-masse Date: Tue, 5 Nov 2024 14:08:52 +0100 Subject: [PATCH 028/102] add mag and mid for interval and intervalMatrix, and python bindings --- .../domains/interval/codac2_py_Interval.cpp | 8 ++++++- .../interval/codac2_py_IntervalMatrixBase.h | 8 ++++++- src/core/domains/codac2_Domain.h | 4 +++- src/core/domains/interval/codac2_Interval.cpp | 12 ++++++++++- src/core/domains/interval/codac2_Interval.h | 21 ++++++++++++++++++- .../interval/codac2_IntervalMatrixBase.h | 12 ++++++++++- 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/python/src/core/domains/interval/codac2_py_Interval.cpp b/python/src/core/domains/interval/codac2_py_Interval.cpp index d64f0364..41d7dbe6 100644 --- a/python/src/core/domains/interval/codac2_py_Interval.cpp +++ b/python/src/core/domains/interval/codac2_py_Interval.cpp @@ -77,6 +77,12 @@ py::class_ export_Interval(py::module& m) .def("mid", &Interval::mid, DOUBLE_INTERVAL_MID_CONST) + .def("mag", &Interval::mag, + DOUBLE_INTERVAL_MAG_CONST) + + .def("mig", &Interval::mig, + DOUBLE_INTERVAL_MIG_CONST) + .def("rand", &Interval::rand, DOUBLE_INTERVAL_RAND_CONST) @@ -266,4 +272,4 @@ py::class_ export_Interval(py::module& m) "x"_a); return exported_interval_class; -} \ No newline at end of file +} diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h index e7890645..8200f313 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h @@ -46,6 +46,12 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) .def("mid", &S::mid, V_INTERVALMATRIXBASE_SV_MID_CONST) + .def("mig", &S::mig, + V_INTERVALMATRIXBASE_SV_MIG_CONST) + + .def("mag", &S::mag, + V_INTERVALMATRIXBASE_SV_MAG_CONST) + .def("rand", &S::rand, V_INTERVALMATRIXBASE_SV_RAND_CONST) @@ -166,4 +172,4 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) ; py::implicitly_convertible(); -} \ No newline at end of file +} diff --git a/src/core/domains/codac2_Domain.h b/src/core/domains/codac2_Domain.h index b9192964..65ec2d38 100644 --- a/src/core/domains/codac2_Domain.h +++ b/src/core/domains/codac2_Domain.h @@ -36,6 +36,8 @@ namespace codac2 virtual V lb() const = 0; virtual V ub() const = 0; virtual V mid() const = 0; + virtual V mag() const = 0; + virtual V mig() const = 0; virtual V rad() const = 0; virtual V diam() const = 0; virtual double volume() const = 0; @@ -56,4 +58,4 @@ namespace codac2 virtual bool is_strict_superset(const T& x) const = 0; }; -} \ No newline at end of file +} diff --git a/src/core/domains/interval/codac2_Interval.cpp b/src/core/domains/interval/codac2_Interval.cpp index 1edde677..1d24e693 100644 --- a/src/core/domains/interval/codac2_Interval.cpp +++ b/src/core/domains/interval/codac2_Interval.cpp @@ -98,6 +98,16 @@ namespace codac2 return ibex::Interval::mid(); } + double Interval::mag() const + { + return ibex::Interval::mag(); + } + + double Interval::mig() const + { + return ibex::Interval::mig(); + } + double Interval::rand() const { if(is_empty()) @@ -378,4 +388,4 @@ namespace codac2 return Interval(x); } -} // namespace codac \ No newline at end of file +} // namespace codac diff --git a/src/core/domains/interval/codac2_Interval.h b/src/core/domains/interval/codac2_Interval.h index e416f2d0..b439a32f 100644 --- a/src/core/domains/interval/codac2_Interval.h +++ b/src/core/domains/interval/codac2_Interval.h @@ -163,6 +163,25 @@ namespace codac2 */ double mid() const; + /** + * \brief Returns the magnitude of this + * i.e. max(|lower bound|, |upper bound|). + * + * \return the magnitude of the interval + */ + double mag() const; + + /** + * \brief Returns the mignitude of this + * + * +(lower bound) if lower_bound > 0 + * -(upper bound) if upper_bound < 0 + * 0 otherwise. + * + * \return the mignitude of the interval + */ + double mig() const; + /** * \brief Returns a random value inside the interval * @@ -659,4 +678,4 @@ namespace codac2 { return ibex::next_float(x); } -} \ No newline at end of file +} diff --git a/src/core/domains/interval/codac2_IntervalMatrixBase.h b/src/core/domains/interval/codac2_IntervalMatrixBase.h index 2d47d717..86795890 100644 --- a/src/core/domains/interval/codac2_IntervalMatrixBase.h +++ b/src/core/domains/interval/codac2_IntervalMatrixBase.h @@ -115,6 +115,16 @@ namespace codac2 degenerate_mat(mid); } + V mag() const + { + degenerate_mat(mag); + } + + V mig() const + { + degenerate_mat(mig); + } + V rand() const { srand(time(NULL)); @@ -504,4 +514,4 @@ namespace codac2 return bisect(max_diam_index(), ratio); } }; -} \ No newline at end of file +} From 527e4b0abc99a1062e4bf41aeb72cb7e4938c998 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 5 Nov 2024 14:57:38 +0100 Subject: [PATCH 029/102] [graphics] minor changes --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 31bbe1f6..9d5e0e2f 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -110,8 +110,8 @@ void Figure2D_IPE::begin_path_with_matrix(const Vector& x, float length, const S matrix="; // Matrix is composed of the 4 components of the 2D transformation matrix and the translation vector - _f_temp_content << "\"" << scale_length(length) * cos(x[j()+1]).mid() << " " << scale_length(length) * sin(x[j()+1]).mid() << " " - << - scale_length(length) * sin(x[j()+1]).mid() << " " << scale_length(length) * cos(x[j()+1]).mid() << " " + _f_temp_content << "\"" << scale_length(length) * std::cos(x[j()+1]) << " " << scale_length(length) * std::sin(x[j()+1]) << " " + << - scale_length(length) * std::sin(x[j()+1]) << " " << scale_length(length) * std::cos(x[j()+1]) << " " << scale_x(x[i()]) << " " << scale_y(x[j()]) << "\">\n"; } @@ -194,10 +194,10 @@ void Figure2D_IPE::draw_pie(const Vector& c, const Interval& r, const Interval& begin_path(s); - Vector point1 ({r.lb() * cos(theta.lb()).mid(), r.lb() * sin(theta.lb()).mid()}); - Vector point2 ({r.ub() * cos(theta.lb()).mid(), r.ub() * sin(theta.lb()).mid()}); - Vector point3 ({r.ub() * cos(theta.ub()).mid(), r.ub() * sin(theta.ub()).mid()}); - Vector point4 ({r.lb() * cos(theta.ub()).mid(), r.lb() * sin(theta.ub()).mid()}); + Vector point1 ({r.lb() * std::cos(theta.lb()), r.lb() * std::sin(theta.lb())}); + Vector point2 ({r.ub() * std::cos(theta.lb()), r.ub() * std::sin(theta.lb())}); + Vector point3 ({r.ub() * std::cos(theta.ub()), r.ub() * std::sin(theta.ub())}); + Vector point4 ({r.lb() * std::cos(theta.ub()), r.lb() * std::sin(theta.ub())}); _f_temp_content << scale_x(c[0] + point1[0]) << " " << scale_y(c[1] + point1[1]) << " m \n"; _f_temp_content << scale_x(c[0] + point2[0]) << " " << scale_y(c[1] + point2[1]) << " l \n"; @@ -218,8 +218,8 @@ void Figure2D_IPE::draw_ellipse(const Vector& c, const Vector& ab, double theta, assert(ab.size() == 2); begin_path(s); - _f_temp_content << scale_length(ab[0]) * cos(theta).mid() << " " << scale_length(ab[0]) * sin(theta).mid() << " " - << - scale_length(ab[1]) * sin(theta).mid() << " " << scale_length(ab[1]) * cos(theta).mid() << " " + _f_temp_content << scale_length(ab[0]) * std::cos(theta) << " " << scale_length(ab[0]) * std::sin(theta) << " " + << - scale_length(ab[1]) * std::sin(theta) << " " << scale_length(ab[1]) * std::cos(theta) << " " << scale_x(c[i()]) << " " << scale_y(c[j()]) << " e \n"; _f_temp_content << ""; } From 2d5a86e33e30d86e1b95de04de33f8c3e4c9d2af Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 5 Nov 2024 15:21:00 +0100 Subject: [PATCH 030/102] [mat] Vector types: Eigen col dimensions are now known at compile time --- .../interval/codac2_py_IntervalMatrixBase.h | 76 ++++++++-------- .../src/core/matrices/codac2_py_MatrixBase.h | 42 ++++----- src/core/CMakeLists.txt | 1 + .../interval/codac2_IntervalMatrixBase.h | 18 ++-- .../interval/codac2_IntervalVector.cpp | 26 +++--- .../domains/interval/codac2_IntervalVector.h | 10 +-- src/core/matrices/codac2_MatrixBase.h | 86 ++++++++++--------- src/core/matrices/codac2_MatrixBaseBlock.h | 8 +- src/core/matrices/codac2_MatrixBase_fwd.h | 16 ++++ src/core/matrices/codac2_Vector.cpp | 8 +- src/core/matrices/codac2_Vector.h | 4 +- src/core/matrices/codac2_VectorBase.h | 12 +-- 12 files changed, 165 insertions(+), 142 deletions(-) create mode 100644 src/core/matrices/codac2_MatrixBase_fwd.h diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h index e7890645..d0afc06a 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h @@ -29,111 +29,111 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) pyclass .def("volume", &S::volume, - DOUBLE_INTERVALMATRIXBASE_SV_VOLUME_CONST) + DOUBLE_INTERVALMATRIXBASE_SVROWSCOLS_VOLUME_CONST) .def("is_empty", &S::is_empty, - BOOL_INTERVALMATRIXBASE_SV_IS_EMPTY_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_EMPTY_CONST) .def("set_empty", &S::set_empty, - VOID_INTERVALMATRIXBASE_SV_SET_EMPTY) + VOID_INTERVALMATRIXBASE_SVROWSCOLS_SET_EMPTY) .def("lb", &S::lb, - V_INTERVALMATRIXBASE_SV_LB_CONST) + V_INTERVALMATRIXBASE_SVROWSCOLS_LB_CONST) .def("ub", &S::ub, - V_INTERVALMATRIXBASE_SV_UB_CONST) + V_INTERVALMATRIXBASE_SVROWSCOLS_UB_CONST) .def("mid", &S::mid, - V_INTERVALMATRIXBASE_SV_MID_CONST) + V_INTERVALMATRIXBASE_SVROWSCOLS_MID_CONST) .def("rand", &S::rand, - V_INTERVALMATRIXBASE_SV_RAND_CONST) + V_INTERVALMATRIXBASE_SVROWSCOLS_RAND_CONST) .def("rad", &S::rad, - V_INTERVALMATRIXBASE_SV_RAD_CONST) + V_INTERVALMATRIXBASE_SVROWSCOLS_RAD_CONST) .def("diam", &S::diam, - V_INTERVALMATRIXBASE_SV_DIAM_CONST) + V_INTERVALMATRIXBASE_SVROWSCOLS_DIAM_CONST) .def("min_diam", &S::min_diam, - DOUBLE_INTERVALMATRIXBASE_SV_MIN_DIAM_CONST) + DOUBLE_INTERVALMATRIXBASE_SVROWSCOLS_MIN_DIAM_CONST) .def("max_diam", &S::max_diam, - DOUBLE_INTERVALMATRIXBASE_SV_MAX_DIAM_CONST) + DOUBLE_INTERVALMATRIXBASE_SVROWSCOLS_MAX_DIAM_CONST) .def("min_diam_index", [](const S& x) { return matlab::output_index(x.min_diam_index()); }, - SIZET_INTERVALMATRIXBASE_SV_MIN_DIAM_INDEX_CONST) + SIZET_INTERVALMATRIXBASE_SVROWSCOLS_MIN_DIAM_INDEX_CONST) .def("max_diam_index", [](const S& x) { return matlab::output_index(x.max_diam_index()); }, - SIZET_INTERVALMATRIXBASE_SV_MAX_DIAM_INDEX_CONST) + SIZET_INTERVALMATRIXBASE_SVROWSCOLS_MAX_DIAM_INDEX_CONST) .def("extr_diam_index", [](const S& x, bool min) { return matlab::output_index(x.extr_diam_index(min)); }, - SIZET_INTERVALMATRIXBASE_SV_EXTR_DIAM_INDEX_BOOL_CONST, + SIZET_INTERVALMATRIXBASE_SVROWSCOLS_EXTR_DIAM_INDEX_BOOL_CONST, "min"_a) .def("__contains__", &S::contains, - BOOL_INTERVALMATRIXBASE_SV_CONTAINS_CONST_V_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_CONTAINS_CONST_V_REF_CONST) .def("contains", &S::contains, - BOOL_INTERVALMATRIXBASE_SV_CONTAINS_CONST_V_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_CONTAINS_CONST_V_REF_CONST) .def("interior_contains", &S::interior_contains, - BOOL_INTERVALMATRIXBASE_SV_INTERIOR_CONTAINS_CONST_V_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_INTERIOR_CONTAINS_CONST_V_REF_CONST) .def("is_unbounded", &S::is_unbounded, - BOOL_INTERVALMATRIXBASE_SV_IS_UNBOUNDED_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_UNBOUNDED_CONST) .def("is_degenerated", &S::is_degenerated, - BOOL_INTERVALMATRIXBASE_SV_IS_DEGENERATED_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_DEGENERATED_CONST) .def("is_flat", &S::is_flat, - BOOL_INTERVALMATRIXBASE_SV_IS_FLAT_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_FLAT_CONST) .def("intersects", &S::intersects, - BOOL_INTERVALMATRIXBASE_SV_INTERSECTS_CONST_S_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_INTERSECTS_CONST_S_REF_CONST) .def("is_disjoint", &S::is_disjoint, - BOOL_INTERVALMATRIXBASE_SV_IS_DISJOINT_CONST_S_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_DISJOINT_CONST_S_REF_CONST) .def("overlaps", &S::overlaps, - BOOL_INTERVALMATRIXBASE_SV_OVERLAPS_CONST_S_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_OVERLAPS_CONST_S_REF_CONST) .def("is_subset", &S::is_subset, - BOOL_INTERVALMATRIXBASE_SV_IS_SUBSET_CONST_S_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_SUBSET_CONST_S_REF_CONST) .def("is_strict_subset", &S::is_strict_subset, - BOOL_INTERVALMATRIXBASE_SV_IS_STRICT_SUBSET_CONST_S_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_STRICT_SUBSET_CONST_S_REF_CONST) .def("is_interior_subset", &S::is_interior_subset, - BOOL_INTERVALMATRIXBASE_SV_IS_INTERIOR_SUBSET_CONST_S_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_INTERIOR_SUBSET_CONST_S_REF_CONST) .def("is_strict_interior_subset", &S::is_strict_interior_subset, - BOOL_INTERVALMATRIXBASE_SV_IS_STRICT_INTERIOR_SUBSET_CONST_S_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_STRICT_INTERIOR_SUBSET_CONST_S_REF_CONST) .def("is_superset", &S::is_superset, - BOOL_INTERVALMATRIXBASE_SV_IS_SUPERSET_CONST_S_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_SUPERSET_CONST_S_REF_CONST) .def("is_strict_superset", &S::is_strict_superset, - BOOL_INTERVALMATRIXBASE_SV_IS_STRICT_SUPERSET_CONST_S_REF_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_STRICT_SUPERSET_CONST_S_REF_CONST) .def("is_bisectable", &S::is_bisectable, - BOOL_INTERVALMATRIXBASE_SV_IS_BISECTABLE_CONST) + BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_BISECTABLE_CONST) .def("inflate", (S&(S::*)(double))&S::inflate, - S_REF_INTERVALMATRIXBASE_SV_INFLATE_DOUBLE, + S_REF_INTERVALMATRIXBASE_SVROWSCOLS_INFLATE_DOUBLE, "r"_a) .def("inflate", (S&(S::*)(const V&))&S::inflate, - S_REF_INTERVALMATRIXBASE_SV_INFLATE_CONST_V_REF, + S_REF_INTERVALMATRIXBASE_SVROWSCOLS_INFLATE_CONST_V_REF, "r"_a) .def("bisect", [](const S& x, size_t_type i, double ratio) @@ -141,27 +141,27 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(i); return x.bisect(matlab::input_index(i),ratio); }, - PAIR_SS_INTERVALMATRIXBASE_SV_BISECT_SIZET_FLOAT_CONST, + PAIR_SS_INTERVALMATRIXBASE_SVROWSCOLS_BISECT_SIZET_FLOAT_CONST, "i"_a, "ratio"_a = 0.49) .def("bisect_largest", &S::bisect_largest, - PAIR_SS_INTERVALMATRIXBASE_SV_BISECT_LARGEST_FLOAT_CONST, + PAIR_SS_INTERVALMATRIXBASE_SVROWSCOLS_BISECT_LARGEST_FLOAT_CONST, "ratio"_a = 0.49) .def(py::self &= py::self, - S_REF_INTERVALMATRIXBASE_SV_OPERATORANDEQ_CONST_S_REF + S_REF_INTERVALMATRIXBASE_SVROWSCOLS_OPERATORANDEQ_CONST_S_REF "x"_a) .def(py::self |= py::self, - S_REF_INTERVALMATRIXBASE_SV_OPERATOROREQ_CONST_S_REF + S_REF_INTERVALMATRIXBASE_SVROWSCOLS_OPERATOROREQ_CONST_S_REF "x"_a) .def(py::self & py::self, - S_INTERVALMATRIXBASE_SV_OPERATORAND_CONST_S_REF_CONST + S_INTERVALMATRIXBASE_SVROWSCOLS_OPERATORAND_CONST_S_REF_CONST "x"_a) .def(py::self | py::self, - S_INTERVALMATRIXBASE_SV_OPERATOROR_CONST_S_REF_CONST, + S_INTERVALMATRIXBASE_SVROWSCOLS_OPERATOROR_CONST_S_REF_CONST, "x"_a) ; diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index eeacc5d4..d8d54358 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -33,37 +33,37 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { return x.size(); }, - SIZET_MATRIXBASE_ST_SIZE_CONST) + SIZET_MATRIXBASE_STROWSCOLS_SIZE_CONST) .def("size", [](const S& x) { return x.size(); }, - SIZET_MATRIXBASE_ST_SIZE_CONST) + SIZET_MATRIXBASE_STROWSCOLS_SIZE_CONST) .def("nb_rows", [](const S& x) { return x.nb_rows(); }, - SIZET_MATRIXBASE_ST_NB_ROWS_CONST) + SIZET_MATRIXBASE_STROWSCOLS_NB_ROWS_CONST) .def("nb_cols", [](const S& x) { return x.nb_cols(); }, - SIZET_MATRIXBASE_ST_NB_COLS_CONST) + SIZET_MATRIXBASE_STROWSCOLS_NB_COLS_CONST) .def("min_coeff", [](const S& x) { return x.min_coeff(); }, - T_MATRIXBASE_ST_MIN_COEFF_CONST) + T_MATRIXBASE_STROWSCOLS_MIN_COEFF_CONST) .def("max_coeff", [](const S& x) { return x.max_coeff(); }, - T_MATRIXBASE_ST_MAX_COEFF_CONST) + T_MATRIXBASE_STROWSCOLS_MAX_COEFF_CONST) ; @@ -75,7 +75,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { return x.is_squared(); }, - BOOL_MATRIXBASE_ST_IS_SQUARED_CONST) + BOOL_MATRIXBASE_STROWSCOLS_IS_SQUARED_CONST) .def("__getitem__", [](const S& x, const py::tuple& ij) -> const T& { @@ -87,7 +87,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) return x(matlab::input_index(i), matlab::input_index(j)); }, py::return_value_policy::reference_internal, - CONST_T_REF_MATRIXBASE_ST_OPERATORCALL_SIZET_SIZET_CONST) + CONST_T_REF_MATRIXBASE_STROWSCOLS_OPERATORCALL_SIZET_SIZET_CONST) .def("__setitem__", [](S& x, const py::tuple& ij, const T& a) { @@ -99,7 +99,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) x(matlab::input_index(i), matlab::input_index(j)) = a; }, - T_REF_MATRIXBASE_ST_OPERATORCALL_SIZET_SIZET) + T_REF_MATRIXBASE_STROWSCOLS_OPERATORCALL_SIZET_SIZET) ; } @@ -110,14 +110,14 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { x.init(a); }, - VOID_MATRIXBASE_ST_INIT_CONST_T_REF, + VOID_MATRIXBASE_STROWSCOLS_INIT_CONST_T_REF, "x"_a) .def("init", [](S& x, const S& a) { x.init(a); }, - VOID_MATRIXBASE_ST_INIT_CONST_S_REF, + VOID_MATRIXBASE_STROWSCOLS_INIT_CONST_S_REF, "x"_a) .def("__repr__", [](const S& x) @@ -126,7 +126,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) s << x; return string(s.str()); }, - OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_MATRIXBASE_ST_REF) + OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_MATRIXBASE_STROWSCOLS_REF) ; if constexpr(!VECTOR_INHERITANCE) @@ -143,7 +143,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) return x.block(matlab::input_index(i),matlab::input_index(j),matlab::input_index(p),matlab::input_index(q)); }, py::keep_alive<0,1>(), - MATRIXBASEBLOCK_EIGENMATRIX_T_REFT_MATRIXBASE_ST_BLOCK_SIZET_SIZET_SIZET_SIZET) + MATRIXBASEBLOCK_EIGENMATRIX_TROWSCOLS_REFT_MATRIXBASE_STROWSCOLS_BLOCK_SIZET_SIZET_SIZET_SIZET) .def("col", [](S& x, size_t_type i) -> MatrixBaseBlock&,T> { @@ -151,7 +151,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) return x.col(matlab::input_index(i)); }, py::keep_alive<0,1>(), - MATRIXBASEBLOCK_EIGENMATRIX_T_REFT_MATRIXBASE_ST_COL_SIZET) + MATRIXBASEBLOCK_EIGENMATRIX_TROWSCOLS_REFT_MATRIXBASE_STROWSCOLS_COL_SIZET) .def("row", [](S& x, size_t_type i) -> MatrixBaseBlock&,T> { @@ -159,21 +159,21 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) return x.row(matlab::input_index(i)); }, py::keep_alive<0,1>(), - MATRIXBASEBLOCK_EIGENMATRIX_T_REFT_MATRIXBASE_ST_ROW_SIZET) + MATRIXBASEBLOCK_EIGENMATRIX_TROWSCOLS_REFT_MATRIXBASE_STROWSCOLS_ROW_SIZET) .def("__call__", [](S& x, size_t_type i, size_t_type j) -> T& { matlab::test_integer(i,j); return x(matlab::input_index(i),matlab::input_index(j)); }, py::return_value_policy::reference_internal, - T_REF_MATRIXBASE_ST_OPERATORCALL_SIZET_SIZET) + T_REF_MATRIXBASE_STROWSCOLS_OPERATORCALL_SIZET_SIZET) .def("resize", [](S& x, size_t_type nb_rows, size_t_type nb_cols) { matlab::test_integer(nb_rows, nb_cols); x.resize(nb_rows, nb_cols); }, - VOID_MATRIXBASE_ST_RESIZE_SIZET_SIZET, + VOID_MATRIXBASE_STROWSCOLS_RESIZE_SIZET_SIZET, "nb_rows"_a, "nb_cols"_a) .def_static("zeros", [](size_t_type r, size_t_type c) @@ -181,7 +181,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::zeros(r,c); }, - STATIC_S_MATRIXBASE_ST_ZEROS_SIZET_SIZET, + STATIC_S_MATRIXBASE_STROWSCOLS_ZEROS_SIZET_SIZET, "r"_a, "c"_a) .def_static("ones", [](size_t_type r, size_t_type c) @@ -189,7 +189,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::ones(r,c); }, - STATIC_S_MATRIXBASE_ST_ONES_SIZET_SIZET, + STATIC_S_MATRIXBASE_STROWSCOLS_ONES_SIZET_SIZET, "r"_a, "c"_a) .def_static("eye", [](size_t_type r, size_t_type c) @@ -197,7 +197,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::ones(r,c); }, - STATIC_S_MATRIXBASE_ST_EYE_SIZET_SIZET, + STATIC_S_MATRIXBASE_STROWSCOLS_EYE_SIZET_SIZET, "r"_a, "c"_a) ; @@ -205,5 +205,5 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) //S abs(const MatrixBase& x) m.def("abs", [](const S& x) { return abs(x); }, - S_ABS_CONST_MATRIXBASE_ST_REF); + S_ABS_CONST_MATRIXBASE_STROWSCOLS_REF); } \ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index db305b75..a3258276 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -100,6 +100,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Matrix.cpp ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Matrix.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_MatrixBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_MatrixBase_fwd.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_MatrixBaseBlock.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Vector.cpp ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Vector.h diff --git a/src/core/domains/interval/codac2_IntervalMatrixBase.h b/src/core/domains/interval/codac2_IntervalMatrixBase.h index 2d47d717..7361c34a 100644 --- a/src/core/domains/interval/codac2_IntervalMatrixBase.h +++ b/src/core/domains/interval/codac2_IntervalMatrixBase.h @@ -23,21 +23,21 @@ namespace codac2 { class IntervalMatrix; - template - class IntervalMatrixBase : virtual public MatrixBase, public DomainInterface + template + class IntervalMatrixBase : virtual public MatrixBase, public DomainInterface { public: explicit IntervalMatrixBase(size_t r, size_t c) - : MatrixBase(r,c) + : MatrixBase(r,c) { } explicit IntervalMatrixBase(size_t r, size_t c, const Interval& x) - : MatrixBase(r,c,x) + : MatrixBase(r,c,x) { } explicit IntervalMatrixBase(size_t r, size_t c, const double bounds[][2]) - : MatrixBase(r,c) + : MatrixBase(r,c) { size_t k = 0; for(size_t i = 0 ; i < this->nb_rows() ; i++) @@ -50,12 +50,12 @@ namespace codac2 } IntervalMatrixBase(std::initializer_list> l) - : MatrixBase(l) + : MatrixBase(l) { } template IntervalMatrixBase(const Eigen::MatrixBase& x) - : MatrixBase(x) + : MatrixBase(x) { } double volume() const @@ -478,12 +478,12 @@ namespace codac2 return y |= x; } - friend bool operator==(const IntervalMatrixBase& x1, const IntervalMatrixBase& x2) + friend bool operator==(const IntervalMatrixBase& x1, const IntervalMatrixBase& x2) { if(x1.is_empty() || x2.is_empty()) return x1.is_empty() && x2.is_empty() && x1.size() == x2.size(); - return (MatrixBase)x1 == (MatrixBase)x2; + return (MatrixBase)x1 == (MatrixBase)x2; } std::pair bisect(size_t i, float ratio = 0.49) const diff --git a/src/core/domains/interval/codac2_IntervalVector.cpp b/src/core/domains/interval/codac2_IntervalVector.cpp index 8d1cef0b..589d20c8 100644 --- a/src/core/domains/interval/codac2_IntervalVector.cpp +++ b/src/core/domains/interval/codac2_IntervalVector.cpp @@ -21,30 +21,30 @@ namespace codac2 } IntervalVector::IntervalVector(size_t n, const Interval& x) - : MatrixBase(n,1,x), - IntervalMatrixBase(n,1), + : MatrixBase(n,1,x), + IntervalMatrixBase(n,1), VectorBase(n) { assert_release(n >= 0); } IntervalVector::IntervalVector(size_t n, const double bounds[][2]) - : MatrixBase(n,1), - IntervalMatrixBase(n,1,bounds), + : MatrixBase(n,1), + IntervalMatrixBase(n,1,bounds), VectorBase(n) { assert_release(n >= 0); } IntervalVector::IntervalVector(const Vector& x) - : MatrixBase(x._e.template cast()), - IntervalMatrixBase(x.size(),1), + : MatrixBase(x._e.template cast()), + IntervalMatrixBase(x.size(),1), VectorBase(x.size()) { } IntervalVector::IntervalVector(const Vector& lb, const Vector& ub) - : MatrixBase(lb._e.template cast()), - IntervalMatrixBase(lb.size(),1), + : MatrixBase(lb._e.template cast()), + IntervalMatrixBase(lb.size(),1), VectorBase(lb.size()) { assert_release(lb.size() == ub.size()); @@ -52,25 +52,25 @@ namespace codac2 } IntervalVector::IntervalVector(initializer_list l) - : MatrixBase(l.size(),1), - IntervalMatrixBase(l.size(),1), + : MatrixBase(l.size(),1), + IntervalMatrixBase(l.size(),1), VectorBase(l) { assert_release(!std::empty(l)); } - IntervalVector::IntervalVector(const MatrixBase& x) + IntervalVector::IntervalVector(const MatrixBase& x) : IntervalVector(x._e.template cast()) { } - IntervalVector::IntervalVector(const MatrixBase& x) + IntervalVector::IntervalVector(const MatrixBase& x) : IntervalVector(x._e) { } bool operator==(const IntervalVector& x1, const IntervalVector& x2) { // ^ This overload allows automatic cast for Vector == IntervalVector comparisons - return (IntervalMatrixBase)x1 == (IntervalMatrixBase)x2; + return (IntervalMatrixBase)x1 == (IntervalMatrixBase)x2; } list IntervalVector::complementary() const diff --git a/src/core/domains/interval/codac2_IntervalVector.h b/src/core/domains/interval/codac2_IntervalVector.h index ae336a74..376331ad 100644 --- a/src/core/domains/interval/codac2_IntervalVector.h +++ b/src/core/domains/interval/codac2_IntervalVector.h @@ -23,7 +23,7 @@ namespace codac2 { - class IntervalVector : public IntervalMatrixBase, public VectorBase + class IntervalVector : public IntervalMatrixBase, public VectorBase { public: @@ -39,14 +39,14 @@ namespace codac2 IntervalVector(std::initializer_list l); - IntervalVector(const MatrixBase& x); + IntervalVector(const MatrixBase& x); - IntervalVector(const MatrixBase& x); + IntervalVector(const MatrixBase& x); template IntervalVector(const Eigen::MatrixBase& x) - : MatrixBase(x.template cast()), - IntervalMatrixBase(x.template cast()), + : MatrixBase(x.template cast()), + IntervalMatrixBase(x.template cast()), VectorBase(x.template cast()) { assert_release(x.cols() == 1); diff --git a/src/core/matrices/codac2_MatrixBase.h b/src/core/matrices/codac2_MatrixBase.h index b719df52..0be43dc9 100644 --- a/src/core/matrices/codac2_MatrixBase.h +++ b/src/core/matrices/codac2_MatrixBase.h @@ -12,6 +12,7 @@ #include #include "codac2_eigen.h" #include "codac2_assert.h" +#include "codac2_MatrixBase_fwd.h" #include "codac2_MatrixBaseBlock.h" namespace codac2 @@ -22,29 +23,33 @@ namespace codac2 template struct MatrixBaseBlock; - template - using EigenMatrix = Eigen::Matrix; + template + using EigenMatrix = Eigen::Matrix; - template + template class MatrixBase { public: explicit MatrixBase(size_t r, size_t c) - : _e(EigenMatrix(r,c)) + : _e(EigenMatrix(r,c)) { + assert((Rows == (int)r || Rows == -1) && (Cols == (int)c || Cols == -1)); assert(r >= 0 && c >= 0); } explicit MatrixBase(size_t r, size_t c, const T& x) - : MatrixBase(r,c) + : MatrixBase(r,c) { + assert((Rows == (int)r || Rows == -1) && (Cols == (int)c || Cols == -1)); init(x); } explicit MatrixBase(size_t r, size_t c, const T values[]) - : MatrixBase(r,c) + : MatrixBase(r,c) { + assert((Rows == (int)r || Rows == -1) && (Cols == (int)c || Cols == -1)); + if(values == 0) init(T(0.)); // in case the user called MatrixBase(r,c,0) and 0 is interpreted as NULL! @@ -59,14 +64,16 @@ namespace codac2 } explicit MatrixBase(const std::vector& x) - : MatrixBase(x.size(),1,&x[0]) + : MatrixBase(x.size(),1,&x[0]) { + assert(Rows == -1 && Cols == -1); assert(!x.empty()); } MatrixBase(std::initializer_list> l) - : MatrixBase(0,0 /* will be resized thereafter */) + : MatrixBase(0,0 /* will be resized thereafter */) { + assert(Rows == -1 && Cols == -1); assert(!std::empty(l)); int cols = -1; @@ -88,8 +95,9 @@ namespace codac2 } MatrixBase(const std::vector>& l) - : MatrixBase(0,0 /* will be resized thereafter */) + : MatrixBase(0,0 /* will be resized thereafter */) { + assert(Rows == -1 && Cols == -1); assert(!std::empty(l)); int cols = -1; @@ -118,7 +126,7 @@ namespace codac2 virtual ~MatrixBase() { } - MatrixBase& operator=(const MatrixBase&) = default; + MatrixBase& operator=(const MatrixBase&) = default; size_t size() const { @@ -161,7 +169,7 @@ namespace codac2 minmax_item(max); } - friend bool operator==(const MatrixBase& x1, const MatrixBase& x2) + friend bool operator==(const MatrixBase& x1, const MatrixBase& x2) { if(x1.nb_rows() != x2.nb_rows() || x1.nb_cols() != x2.nb_cols()) return false; @@ -176,7 +184,7 @@ namespace codac2 T& operator()(size_t i, size_t j) { - return const_cast(const_cast*>(this)->operator()(i,j)); + return const_cast(const_cast*>(this)->operator()(i,j)); } const T& operator()(size_t i, size_t j) const @@ -208,36 +216,36 @@ namespace codac2 _e(i,j) = copy(i,j); } - MatrixBaseBlock&,T> block(size_t i, size_t j, size_t p, size_t q) + MatrixBaseBlock&,T> block(size_t i, size_t j, size_t p, size_t q) { assert_release(i >= 0 && p > 0 && i+p <= nb_rows()); assert_release(j >= 0 && q > 0 && j+q <= nb_cols()); return { _e,i,j,p,q }; } - MatrixBaseBlock&,T> block(size_t i, size_t j, size_t p, size_t q) const + MatrixBaseBlock&,T> block(size_t i, size_t j, size_t p, size_t q) const { assert_release(i >= 0 && p > 0 && i+p <= nb_rows()); assert_release(j >= 0 && q > 0 && j+q <= nb_cols()); return { _e,i,j,p,q }; } - MatrixBaseBlock&,T> col(size_t i) + MatrixBaseBlock&,T> col(size_t i) { return block(0,i,nb_rows(),1); } - MatrixBaseBlock&,T> col(size_t i) const + MatrixBaseBlock&,T> col(size_t i) const { return block(0,i,nb_rows(),1); } - MatrixBaseBlock&,T> row(size_t i) + MatrixBaseBlock&,T> row(size_t i) { return block(i,0,1,nb_cols()); } - MatrixBaseBlock&,T> row(size_t i) const + MatrixBaseBlock&,T> row(size_t i) const { return block(i,0,1,nb_cols()); } @@ -255,43 +263,43 @@ namespace codac2 static S zeros(size_t r, size_t c) { assert_release(r >= 0 && c >= 0); - return EigenMatrix::Zero(r,c); + return EigenMatrix::Zero(r,c); } static S ones(size_t r, size_t c) { assert_release(r >= 0 && c >= 0); - return EigenMatrix::Ones(r,c); + return EigenMatrix::Ones(r,c); } static S eye(size_t r, size_t c) { assert_release(r >= 0 && c >= 0); - return EigenMatrix::Identity(r,c); + return EigenMatrix::Identity(r,c); } - template - friend std::ostream& operator<<(std::ostream& os, const MatrixBase& x); + template + friend std::ostream& operator<<(std::ostream& os, const MatrixBase& x); - template - friend S_ abs(const MatrixBase& x); + template + friend S_ abs(const MatrixBase& x); - operator EigenMatrix() + operator EigenMatrix() { - return const_cast&>(const_cast*>(this)->operator EigenMatrix()); + return const_cast&>(const_cast*>(this)->operator EigenMatrix()); } - operator EigenMatrix() const + operator EigenMatrix() const { return _e; } - using iterator = typename EigenMatrix::iterator; - using const_iterator = typename EigenMatrix::const_iterator; + using iterator = typename EigenMatrix::iterator; + using const_iterator = typename EigenMatrix::const_iterator; iterator begin() { - return const_cast(const_cast*>(this)->begin()); + return const_cast(const_cast*>(this)->begin()); } const_iterator begin() const @@ -306,14 +314,14 @@ namespace codac2 iterator end() { - return const_cast(const_cast*>(this)->end()); + return const_cast(const_cast*>(this)->end()); } - EigenMatrix _e; + EigenMatrix _e; }; - template - S abs(const MatrixBase& x) + template + S abs(const MatrixBase& x) { S a(x); @@ -328,8 +336,8 @@ namespace codac2 return a; } - template - std::ostream& operator<<(std::ostream& os, const MatrixBase& x) + template + std::ostream& operator<<(std::ostream& os, const MatrixBase& x) { os << "("; for(size_t i = 0 ; i < x.nb_rows() ; i++) @@ -344,8 +352,8 @@ namespace codac2 return os; } - template - const auto& eigen(const MatrixBase& x) + template + const auto& eigen(const MatrixBase& x) { return x._e; } diff --git a/src/core/matrices/codac2_MatrixBaseBlock.h b/src/core/matrices/codac2_MatrixBaseBlock.h index c1a09b8b..ad8ada14 100644 --- a/src/core/matrices/codac2_MatrixBaseBlock.h +++ b/src/core/matrices/codac2_MatrixBaseBlock.h @@ -12,13 +12,11 @@ #include #include "codac2_eigen.h" #include "codac2_assert.h" +#include "codac2_MatrixBase_fwd.h" #include "codac2_MatrixBase.h" namespace codac2 { - template - class MatrixBase; - template struct MatrixBaseBlock { @@ -42,8 +40,8 @@ namespace codac2 return _q; } - template - void operator=(const MatrixBase& x) + template + void operator=(const MatrixBase& x) { assert_release(x.nb_rows() == _p && x.nb_cols() == _q); _m.block(_i,_j,_p,_q) = x._e; diff --git a/src/core/matrices/codac2_MatrixBase_fwd.h b/src/core/matrices/codac2_MatrixBase_fwd.h new file mode 100644 index 00000000..44fe5ee0 --- /dev/null +++ b/src/core/matrices/codac2_MatrixBase_fwd.h @@ -0,0 +1,16 @@ +/** + * \file codac2_MatrixBase_fwd.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +namespace codac2 +{ + template + class MatrixBase; +} \ No newline at end of file diff --git a/src/core/matrices/codac2_Vector.cpp b/src/core/matrices/codac2_Vector.cpp index 324c7a3d..24768680 100644 --- a/src/core/matrices/codac2_Vector.cpp +++ b/src/core/matrices/codac2_Vector.cpp @@ -21,27 +21,27 @@ namespace codac2 } Vector::Vector(size_t n, double x) - : MatrixBase(n,1,x), + : MatrixBase(n,1,x), VectorBase(n) { assert_release(n >= 0); } Vector::Vector(std::initializer_list l) - : MatrixBase(l.size(),1), + : MatrixBase(l.size(),1), VectorBase(l) { assert_release(!std::empty(l)); } Vector::Vector(const std::vector& l) - : MatrixBase(l.size(),1), + : MatrixBase(l.size(),1), VectorBase(l) { assert_release(!std::empty(l)); } - Vector::Vector(const MatrixBase& x) + Vector::Vector(const MatrixBase& x) : Vector(x._e) { } diff --git a/src/core/matrices/codac2_Vector.h b/src/core/matrices/codac2_Vector.h index 2e59adf4..a75fa6c1 100644 --- a/src/core/matrices/codac2_Vector.h +++ b/src/core/matrices/codac2_Vector.h @@ -29,11 +29,11 @@ namespace codac2 Vector(const std::vector& l); - Vector(const MatrixBase& x); + Vector(const MatrixBase& x); template Vector(const Eigen::MatrixBase& x) - : MatrixBase(x), + : MatrixBase(x), VectorBase(x) { } diff --git a/src/core/matrices/codac2_VectorBase.h b/src/core/matrices/codac2_VectorBase.h index 7340421c..e4c296ff 100644 --- a/src/core/matrices/codac2_VectorBase.h +++ b/src/core/matrices/codac2_VectorBase.h @@ -14,18 +14,18 @@ namespace codac2 { template - class VectorBase : virtual public MatrixBase + class VectorBase : virtual public MatrixBase { public: explicit VectorBase(size_t n) - : MatrixBase(n,1) + : MatrixBase(n,1) { assert_release(n >= 0); } VectorBase(std::initializer_list l) - : MatrixBase(l.size(),1) + : MatrixBase(l.size(),1) { assert(!std::empty(l)); size_t i = 0; @@ -34,7 +34,7 @@ namespace codac2 } VectorBase(const std::vector& l) - : MatrixBase(l.size(),1) + : MatrixBase(l.size(),1) { assert(!std::empty(l)); size_t i = 0; @@ -44,7 +44,7 @@ namespace codac2 template VectorBase(const Eigen::MatrixBase& x) - : MatrixBase(x) + : MatrixBase(x) { } bool is_squared() const = delete; @@ -70,7 +70,7 @@ namespace codac2 void resize(size_t n) { assert_release(n >= 0); - MatrixBase::resize(n,1); + MatrixBase::resize(n,1); } void put(size_t start_id, const S& x) From 10102841c0de31485783b42303dad4f1304aa95c Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 5 Nov 2024 16:44:06 +0100 Subject: [PATCH 031/102] [mat] adding EigenType def --- python/src/core/codac2_py_core.cpp | 8 ++-- .../interval/codac2_py_IntervalMatrix.cpp | 4 +- python/src/core/matrices/codac2_py_Matrix.cpp | 2 +- .../src/core/matrices/codac2_py_MatrixBase.h | 12 +++--- .../core/matrices/codac2_py_MatrixBaseBlock.h | 14 +++---- .../matrices/codac2_py_arithmetic_add.cpp | 4 +- .../matrices/codac2_py_arithmetic_div.cpp | 4 +- .../matrices/codac2_py_arithmetic_mul.cpp | 4 +- .../matrices/codac2_py_arithmetic_sub.cpp | 4 +- src/core/matrices/codac2_MatrixBase.h | 37 +++++++++---------- src/core/matrices/codac2_VectorBase.h | 4 +- src/core/tools/codac2_template_tools.h | 8 ++-- 12 files changed, 52 insertions(+), 53 deletions(-) diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index fbee9d6d..a3f3c681 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -73,19 +73,19 @@ void export_Polygon(py::module& m); void export_arithmetic_add(py::module& m, py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, - py::class_&,double>>& py_B, py::class_&,Interval>>& py_IB); + py::class_>& py_B, py::class_>& py_IB); void export_arithmetic_sub(py::module& m, py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, - py::class_&,double>>& py_B, py::class_&,Interval>>& py_IB); + py::class_>& py_B, py::class_>& py_IB); void export_arithmetic_mul(py::module& m, py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, - py::class_&,double>>& py_B, py::class_&,Interval>>& py_IB); + py::class_>& py_B, py::class_>& py_IB); void export_arithmetic_div(py::module& m, py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, - py::class_&,double>>& py_B, py::class_&,Interval>>& py_IB); + py::class_>& py_B, py::class_>& py_IB); py::class_ export_Vector(py::module& m); py::class_ export_Matrix(py::module& m); diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp index feeb208e..bf337d78 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp @@ -65,11 +65,11 @@ py::class_ export_IntervalMatrix(py::module& m) INTERVALMATRIX_INTERVALMATRIX_CONST_INTERVALVECTOR_REF, "x"_a) - .def(py::init&,double>&>(), + .def(py::init&>(), INTERVALMATRIX_INTERVALMATRIX_CONST_MATRIXBASEBLOCK_QT_REF, "x"_a) - .def(py::init&,Interval>&>(), + .def(py::init&>(), INTERVALMATRIX_INTERVALMATRIX_CONST_MATRIXBASEBLOCK_QT_REF, "x"_a) diff --git a/python/src/core/matrices/codac2_py_Matrix.cpp b/python/src/core/matrices/codac2_py_Matrix.cpp index e4664f58..bc38b11e 100644 --- a/python/src/core/matrices/codac2_py_Matrix.cpp +++ b/python/src/core/matrices/codac2_py_Matrix.cpp @@ -58,7 +58,7 @@ py::class_ export_Matrix(py::module& m) MATRIX_MATRIX_CONST_VECTOR_REF, "x"_a) - .def(py::init&,double>&>(), + .def(py::init&>(), MATRIX_MATRIX_CONST_MATRIXBASEBLOCK_QDOUBLE_REF, "x"_a) diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index d8d54358..f6d182ef 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -136,30 +136,30 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) pyclass - .def("block", [](S& x, size_t_type i, size_t_type j, size_t_type p, size_t_type q) -> MatrixBaseBlock&,T> + .def("block", [](S& x, size_t_type i, size_t_type j, size_t_type p, size_t_type q) -> MatrixBaseBlock { matlab::test_integer(i,j); matlab::test_integer(p,q); return x.block(matlab::input_index(i),matlab::input_index(j),matlab::input_index(p),matlab::input_index(q)); }, py::keep_alive<0,1>(), - MATRIXBASEBLOCK_EIGENMATRIX_TROWSCOLS_REFT_MATRIXBASE_STROWSCOLS_BLOCK_SIZET_SIZET_SIZET_SIZET) + MATRIXBASEBLOCK_EIGENTYPE_REFT_MATRIXBASE_STROWSCOLS_BLOCK_SIZET_SIZET_SIZET_SIZET) - .def("col", [](S& x, size_t_type i) -> MatrixBaseBlock&,T> + .def("col", [](S& x, size_t_type i) -> MatrixBaseBlock { matlab::test_integer(i); return x.col(matlab::input_index(i)); }, py::keep_alive<0,1>(), - MATRIXBASEBLOCK_EIGENMATRIX_TROWSCOLS_REFT_MATRIXBASE_STROWSCOLS_COL_SIZET) + MATRIXBASEBLOCK_EIGENTYPE_REFT_MATRIXBASE_STROWSCOLS_COL_SIZET) - .def("row", [](S& x, size_t_type i) -> MatrixBaseBlock&,T> + .def("row", [](S& x, size_t_type i) -> MatrixBaseBlock { matlab::test_integer(i); return x.row(matlab::input_index(i)); }, py::keep_alive<0,1>(), - MATRIXBASEBLOCK_EIGENMATRIX_TROWSCOLS_REFT_MATRIXBASE_STROWSCOLS_ROW_SIZET) + MATRIXBASEBLOCK_EIGENTYPE_REFT_MATRIXBASE_STROWSCOLS_ROW_SIZET) .def("__call__", [](S& x, size_t_type i, size_t_type j) -> T& { diff --git a/python/src/core/matrices/codac2_py_MatrixBaseBlock.h b/python/src/core/matrices/codac2_py_MatrixBaseBlock.h index 6e1e98dd..14d1a562 100644 --- a/python/src/core/matrices/codac2_py_MatrixBaseBlock.h +++ b/python/src/core/matrices/codac2_py_MatrixBaseBlock.h @@ -22,32 +22,32 @@ namespace py = pybind11; using namespace pybind11::literals; template -py::class_&,T>> export_MatrixBaseBlock(py::module& m, const std::string& name) +py::class_> export_MatrixBaseBlock(py::module& m, const std::string& name) { - py::class_&,T>> exported_mbb_class(m, name.c_str(), MATRIXBASEBLOCK_MAIN); + py::class_> exported_mbb_class(m, name.c_str(), MATRIXBASEBLOCK_MAIN); exported_mbb_class - .def("init", [](MatrixBaseBlock&,T>& x, const S& a) + .def("init", [](MatrixBaseBlock& x, const S& a) { return x = a; }, VOID_MATRIXBASEBLOCK_QT_INIT_CONST_S__REF, "x"_a) - .def("nb_rows", &MatrixBaseBlock&,T>::nb_rows, + .def("nb_rows", &MatrixBaseBlock::nb_rows, SIZET_MATRIXBASEBLOCK_QT_NB_ROWS_CONST) - .def("nb_cols", &MatrixBaseBlock&,T>::nb_cols, + .def("nb_cols", &MatrixBaseBlock::nb_cols, SIZET_MATRIXBASEBLOCK_QT_NB_COLS_CONST) - .def("eval", &MatrixBaseBlock&,T>::eval, + .def("eval", &MatrixBaseBlock::eval, AUTO_MATRIXBASEBLOCK_QT_EVAL_CONST) .def(py::self == py::self) .def(py::self != py::self) - .def("__repr__", [](const MatrixBaseBlock&,T>& x) + .def("__repr__", [](const MatrixBaseBlock& x) { std::ostringstream s; s << x; diff --git a/python/src/core/matrices/codac2_py_arithmetic_add.cpp b/python/src/core/matrices/codac2_py_arithmetic_add.cpp index 5c5b8fbd..2adb8232 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_add.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_add.cpp @@ -18,8 +18,8 @@ using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -using B = MatrixBaseBlock&,double>; -using IB = MatrixBaseBlock&,Interval>; +using B = MatrixBaseBlock; +using IB = MatrixBaseBlock; void export_arithmetic_add(py::module& m, py::class_& py_V, py::class_& py_IV, diff --git a/python/src/core/matrices/codac2_py_arithmetic_div.cpp b/python/src/core/matrices/codac2_py_arithmetic_div.cpp index eb318df7..ee430951 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_div.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_div.cpp @@ -18,8 +18,8 @@ using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -using B = MatrixBaseBlock&,double>; -using IB = MatrixBaseBlock&,Interval>; +using B = MatrixBaseBlock; +using IB = MatrixBaseBlock; void export_arithmetic_div(py::module& m, py::class_& py_V, py::class_& py_IV, diff --git a/python/src/core/matrices/codac2_py_arithmetic_mul.cpp b/python/src/core/matrices/codac2_py_arithmetic_mul.cpp index 94713df0..adfeaf1d 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_mul.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_mul.cpp @@ -18,8 +18,8 @@ using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -using B = MatrixBaseBlock&,double>; -using IB = MatrixBaseBlock&,Interval>; +using B = MatrixBaseBlock; +using IB = MatrixBaseBlock; void export_arithmetic_mul(py::module& m, py::class_& py_V, py::class_& py_IV, diff --git a/python/src/core/matrices/codac2_py_arithmetic_sub.cpp b/python/src/core/matrices/codac2_py_arithmetic_sub.cpp index 715fb06e..eaca2259 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_sub.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_sub.cpp @@ -18,8 +18,8 @@ using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -using B = MatrixBaseBlock&,double>; -using IB = MatrixBaseBlock&,Interval>; +using B = MatrixBaseBlock; +using IB = MatrixBaseBlock; void export_arithmetic_sub(py::module& m, py::class_& py_V, py::class_& py_IV, diff --git a/src/core/matrices/codac2_MatrixBase.h b/src/core/matrices/codac2_MatrixBase.h index 0be43dc9..3d334912 100644 --- a/src/core/matrices/codac2_MatrixBase.h +++ b/src/core/matrices/codac2_MatrixBase.h @@ -23,16 +23,15 @@ namespace codac2 template struct MatrixBaseBlock; - template - using EigenMatrix = Eigen::Matrix; - template class MatrixBase { public: + using EigenType = Eigen::Matrix; + explicit MatrixBase(size_t r, size_t c) - : _e(EigenMatrix(r,c)) + : _e(EigenType(r,c)) { assert((Rows == (int)r || Rows == -1) && (Cols == (int)c || Cols == -1)); assert(r >= 0 && c >= 0); @@ -216,36 +215,36 @@ namespace codac2 _e(i,j) = copy(i,j); } - MatrixBaseBlock&,T> block(size_t i, size_t j, size_t p, size_t q) + MatrixBaseBlock block(size_t i, size_t j, size_t p, size_t q) { assert_release(i >= 0 && p > 0 && i+p <= nb_rows()); assert_release(j >= 0 && q > 0 && j+q <= nb_cols()); return { _e,i,j,p,q }; } - MatrixBaseBlock&,T> block(size_t i, size_t j, size_t p, size_t q) const + MatrixBaseBlock block(size_t i, size_t j, size_t p, size_t q) const { assert_release(i >= 0 && p > 0 && i+p <= nb_rows()); assert_release(j >= 0 && q > 0 && j+q <= nb_cols()); return { _e,i,j,p,q }; } - MatrixBaseBlock&,T> col(size_t i) + MatrixBaseBlock col(size_t i) { return block(0,i,nb_rows(),1); } - MatrixBaseBlock&,T> col(size_t i) const + MatrixBaseBlock col(size_t i) const { return block(0,i,nb_rows(),1); } - MatrixBaseBlock&,T> row(size_t i) + MatrixBaseBlock row(size_t i) { return block(i,0,1,nb_cols()); } - MatrixBaseBlock&,T> row(size_t i) const + MatrixBaseBlock row(size_t i) const { return block(i,0,1,nb_cols()); } @@ -263,19 +262,19 @@ namespace codac2 static S zeros(size_t r, size_t c) { assert_release(r >= 0 && c >= 0); - return EigenMatrix::Zero(r,c); + return EigenType::Zero(r,c); } static S ones(size_t r, size_t c) { assert_release(r >= 0 && c >= 0); - return EigenMatrix::Ones(r,c); + return EigenType::Ones(r,c); } static S eye(size_t r, size_t c) { assert_release(r >= 0 && c >= 0); - return EigenMatrix::Identity(r,c); + return EigenType::Identity(r,c); } template @@ -284,18 +283,18 @@ namespace codac2 template friend S_ abs(const MatrixBase& x); - operator EigenMatrix() + operator EigenType() { - return const_cast&>(const_cast*>(this)->operator EigenMatrix()); + return const_cast(const_cast*>(this)->operator EigenType()); } - operator EigenMatrix() const + operator EigenType() const { return _e; } - using iterator = typename EigenMatrix::iterator; - using const_iterator = typename EigenMatrix::const_iterator; + using iterator = typename EigenType::iterator; + using const_iterator = typename EigenType::const_iterator; iterator begin() { @@ -317,7 +316,7 @@ namespace codac2 return const_cast(const_cast*>(this)->end()); } - EigenMatrix _e; + EigenType _e; }; template diff --git a/src/core/matrices/codac2_VectorBase.h b/src/core/matrices/codac2_VectorBase.h index e4c296ff..2ee4bcff 100644 --- a/src/core/matrices/codac2_VectorBase.h +++ b/src/core/matrices/codac2_VectorBase.h @@ -96,13 +96,13 @@ namespace codac2 static S zeros(size_t n) { assert_release(n >= 0); - return EigenMatrix::Zero(n,1); + return S::EigenType::Zero(n,1); } static S ones(size_t n) { assert_release(n >= 0); - return EigenMatrix::Ones(n,1); + return S::EigenType::Ones(n,1); } }; diff --git a/src/core/tools/codac2_template_tools.h b/src/core/tools/codac2_template_tools.h index ea5dad5b..489dc5b6 100644 --- a/src/core/tools/codac2_template_tools.h +++ b/src/core/tools/codac2_template_tools.h @@ -17,13 +17,13 @@ namespace codac2 { template concept IsMatrix = (std::is_same_v - || std::is_same_v&,double>,T> - || std::is_same_v&,double>,T>); + || std::is_same_v,T> + || std::is_same_v,T>); template concept IsIntervalMatrix = (std::is_same_v - || std::is_same_v&,Interval>,T> - || std::is_same_v&,Interval>,T>); + || std::is_same_v,T> + || std::is_same_v,T>); template concept IsCtcBaseOrPtr = (std::is_base_of_v,C> From a59fe93513ef19ea1f3e52e6604d701d695b600b Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 5 Nov 2024 17:30:55 +0100 Subject: [PATCH 032/102] [mat] corrected iterator --- python/src/core/matrices/codac2_py_VectorBase.h | 3 +-- src/core/matrices/codac2_MatrixBase.h | 4 ++-- tests/core/matrices/codac2_tests_Vector.cpp | 6 +++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python/src/core/matrices/codac2_py_VectorBase.h b/python/src/core/matrices/codac2_py_VectorBase.h index 4d2cfada..62a1a57b 100644 --- a/python/src/core/matrices/codac2_py_VectorBase.h +++ b/python/src/core/matrices/codac2_py_VectorBase.h @@ -101,8 +101,7 @@ void export_VectorBase(py::module& m, py::class_& pyclass) .def("__iter__", [](const S &x) { - auto x_ = x._e.reshaped(); - return py::make_iterator(x_.begin(), x_.end()); + return py::make_iterator(x._e.begin(), x._e.end()); }, py::keep_alive<0, 1>() /* keep object alive while iterator exists */) ; diff --git a/src/core/matrices/codac2_MatrixBase.h b/src/core/matrices/codac2_MatrixBase.h index 3d334912..5b4931a3 100644 --- a/src/core/matrices/codac2_MatrixBase.h +++ b/src/core/matrices/codac2_MatrixBase.h @@ -298,7 +298,7 @@ namespace codac2 iterator begin() { - return const_cast(const_cast*>(this)->begin()); + return _e.begin(); } const_iterator begin() const @@ -313,7 +313,7 @@ namespace codac2 iterator end() { - return const_cast(const_cast*>(this)->end()); + return _e.end(); } EigenType _e; diff --git a/tests/core/matrices/codac2_tests_Vector.cpp b/tests/core/matrices/codac2_tests_Vector.cpp index 0be891f5..9c8e5f21 100644 --- a/tests/core/matrices/codac2_tests_Vector.cpp +++ b/tests/core/matrices/codac2_tests_Vector.cpp @@ -16,5 +16,9 @@ using namespace codac2; TEST_CASE("Vector") { - + size_t i = 0; + Vector a(3), b {{-1},{2},{-3}}; + for(const auto& bi : b) + a[i++] = bi; + CHECK(a == b); } \ No newline at end of file From 21a61f1be7a83046474a79469afeec849a080b70 Mon Sep 17 00:00:00 2001 From: damien-masse Date: Tue, 5 Nov 2024 20:50:42 +0100 Subject: [PATCH 033/102] Modification for python bindings --- .../src/core/domains/interval/codac2_py_IntervalMatrixBase.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h index a5327983..fbd9f7a9 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h @@ -47,10 +47,10 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) V_INTERVALMATRIXBASE_SVROWSCOLS_MID_CONST) .def("mig", &S::mig, - V_INTERVALMATRIXBASE_SV_MIG_CONST) + V_INTERVALMATRIXBASE_SVROWSCOLS_MIG_CONST) .def("mag", &S::mag, - V_INTERVALMATRIXBASE_SV_MAG_CONST) + V_INTERVALMATRIXBASE_SVROWSCOLS_MAG_CONST) .def("rand", &S::rand, V_INTERVALMATRIXBASE_SVROWSCOLS_RAND_CONST) From ec0558a32d8389dece5291a27e364a1ffa61b69d Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Wed, 6 Nov 2024 09:09:08 +0100 Subject: [PATCH 034/102] =?UTF-8?q?[graphics]=20added=20comment=20for=20fu?= =?UTF-8?q?ture=20doc=20(Thanks=20Ma=C3=ABl)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 2 +- src/graphics/3rd/ipe/codac2_Figure2D_IPE.h | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 9d5e0e2f..6808f8b0 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -2,7 +2,7 @@ * codac2_Figure2D_IPE.cpp * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou + * \author Simon Rohou, Maël Godard * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h index f121efdc..f757c504 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h @@ -2,7 +2,7 @@ * \file codac2_Figure2D_IPE.h * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou + * \author Simon Rohou, Maël Godard * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ @@ -29,6 +29,24 @@ namespace codac2 void update_window_properties(); void center_viewbox(const Vector& c, const Vector& r); void begin_path(const StyleProperties& s,bool tip); + + /* For future doc: + https://github.com/codac-team/codac/pull/126#discussion_r1829030491 + Pour les véhicules (draw_tank et draw_AUV) le header par défaut du begin_path n'est pas suffisant. + J'ai donc ajouté cette fonction qui fait le même travail que le begin_path, avec en plus le champ + "matrix" complété. + Ce champ contient 6 valeurs : les 4 premières sont la matrice de transformation 2D, rotation et + dilatation, "par colonne" (i.e. m11, m21, m12, m22) et les 2 autres valeurs sont la translation. + Le tout permet de scale le véhicule, l'orienter et le déplacer au bon endroit. + Cette fonction écrit dans le xml quelque chose dans le style : + + */ void begin_path_with_matrix(const Vector& x, float length, const StyleProperties& s); // Geometric shapes From b6bc7f44c216c0bebade467f215d41ea685b15ac Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Wed, 6 Nov 2024 11:42:54 +0100 Subject: [PATCH 035/102] [cmake] corrected FAST_RELEASE config (closes #128) --- CMakeLists.txt | 3 ++- examples/01_batman/CMakeLists.txt | 5 +++++ examples/02_centered_form/CMakeLists.txt | 5 +++++ examples/03_sivia/CMakeLists.txt | 5 +++++ src/core/tools/codac2_assert.h | 2 +- 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f25b75d8..33f7debf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,8 @@ ################################################################################ if(FAST_RELEASE) - add_compile_definitions(FAST_RELEASE=1) + add_compile_definitions(FAST_RELEASE) + message(STATUS "You are running Codac in fast release mode. (option -DCMAKE_BUILD_TYPE=Release is required)") endif() add_subdirectory(src) # C++ sources diff --git a/examples/01_batman/CMakeLists.txt b/examples/01_batman/CMakeLists.txt index ce2e8a92..3c62a678 100644 --- a/examples/01_batman/CMakeLists.txt +++ b/examples/01_batman/CMakeLists.txt @@ -38,6 +38,11 @@ # Compilation + if(FAST_RELEASE) + add_compile_definitions(FAST_RELEASE) + message(STATUS "You are running Codac in fast release mode. (option -DCMAKE_BUILD_TYPE=Release is required)") + endif() + add_executable(${PROJECT_NAME} main.cpp) target_compile_options(${PROJECT_NAME} PUBLIC ${CODAC_CXX_FLAGS}) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CODAC_INCLUDE_DIRS}) diff --git a/examples/02_centered_form/CMakeLists.txt b/examples/02_centered_form/CMakeLists.txt index ce2e8a92..3c62a678 100644 --- a/examples/02_centered_form/CMakeLists.txt +++ b/examples/02_centered_form/CMakeLists.txt @@ -38,6 +38,11 @@ # Compilation + if(FAST_RELEASE) + add_compile_definitions(FAST_RELEASE) + message(STATUS "You are running Codac in fast release mode. (option -DCMAKE_BUILD_TYPE=Release is required)") + endif() + add_executable(${PROJECT_NAME} main.cpp) target_compile_options(${PROJECT_NAME} PUBLIC ${CODAC_CXX_FLAGS}) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CODAC_INCLUDE_DIRS}) diff --git a/examples/03_sivia/CMakeLists.txt b/examples/03_sivia/CMakeLists.txt index ce2e8a92..3c62a678 100644 --- a/examples/03_sivia/CMakeLists.txt +++ b/examples/03_sivia/CMakeLists.txt @@ -38,6 +38,11 @@ # Compilation + if(FAST_RELEASE) + add_compile_definitions(FAST_RELEASE) + message(STATUS "You are running Codac in fast release mode. (option -DCMAKE_BUILD_TYPE=Release is required)") + endif() + add_executable(${PROJECT_NAME} main.cpp) target_compile_options(${PROJECT_NAME} PUBLIC ${CODAC_CXX_FLAGS}) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CODAC_INCLUDE_DIRS}) diff --git a/src/core/tools/codac2_assert.h b/src/core/tools/codac2_assert.h index 7c68dd64..c054a228 100644 --- a/src/core/tools/codac2_assert.h +++ b/src/core/tools/codac2_assert.h @@ -18,7 +18,7 @@ namespace codac2 { #if defined FAST_RELEASE & defined NDEBUG - #define assert_release(ignore_test,ignore_message) ((void)0) + #define assert_release(ignore_test) ((void)0) #else From 8074ecf3daa0e3cafa9d606baa279ce4e5e4ab6a Mon Sep 17 00:00:00 2001 From: godardma Date: Wed, 6 Nov 2024 16:03:27 +0100 Subject: [PATCH 036/102] [graphics] updated VIBes files --- examples/00_graphics/graphic_examples.py | 2 +- src/graphics/3rd/vibes/vibes.cpp | 223 ++++++++++++++--------- src/graphics/3rd/vibes/vibes.h | 10 +- src/graphics/styles/codac2_Color.cpp | 2 +- src/graphics/styles/codac2_Color.h | 2 +- 5 files changed, 151 insertions(+), 88 deletions(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index 97777710..ae9dcb45 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -37,7 +37,7 @@ DefaultView.set(fig1) DefaultView.draw_box([[2.2,2.5],[2.2,2.5]],[Color.blue(),Color.cyan(0.8)]) -fig2.draw_AUV([1,1,3.14/2],1.,[Color.black(),Color.yellow()]) +fig2.draw_AUV([1,1,3.14/2],2.,[Color.black(),Color.yellow()]) fig2.draw_tank([2,1,3.14/2],1.,[Color.black(),Color.yellow()]) fig2.draw_pie([2,2],[1.5,2.5],[(3*3.14/4)-0.5,(3*3.14/4)+0.5],[Color.blue(),Color.cyan()]) fig2.draw_polyline([[2,-0.5],[4,0.5],[3,1.5],[4,2.5],[3,3]], Color.red()) diff --git a/src/graphics/3rd/vibes/vibes.cpp b/src/graphics/3rd/vibes/vibes.cpp index 63038abd..e55a9c13 100644 --- a/src/graphics/3rd/vibes/vibes.cpp +++ b/src/graphics/3rd/vibes/vibes.cpp @@ -1,7 +1,7 @@ // This file is part of VIBes' C++ API // // Copyright (c) 2013-2015 Vincent Drevelle, Jeremy Nicola, Simon Rohou, -// Benoit Desrochers +// Benoit Desrochers, Maël Godard // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,6 +28,7 @@ #include #include #include +#include // // Vibes properties key,value system implementation @@ -94,7 +95,8 @@ namespace vibes namespace { /// Current communication file descriptor - FILE *channel=0; + // FILE *channel=nullptr; + std::shared_ptr channel; /// Current figure name (client-maintained state) string current_fig="default"; @@ -125,59 +127,83 @@ namespace vibes void beginDrawing(const std::string &fileName) { - channel=fopen(fileName.c_str(),"a"); + if (!channel) + channel = std::shared_ptr( + fopen(fileName.c_str(),"a"), + // Callback for automatically closing the file + // when the shared_ptr is released: + [](FILE* file) { + if(file) + fclose(file); + } + ); + } + + void beginDrawingIfNeeded() + { + if (!channel) + { + beginDrawing(); + } } void endDrawing() { - fclose(channel); + } + + // // Figure management // void newFigure(const std::string &figureName) { + beginDrawingIfNeeded(); std::string msg; if (!figureName.empty()) current_fig = figureName; msg ="{\"action\":\"new\"," "\"figure\":\""+(figureName.empty()?current_fig:figureName)+"\"}\n\n"; - fputs(msg.c_str(),channel); - fflush(channel); + fputs(msg.c_str(),channel.get()); + fflush(channel.get()); } void clearFigure(const std::string &figureName) { + beginDrawingIfNeeded(); std::string msg; msg="{\"action\":\"clear\"," "\"figure\":\""+(figureName.empty()?current_fig:figureName)+"\"}\n\n"; - fputs(msg.c_str(),channel); - fflush(channel); + fputs(msg.c_str(),channel.get()); + fflush(channel.get()); } void closeFigure(const std::string &figureName) { + beginDrawingIfNeeded(); std::string msg; msg="{\"action\":\"close\"," "\"figure\":\""+(figureName.empty()?current_fig:figureName)+"\"}\n\n"; - fputs(msg.c_str(),channel); - fflush(channel); + fputs(msg.c_str(),channel.get()); + fflush(channel.get()); } void saveImage(const std::string &fileName, const std::string &figureName) { - std::string msg; - msg="{\"action\":\"export\"," - "\"figure\":\""+(figureName.empty()?current_fig:figureName)+"\"," - "\"file\":\""+fileName+"\"}\n\n"; - fputs(msg.c_str(),channel); - fflush(channel); + beginDrawingIfNeeded(); + std::string msg; + msg="{\"action\":\"export\"," + "\"figure\":\""+(figureName.empty()?current_fig:figureName)+"\"," + "\"file\":\""+fileName+"\"}\n\n"; + fputs(msg.c_str(),channel.get()); + fflush(channel.get()); } void selectFigure(const std::string &figureName) { - current_fig = figureName; + beginDrawingIfNeeded(); + current_fig = figureName; } @@ -187,17 +213,20 @@ namespace vibes void axisAuto(const std::string &figureName) { + beginDrawingIfNeeded(); setFigureProperty(figureName.empty()?current_fig:figureName, "viewbox", "auto"); } void axisLimits(const double &x_lb, const double &x_ub, const double &y_lb, const double &y_ub, const std::string &figureName) { + beginDrawingIfNeeded(); Vec4d v4d = { x_lb, x_ub, y_lb, y_ub }; setFigureProperty(figureName.empty()?current_fig:figureName, "viewbox", v4d); } void axisLabels(const std::string &x_label, const std::string &y_label, const std::string &figureName) { + beginDrawingIfNeeded(); vector labels; labels.push_back(x_label); labels.push_back(y_label); @@ -206,6 +235,7 @@ namespace vibes void axisLabels(const std::vector &labels, const std::string &figureName) { + beginDrawingIfNeeded(); setFigureProperty( figureName.empty()?current_fig:figureName, "axislabels", labels); } @@ -216,18 +246,20 @@ namespace vibes void drawBox(const double &x_lb, const double &x_ub, const double &y_lb, const double &y_ub, Params params) { + beginDrawingIfNeeded(); Vec4d v4d = { x_lb, x_ub, y_lb, y_ub }; Params msg; msg["action"] = "draw"; msg["figure"] = params.pop("figure",current_fig); msg["shape"] = (params, "type", "box", "bounds", v4d); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawBox(const vector &bounds, Params params) { + beginDrawingIfNeeded(); assert(!bounds.empty()); assert(bounds.size()%2 == 0); @@ -236,13 +268,14 @@ namespace vibes msg["figure"] = params.pop("figure",current_fig); msg["shape"] = (params, "type", "box", "bounds", vector(bounds.begin(),bounds.end())); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawEllipse(const double &cx, const double &cy, const double &a, const double &b, const double &rot, Params params) { + beginDrawingIfNeeded(); Vec2d vc = { cx, cy }; Vec2d va = {a, b}; Params msg; @@ -253,14 +286,15 @@ namespace vibes "axis", va, "orientation", rot); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawConfidenceEllipse(const double &cx, const double &cy, const double &sxx, const double &sxy, const double &syy, const double &K, Params params) { + beginDrawingIfNeeded(); Vec2d vc = {cx, cy}; Vec4d vcov = { sxx, sxy, sxy, syy }; Params msg; @@ -271,13 +305,14 @@ namespace vibes "covariance", vcov, "sigma", K); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawConfidenceEllipse(const vector ¢er, const vector &cov, const double &K, Params params) { + beginDrawingIfNeeded(); Params msg; msg["action"] = "draw"; msg["figure"] = params.pop("figure",current_fig); @@ -286,13 +321,14 @@ namespace vibes "covariance", vector(cov.begin(),cov.end()), "sigma", K); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawSector(const double &cx, const double &cy, const double &a, const double &b, const double &startAngle, const double &endAngle, Params params) { + beginDrawingIfNeeded(); // Angle need to be in degree Params msg; Vec2d cxy={ cx, cy }; @@ -306,13 +342,14 @@ namespace vibes "orientation", 0, "angles", startEnd); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawPie(const double &cx, const double &cy, const double &r_min, const double &r_max, const double &theta_min, const double &theta_max, Params params) { + beginDrawingIfNeeded(); // Angle need to be in degree Params msg; Vec2d cxy = { cx, cy }; @@ -325,36 +362,39 @@ namespace vibes "rho", rMinMax, "theta", thetaMinMax); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawPoint(const double &cx, const double &cy, Params params) { + beginDrawingIfNeeded(); Params msg; Vec2d cxy = { cx, cy }; msg["action"]="draw"; msg["figure"]=params.pop("figure",current_fig); msg["shape"]=(params, "type","point", "point",cxy); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawPoint(const double &cx, const double &cy, const double &radius, Params params) { + beginDrawingIfNeeded(); Params msg; Vec2d cxy = { cx, cy }; msg["action"]="draw"; msg["figure"]=params.pop("figure",current_fig); msg["shape"]=(params, "type","point", "point",cxy,"Radius",radius); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawRing(const double &cx, const double &cy, const double &r_min, const double &r_max, Params params) { + beginDrawingIfNeeded(); Params msg; Vec2d cxy = { cx, cy }; Vec2d rMinMax = { r_min, r_max }; @@ -363,48 +403,52 @@ namespace vibes msg["shape"] = (params, "type", "ring", "center", cxy, "rho", rMinMax); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawBoxes(const std::vector > &bounds, Params params) { + beginDrawingIfNeeded(); Params msg; msg["action"] = "draw"; msg["figure"] = params.pop("figure",current_fig); msg["shape"] = (params, "type", "boxes", "bounds", bounds); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawBoxesUnion(const std::vector > &bounds, Params params) { + beginDrawingIfNeeded(); Params msg; msg["action"] = "draw"; msg["figure"] = params.pop("figure",current_fig); msg["shape"] = (params, "type", "boxes union", "bounds", bounds); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawLine(const std::vector > &points, Params params) { + beginDrawingIfNeeded(); Params msg; msg["action"] = "draw"; msg["figure"] = params.pop("figure",current_fig); msg["shape"] = (params, "type", "line", "points", points); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawLine(const std::vector &x, const std::vector &y, Params params) { + beginDrawingIfNeeded(); // Reshape x and y into a vector of points std::vector points; std::vector::const_iterator itx = x.begin(); @@ -422,8 +466,8 @@ namespace vibes msg["shape"] = (params, "type", "line", "points", points); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } //void drawPoints(const std::vector > &points, Params params) @@ -433,8 +477,8 @@ namespace vibes // msg["figure"] = params.pop("figure",current_fig); // msg["shape"] = (params, "type", "points", // "points", points); - // fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - // fflush(channel); + // fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + // fflush(channel.get()); //} //void drawPoints(const std::vector > &points, const std::vector &colorLevels, const std::vector &radiuses, Params params) @@ -446,12 +490,13 @@ namespace vibes // "points", points, // "colorLevels", colorLevels, // "radiuses", radiuses); - // fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - // fflush(channel); + // fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + // fflush(channel.get()); //} void drawPoints(const std::vector &x, const std::vector &y, Params params) { + beginDrawingIfNeeded(); // Reshape x and y into a vector of points std::vector points; std::vector::const_iterator itx = x.begin(); @@ -469,8 +514,8 @@ namespace vibes msg["shape"] = (params, "type", "points", "centers", points); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } //void drawPoints(const std::vector &x, const std::vector y, const std::vector &colorLevels, Params params) @@ -493,8 +538,8 @@ namespace vibes // "points", points, // "colorLevels", colorLevels); // - // fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - // fflush(channel); + // fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + // fflush(channel.get()); //} //void drawPoints(const std::vector &x, const std::vector y, const std::vector &colorLevels, const std::vector &radiuses, Params params) @@ -518,12 +563,13 @@ namespace vibes // "colorLevels", colorLevels, // "radiuses", radiuses); // - // fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - // fflush(channel); + // fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + // fflush(channel.get()); //} void drawArrow(const double &xA, const double &yA, const double &xB, const double &yB, const double &tip_length, Params params) { + beginDrawingIfNeeded(); // Reshape A and B into a vector of points std::vector points; Vec2d va = { xA, yA }; @@ -539,12 +585,13 @@ namespace vibes "points", points, "tip_length", tip_length); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawArrow(const std::vector > &points, const double &tip_length, Params params) { + beginDrawingIfNeeded(); Params msg; msg["action"] = "draw"; msg["figure"] = params.pop("figure",current_fig); @@ -552,12 +599,13 @@ namespace vibes "points", points, "tip_length", tip_length); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawArrow(const std::vector &x, const std::vector &y, const double &tip_length, Params params) { + beginDrawingIfNeeded(); // Reshape x and y into a vector of points std::vector points; std::vector::const_iterator itx = x.begin(); @@ -576,12 +624,13 @@ namespace vibes "points", points, "tip_length", tip_length); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawPolygon(const std::vector &x, const std::vector &y, Params params) { + beginDrawingIfNeeded(); // Reshape x and y into a vector of points std::vector points; std::vector::const_iterator itx = x.begin(); @@ -599,12 +648,13 @@ namespace vibes msg["shape"] = (params, "type", "polygon", "bounds", points); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawVehicle(const double &cx, const double &cy, const double &rot, const double &length, Params params) { + beginDrawingIfNeeded(); Vec2d vc = { cx, cy }; Params msg; msg["action"] = "draw"; @@ -614,12 +664,13 @@ namespace vibes "length", length, "orientation", rot); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawAUV(const double &cx, const double &cy, const double &rot, const double &length, Params params) { + beginDrawingIfNeeded(); Vec2d vc = { cx, cy }; Params msg; msg["action"] = "draw"; @@ -629,12 +680,13 @@ namespace vibes "length", length, "orientation", rot); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawTank(const double &cx, const double &cy, const double &rot, const double &length, Params params) { + beginDrawingIfNeeded(); Vec2d vc = { cx, cy }; Params msg; msg["action"] = "draw"; @@ -644,12 +696,13 @@ namespace vibes "length", length, "orientation", rot); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void drawRaster(const std::string& rasterFilename, const double &xlb, const double &yub, const double &xres, const double &yres, Params params) { + beginDrawingIfNeeded(); Vec2d ul_corner = { xlb, yub }; Vec2d scale = { xres, yres }; @@ -662,13 +715,14 @@ namespace vibes "scale", scale ); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void newGroup(const std::string &name, Params params) { + beginDrawingIfNeeded(); // Send message Params msg; msg["action"] = "draw"; @@ -676,19 +730,20 @@ namespace vibes msg["shape"] = (params, "type", "group", "name", name); - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void clearGroup(const std::string &figureName, const std::string &groupName) { + beginDrawingIfNeeded(); Params msg; msg["action"] = "clear"; msg["figure"] = figureName; msg["group"] = groupName; - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void clearGroup(const std::string &groupName) @@ -699,13 +754,14 @@ namespace vibes void removeObject(const std::string &figureName, const std::string &objectName) { + beginDrawingIfNeeded(); Params msg; msg["action"] = "delete"; msg["figure"] = figureName; msg["object"] = objectName; - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void removeObject(const std::string &objectName) @@ -716,23 +772,26 @@ namespace vibes // Property modification void setFigureProperties(const std::string &figureName, const Params &properties) { + beginDrawingIfNeeded(); // Send message Params msg; msg["action"] = "set"; msg["figure"] = figureName; msg["properties"] = properties; - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void setFigureProperties(const Params &properties) { + beginDrawingIfNeeded(); setFigureProperties(current_fig, properties); } void setObjectProperties(const std::string &figureName, const std::string &objectName, const Params &properties) { + beginDrawingIfNeeded(); // Send message Params msg; msg["action"] = "set"; @@ -740,12 +799,12 @@ namespace vibes msg["object"] = objectName; msg["properties"] = properties; - fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel); - fflush(channel); + fputs(Value(msg).toJSONString().append("\n\n").c_str(), channel.get()); + fflush(channel.get()); } void setObjectProperties(const std::string &objectName, const Params &properties) { setObjectProperties(current_fig, objectName, properties); } -} +} \ No newline at end of file diff --git a/src/graphics/3rd/vibes/vibes.h b/src/graphics/3rd/vibes/vibes.h index 7fb859a9..bdfb094e 100644 --- a/src/graphics/3rd/vibes/vibes.h +++ b/src/graphics/3rd/vibes/vibes.h @@ -7,7 +7,7 @@ // This file is part of VIBes' C++ API // // Copyright (c) 2013-2015 Vincent Drevelle, Jeremy Nicola, Simon Rohou, -// Benoit Desrochers +// Benoit Desrochers, Maël Godard // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -221,9 +221,13 @@ namespace vibes { /// Start VIBes in file saving mode. All commands are saved to the specified file. void beginDrawing(const std::string &fileName); + /// Start VIBes in connected mode: connects to the VIBes viewer if needed. + void beginDrawingIfNeeded(); + /// Close connection to the viewer or the drawing file. void endDrawing(); + /** @} */ // end of group connection @@ -460,7 +464,7 @@ namespace vibes { * \param params Optional attributes * * Draws a circle of radius \a r with center at (\a cx , \a cy ). - * This functions internally calls drawEllipse + * This functions internally calls \fn drawEllipse */ inline void drawCircle(const double &cx, const double &cy, const double &r, Params params) { @@ -537,4 +541,4 @@ namespace vibes { #define vibesDrawCircle(cx,cy,r,...) vibes::drawCircle(cx,cy,r,vibesParams(__VA_ARGS__)) #endif //#ifdef VIBES_GENERATE_vibesXXX_MACROS -#endif //#ifndef VIBES_CPP_API_H +#endif //#ifndef VIBES_CPP_API_H \ No newline at end of file diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index 8e6c6a78..879e0c27 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -2,7 +2,7 @@ * codac2_Color.cpp * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou + * \author Simon Rohou, Maël Godard * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index b3e3efd4..6d8a992c 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -2,7 +2,7 @@ * \file codac2_Color.h * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou + * \author Simon Rohou, Maël Godard * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ From a69d089873145fe7a2afb06f7c53cea7843f1fd2 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sun, 3 Nov 2024 19:44:20 +0100 Subject: [PATCH 037/102] Test specific IBEX version --- .github/workflows/dockermatrix.yml | 8 ++++---- .github/workflows/macosmatrix.yml | 2 +- .github/workflows/unixmatrix.yml | 14 +++++++------- .github/workflows/vcmatrix.yml | 6 +++--- packages/temporary/gennewcodacpi_armhf.sh | 4 ++-- scripts/dependencies/install_ibex.sh | 3 ++- scripts/docker/build_pybinding.sh | 2 +- scripts/docker/build_pybinding_codac4matlab.sh | 2 +- 8 files changed, 21 insertions(+), 20 deletions(-) diff --git a/.github/workflows/dockermatrix.yml b/.github/workflows/dockermatrix.yml index 8232472e..e311ea61 100644 --- a/.github/workflows/dockermatrix.yml +++ b/.github/workflows/dockermatrix.yml @@ -70,11 +70,11 @@ jobs: if [ ${{ matrix.cfg.deb }} = true ]; then \ sudo sh -c 'echo \"deb [trusted=yes] https://packages.ensta-bretagne.fr/\$(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 dpkg-dev || true && \ - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/libibex-dev-2.8.9.20240417-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb --no-check-certificate -nv && \ - sudo dpkg -i libibex-dev-2.8.9.20240417-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb && \ - rm -Rf libibex-dev-2.8.9.20240417-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb ; \ + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb --no-check-certificate -nv && \ + sudo dpkg -i libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb && \ + rm -Rf libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb ; \ else \ - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv && \ + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv && \ unzip -q ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip && \ rm -Rf ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip && \ sudo cp -Rf ibex/* /usr/ ; \ diff --git a/.github/workflows/macosmatrix.yml b/.github/workflows/macosmatrix.yml index 941ec5b3..7a598d6b 100644 --- a/.github/workflows/macosmatrix.yml +++ b/.github/workflows/macosmatrix.yml @@ -60,7 +60,7 @@ jobs: - run: brew install graphviz ; brew install --formula doxygen ; python -m pip install --upgrade pip ; pip install --upgrade wheel setuptools sphinx breathe sphinx_rtd_theme sphinx-tabs sphinx-issues sphinx-reredirects if: runner.os=='macOS' - run: | - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv unzip -q ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip rm -Rf ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip sudo cp -Rf ibex/* /usr/local/ diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index 801f6c85..ff53bd5a 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -120,18 +120,18 @@ jobs: if: (matrix.cfg.runtime=='mingw13') - run: | choco install -y -r --no-progress eigen --version=3.4.0.20240224 ${{ matrix.cfg.choco_flags }} - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex.2.8.9.20240417.nupkg --no-check-certificate -nv - choco install -y -r --no-progress --ignore-dependencies -s . ibex --version=2.8.9.20240417 ${{ matrix.cfg.choco_flags }} --params "'/url:https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip'" - del /f /q ibex.2.8.9.20240417.nupkg + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex.2.8.9.20241103.nupkg --no-check-certificate -nv + choco install -y -r --no-progress --ignore-dependencies -s . ibex --version=2.8.9.20241103 ${{ matrix.cfg.choco_flags }} --params "'/url:https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip'" + del /f /q ibex.2.8.9.20241103.nupkg if: runner.os=='Windows' - run: | sudo sh -c 'echo "deb [trusted=yes] https://packages.ensta-bretagne.fr/$(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' # Replace this line by the next ones to test a specific binary package of IBEX. #sudo apt-get -q update ; sudo apt-get -y install libibex-dev libeigen3-dev dpkg-dev || true sudo apt-get -q update ; sudo apt-get -y install libeigen3-dev dpkg-dev || true - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/libibex-dev-2.8.9.20240417-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb --no-check-certificate -nv - sudo dpkg -i libibex-dev-2.8.9.20240417-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb - rm -Rf libibex-dev-2.8.9.20240417-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb --no-check-certificate -nv + sudo dpkg -i libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb + rm -Rf libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb shell: bash if: matrix.cfg.deb==true - run: | @@ -143,7 +143,7 @@ jobs: if: runner.os=='Linux' - run: | brew install eigen - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv unzip -q ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip rm -Rf ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip sudo cp -Rf ibex/* /usr/local/ diff --git a/.github/workflows/vcmatrix.yml b/.github/workflows/vcmatrix.yml index ff2cf5ae..1fd297b2 100644 --- a/.github/workflows/vcmatrix.yml +++ b/.github/workflows/vcmatrix.yml @@ -63,9 +63,9 @@ jobs: - run: choco install -y -r --no-progress graphviz doxygen.install & python -m pip install --upgrade pip & pip install --upgrade wheel setuptools sphinx breathe sphinx-issues sphinx-tabs sphinx_rtd_theme sphinx-reredirects if: runner.os=='Windows' - run: | - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex.2.8.9.20240417.nupkg --no-check-certificate -nv - choco install -y -r --no-progress --ignore-dependencies -s . ibex --version=2.8.9.20240417 ${{ matrix.cfg.choco_flags }} --params "'/url:https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip'" - del /f /q ibex.2.8.9.20240417.nupkg + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex.2.8.9.20241103.nupkg --no-check-certificate -nv + choco install -y -r --no-progress --ignore-dependencies -s . ibex --version=2.8.9.20241103 ${{ matrix.cfg.choco_flags }} --params "'/url:https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip'" + del /f /q ibex.2.8.9.20241103.nupkg - run: | mkdir build ; cd build cmake -E env CXXFLAGS=" /wd4267 /wd4244 /wd4305 /wd4996" CFLAGS=" /wd4267 /wd4244 /wd4305 /wd4996" cmake ${{ matrix.cfg.cmake_params }} -D CMAKE_INSTALL_PREFIX="../codac" -D BUILD_TESTS=ON -D WITH_CAPD=OFF -D WITH_PYTHON=ON .. diff --git a/packages/temporary/gennewcodacpi_armhf.sh b/packages/temporary/gennewcodacpi_armhf.sh index 9001490a..e6300d72 100644 --- a/packages/temporary/gennewcodacpi_armhf.sh +++ b/packages/temporary/gennewcodacpi_armhf.sh @@ -26,8 +26,8 @@ fi && \ sudo apt-get -q update --allow-releaseinfo-change ; sudo apt-get -y install libeigen3-dev python3-dev patchelf || true && \ python3 -m pip install \$PIP_OPTIONS --upgrade patchelf --prefer-binary --extra-index-url https://www.piwheels.org/simple && \ 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.20240417/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.20240417/ibex_armhf_\$(lsb_release -cs).zip --insecure && \ +# wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/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.20241103/ibex_armhf_\$(lsb_release -cs).zip --insecure && \ unzip -q ibex_armhf_\$(lsb_release -cs).zip && \ rm -Rf ibex_armhf_\$(lsb_release -cs).zip && \ sudo cp -Rf ibex/* /usr/local/ && \ diff --git a/scripts/dependencies/install_ibex.sh b/scripts/dependencies/install_ibex.sh index e115fb32..069399ba 100644 --- a/scripts/dependencies/install_ibex.sh +++ b/scripts/dependencies/install_ibex.sh @@ -3,7 +3,8 @@ cd $HOME echo 'Installing IBEX in ' $HOME '...'; if [ ! -e "ibex-lib/README.md" ]; then - git clone -b master https://github.com/lebarsfa/ibex-lib.git ; + #git clone -b master https://github.com/lebarsfa/ibex-lib.git ; + git clone -b ibex-2.8.9.20241103 https://github.com/lebarsfa/ibex-lib.git ; # To test a specific version of IBEX... cd ibex-lib ; mkdir build && cd build ; cmake -E env CXXFLAGS="-fPIC" CFLAGS="-fPIC" cmake -DCMAKE_INSTALL_PREFIX=$HOME/ibex-lib/build_install -DCMAKE_BUILD_TYPE=Debug .. ; diff --git a/scripts/docker/build_pybinding.sh b/scripts/docker/build_pybinding.sh index a579a7f3..e3e19dc4 100755 --- a/scripts/docker/build_pybinding.sh +++ b/scripts/docker/build_pybinding.sh @@ -2,7 +2,7 @@ set -e -x -wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex_$(uname -m)_manylinux2014.zip --no-check-certificate -nv +wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_$(uname -m)_manylinux2014.zip --no-check-certificate -nv unzip -q ibex_$(uname -m)_manylinux2014.zip rm -Rf ibex_$(uname -m)_manylinux2014.zip sudo cp -Rf ibex/* /usr/local/ diff --git a/scripts/docker/build_pybinding_codac4matlab.sh b/scripts/docker/build_pybinding_codac4matlab.sh index 157d285b..aec5e103 100644 --- a/scripts/docker/build_pybinding_codac4matlab.sh +++ b/scripts/docker/build_pybinding_codac4matlab.sh @@ -2,7 +2,7 @@ set -e -x -wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20240417/ibex_$(uname -m)_manylinux2014.zip --no-check-certificate -nv +wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_$(uname -m)_manylinux2014.zip --no-check-certificate -nv unzip -q ibex_$(uname -m)_manylinux2014.zip rm -Rf ibex_$(uname -m)_manylinux2014.zip sudo cp -Rf ibex/* /usr/local/ From d7913392b119ab648e96f0fb7b4cc94ee9153bdc Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sat, 16 Nov 2024 20:17:06 +0100 Subject: [PATCH 038/102] Improve Catch2 dependency handling --- .github/workflows/unixmatrix.yml | 7 ------- 3rd/Catch2-3.6.0.zip | Bin 0 -> 1470300 bytes tests/CMakeLists.txt | 22 +++++++++++++++++----- 3 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 3rd/Catch2-3.6.0.zip diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index ff53bd5a..4e4212d7 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -135,13 +135,6 @@ jobs: shell: bash if: matrix.cfg.deb==true - run: | -# git clone https://github.com/catchorg/Catch2 -# cd Catch2 -# git checkout v2.x -# mkdir build ; cd build ; cmake .. ; make ; sudo make install - shell: bash - if: runner.os=='Linux' - - run: | brew install eigen wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv unzip -q ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip diff --git a/3rd/Catch2-3.6.0.zip b/3rd/Catch2-3.6.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..d966c07dd3ca4badd528f5655d9548bf9155c520 GIT binary patch literal 1470300 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 LxZ;xGBk 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%0D?p22+$ zR0@S}Y~9m)5&|HW8Ud&?H7K?dIE>N9wgluwoM9zDHWfKcj1g~b&P7L^ASoCuMCnbV zHxZ>XTX`y+>xf&%coa*z^s4MMEbEenyFNq#4l+F=+-Z zeGb~Bwux0RrL>Gnan$>cr9F>4cONkw3x^>c@bVO#N$N&Z$%*Stb%vRC?_qur)(AsY z2mldOrxPIVgqEwxe%00To{3zNcD}br#mG_Ospq_O%eP{-YdYF{oeg)Sq2j;pp%||Z zMPT68@{Nz>^(y}4@#4Jmc5O}>K%{WJly)7Xg zkR{deQ6+n`0~T`#S6Z%cf~|xjTl8yf;)XjfW4M5qeSaY(pl?HyTRZBZ3Jykm){>fU;E6WHYl5V|cL@p&OsRl%Q68)FP`TZznoAT|6i~u@ z5VU7|448mF2M)gXaGa1JdK^9OZz;74yfZk|bpPX~#~HyT{daL0dWKYB$}KFM5Kbc_gD>*UXok5_)Qfx#Dy5HeKXw4 zunE7csKR1%rXlER!SImESJG~vM^{w3xlO_4M8i~h!ifJ2DAhrM?Y4^fj5DGP*$$^_RpG6TK@SzQD#S4c z)KUD0c+;TGmh{VvuAT_}IW~}hazUgF4Ki2tuVYqQmC|1YYzxKU?0#dm4=5Cq1){iw z+OsClMvELM;WMJK`$a=|B1T!yxkd1C{^D}|g?7caF30AG?QExBpl5T4UeT0*@@ZD0 z<3ku(WbCz8ki4_C_bKXBsJFT5`!~(;VfVz+IwlHpl&8GT*HV?NzLUJoN z=hU&1<%!U!oG$8eQ*Fv8apx2Te@i(pm$6JkmUOyHpZvUVWe~dudws3O`cp^H{fw+yPgk-ou2uzogc9-J%u`9h! zYGt9{o>SCo0Zy3x(wCdhnb%kB+8sDPQ{akSvwEp2V5Nqm$|%T8vTH7XSP*~0=Oh$% zBm~0HOuQ*SU_=43CiAktSHS$HH&9-AKiTt^2WpS%A1V{48Ej)}jwAUJ)ag{XnVP z!Oq-8^`*{x9ejJbK9IPoYBmApN{nIakMc68U})rY&du2euamYdWEN*+xDj?F~ZHOeCub5jJSK}5w+=D52*zFs@?%!XTZ>1B37aly8IGHG40NvKJ?;x%TP zq-dc>&t(n7a0KhBjz76geQ4vpd{QS6jGB0^R3-34g8*QryQdZWY+hn>_rju%RK->Y z4Yl9mPMys(7mBZ)N<G2NCW&ppj?j?7JGM;zqjo#KrPgyqco2?dSJemhoT8<}T3R?Oea(upt?yItX z^G@a{M}7dJoqr4K_5G4cPrh_ottpn(&fINxYOjMdYR1G-m~+q%IPDztpe&ld~FddL<8`Pu%5><1Y z2nO;rqjmr_ZLyppZ@HH6PIq(XuvT9=XDutdL}C}C+M9E{5x@W6mH7WD?MdCp#LfPQ zF%ds&_y2*k_m8#(E8~B$M0(2gMy1ohcHSf6Ult}Z)vW6?35wxd;uV@U6ewDc(DK*t zSr|m83oU-RTjCU!u1$b&&|7caqyLr#R*o%ssu=7d5<$6r!7lAI(Zb?w^_zD5hJh+nL znh|CA;(_N0@ufF%1vSiEg}7IL1v!=d5pgL09Vvw?FGPZS%R3E=dg;|S{o9UJgjF_G zPtjyko8vLQy~sbz0(V16VDww6sFyN#ZzB)5XK*0a2;2dV>qE_M;siu#kOQvEIJ&q8 z&W=4;AHUP4D3JA9!wyKz)0J?)n0UrMdqForublx?U_v86!0 z5!v=PgJhEO?h3!TQ?&opE4C%o>y`fF71Q})7yLg++y4YX_^+Vszttlbs*GA~u)uac zE5nWu(q3E<4C~PF=>3KV5`yhXJ*4sJNfLvD4_mM~HSF@zGCg&=Xh^#QW^E~a4r^4F z4PO-dxVc_yaxX4p3o%E%d#iN8=C{n${^gSIVPl2~gou~smjT8Y3bXWvb7hIzG#A?< z&x$IYya!{arHa2rp-qjvNlSel8ZcqM-Y|EOSSnD;fYQ8-&Asid5u^#b6pDcchKeLS zc?PTYZPmDD)jZCa-PBN}2HkKW`IJ^#jWp5nZFj%CnA5jt$xBos7wb;UwXv5(8wk-D=z;026T27}>Ui-PfGJ-~2&>a?(j7Fi0rwn|=#C27Pug7s5!}_-pVt z$E5-RxVWXOV0%)AnNBT~%{!sSs9u*KaPgvCYA};lUvH)p>+qkXj)yY3iYNx&YwcRO zC_-ckf1n}}d&`d`j~|v#UH8)}5(}~RhRI?rfKKV%A>zH$?3EAh1(L}^iv&MwS92R) zUtiTpYj+tmXIEc)b-%jQyZAbf&6FZne)ET?=Dn)F@$UF(c zGpag8^e=kMV;%nm;|E@>mnqVQ@lxpHy!z8%Q3#_o%;7q2g2NY`ytcL^g|Q5wrQ2Rs zB(&9dyE0kew}N8q*&u-%6w|PEnWahT;ts~*h>z3&Anw@w!uU{`bp{JqHw`)fP*`GL zh*Bm8`Vfo=(?d1W6uwb~D+yEu2PMSRrp2Ywm$h=VwXRe zgq4h66;-6t%8w7WZ!k#_nS`O7>=E=*D(UWnhkUggWuONGRrL zW=kCY@u>~s58AxvDv@uKISQrVa0yX2MR*`yWzze#Y!EQaN0yuUg-SjwV!gi7H{!*7>>7xpSX@0(8^KY^AwGgt{Jg|E_ zu$*rD=dHg6%?q0~9N8qQ4556nG`juY55Rz)_oK)^b{~|V22+y%7g_JW#=MP|1)^`<9t68i>a|xd!m(B;RTQ^^u?5ANLw^hY%N{?kLV@IBGk8MG-Z6Tq$Vp>)1o;ew>F#=Vf3>uPN zzO#Vb%YfV%B4!^l86rG})V?T&3iGa?9F8ejSlkWgzWPcH2IEovdHbMaMK&WCI4Rz* zJbxtBBFECWTbJhbLGpb{Bs=yev+?=Eff6C#Srw12H?})ip?k)|G)t63@SldwNLbMu z^nFvUN>T}V^z9WYak(Tpj$u{REbK6vs?r03=eh*z0EyH00K!TH)k6nUx#4D`+ya|6 z%|pMF3Uf+hka-A07Sa+jQL)|h$Q$~^lP(#a@A4J+QCa~J`ZO-T6`#3tg4LKrhy54bMi z6WZy2*0YI7hmHa(wc}b4`_|}*O7dV;Q-Qz32`LfB|I!_WnIuuk=RGWlW(PBQcaW6~ zz$^Qm5+Ms@6N^@&2oe{^i$cxPl%O}Lu+`v7?1_H!6sqJgKT+1y1YfU!VQbo(% zAl*~t7zM8!bav+#V_JkP?uGHRlM6JesE}RJvt{*kI2{b8$F@G8D*+5YU)?56sJhw} z<)O_Q=l+31B^|?s{Y0Ou8uNP?Ndgbqn-RL-B{q)7B`zlUGQB1<4C-$5*vxZQA!@Ao ziwJ>VBgaq~pU^#={}zqan69by#FC1Z>cc84POJ3E392g%#pZ&9tmpa33FN@(RTH!Cg`o2-&3j8nSNrR^ zmlGxvp3#;>P-h6JeUudY9}SOC^Ij!*?x_9!tg_1vwaIY9fh4oQ7GP}Kwn5qlfqmX! zcSoaG=g8OWA@@sTdGwm?SJMHlp&$!TYh%c3s18c+*x%X%On)PvsOe;tyCp$}-lh$} zioc)cWgxR0E0{w~ssRm1qFOXwbv{4JkFlUY#o_Xfn(WCxTr$%7*M?y#6*X!pg+W#8 zpN=<$w4sbi>E393a89NqnW3yl@e}2_k26?1B5l?!P18Z3xj=CcoAu54FC1yMzuR zpSL$TO+&g61bLdf7a>ZxqMvI5D3~MzV8*{oc`VoKSG|x02JuW$lv?2V5(zQt0?O=v z?rXg90x9M@K)ZcJ;BK^vrbHna-hO)dK6uH)NxB257x63P?oX^`!k8fq#?|wCZ~hb0 zjvl9j(X6CHrKEdSlgflKcC`kWvNQN3f;uf3pi6s8cb`ZHWK-XWGEF8$@pay)$Jcmp z^lbYpN1Ho$=eMI1`#qJ+1l=15bOu5AJYFtM81xVPBOGD*!{EG^Xu7{G$!*HC09aRS z&qb(7;fSCpN$=&r70oaMj#M}9*pGWR1#1js{jVTUwE^I4G0!)N$k@WY!aYgK!RjWH z^k)Ea^a#;#MhI42is)kz-NJ$lp|1h>#SB}oX`!gL&~pu;-Xz`4CMQO}V>R8TZIVyH zSudD4vr^-;GUtp&9YT0-caZEOonN{>bF-4ln{C_42%Vol1s5z|ww;G@*}>#*<6v9_ z1TlI~Q9*=o@xhjuFze4YzxbOBh`g4TJ8~p)M8Q~7U?cf5c<^y9g=u|CZ!G54sIJ3X}9)DaydoMgn> zP&pNDi6g$+gSz1&_QL3~gX#=)IEDgs%ne+@PlcY!>zZcb6Fq_ALCPqT^DlpZnw1C#B+H_+?e0lunlU=5BIFfmrt4MvKyzfp=~rES=@q7zKz`G(FSHksREAn zB4&fX1+V(Q#jpCkNuPIHkGJ$XD5jem6ZUOaGkv3d)-cB`7N)H5jGsE(-Nv~l7S~$M ze_t+16gR(QF9dzM)Lp37k0x4*cL^jmzOl)}TqX_uJw(esVmOwFXEkS5RZH=ANiXOJ z==6uvf2x#`+-ZUb9Yj9LT@=S;Y%)}K-EdZjbIO+m{|P)WTAkGHQ(K=|GH1!(+Q*9x z3zhHsEm!03=|i2XQJ=D~l&TrTRnn*V)Y5V$)zr$!`d=0nKN(K5eHw(0b8@VQxxOK*=M)EIx#7Z~n4lKT zCnAN{RV0?Um@Lu$Iq&QGc%}x51~$_h-Jwc70EmrYu$owd*l zMf!rVhvjtAC#gLkGa0`SLgnj{Mutt(uAJHrOl`z9Oy=?>v_{8y-Ect#TeUtiG4LhA zAShGUbW-{xTQh9nY>mvMwD_64N3IS!DDEfuZM)+J&z`ilDwjJ(lcK{taHmp?D7^ef zlhrmK5&Igk#Kj{Cp_Cj?U6KIww_^)BhYKFRo|FAf-g0D}E~q0bH<=YVFxP=AU>tN8 zk@A(%VCnDwl!pQD|YMOLTySw$_f2xOt9|Zy?DoVr+=ER1Z%YcZr(CemCot zuYzOjQ?q`$I6H4leC02V$z#`yWpg$&aHPPS(=QEGPqmu_vCN-Z7N>#j(%Z~**mNc1 za<4&feR9BrcBi@dbZ4EA|LdouR#>#lM<_{|^gALJlWU zX87t-R8*}%3JE%fK@g+iooHrZgh&YqB(Chd>Ge4-!Qh;a_4EqDrXYmgekud?=Y~Wy z(^kZ>4c4SWmI5c3T)o>N^OK1whNezY@SB7Tq(xAT09=6E1^W48L=c-v0{1cIr-)+o zA|u4zLTN>6M{z>#Ps94kj488@GEu1W^vPY?GIoA2v}2TCL$v%VL;WSY6}2i?su2`F z>eh)h4ZW5UK3HHEt|dqvX}*IRy?Pwp9Ze1~tW0YZMhGPchHbPwoEG{VVaPzK7a(u; z1DsVCC=keH*c8d3kYm(3dTsBb9Y+X@C`e51;fr$(i=8D@PeG4cocB=vKo=qi&kum4 z)X;EqMODq603Vd|emQj&^1Dyl&Mb81MF8g?7Vq}>5Hmp8B6?28$Q>Kuh~7#2SkdsB zek4~%AEVc7#}AoXddGP%yIhC#TDECm+{k@_9{A9fRyqcWm{k?WKNE3b&_T>S#|?n49oyzbEv zxG_0?NDeaje}R+u}m1b4KCAuF4o$~I2TEdQsv z;Lu7l)lA8ESy|g9UrN@tG`A3Qvo@9IKDGkDnb8b;2ovMZPJbRZ#)tny*X{ z>kuye$kl>qqo4KZ3#Vt{xPg(zh%eQ`KDg($bHU=?5GL)?&+?Qfm3 zG_>G4t-jx3F8cX-RN$_KMy@oo zJnY)cSZkwO0P)O#(I^af-V0`Dror~Fce6)5FjrQ1bNBV4Iyk*%KP~K6v>680UzIp! z`Df@YcCN5HcU&LM)`Pv9B^PJ0OJt04vKeX0H$_?Z-}A|I7@@A^2SesF(2l?BSi~19 zW^j-6Ok}3F6=Q>(ICKlS(BNa$qp$@#T>o2G#gr$%#p_49A^MSS{s)8NpHG*G3X;}) zJW!p-$|`E5W`#)&?h{@j2r*#-rh+F|TY0*BF|$FU4ErHS@FskwYGZ^0UQOBA znC@LL?%ljv77=Piz(BlopAesMa~mqrzWj!xC4!Xyta$%AMm`$72~mAvgsS%7HWJg~>4`5%@pUJO+%%lUN*PoKyg?J2WFwSzVxQ z?ds)DLB-1C^uliF@T$CVvWJOsyuSC{>~PA!aNCG9g}fPH8%!yxl+b5E!U+yvUT?0J z&^KL{w8>%Tc@riGY@+*EH3eyCx@|x;b+$2ubkfsfo0G&ZhzQoA_``dALis za%`jSrm`O#0c4UU4I@popq8n!0_lL!kTtHR1VX6sp8~07DQ>1TtbejXz0<+4A?5qk zU)cVpH>l)N1`N2l?u_1-z1DUo0Dop8&@XSx#MoRBTQi?9!xkIg0O?J{+@wEK!Jd70 z2SWR`8%*u>Dvh3fvr43Vhn(g+nv>dFo&syAQ{JnVhZVAbogMk0*Xxa9I87;v>h-R# zgQ7a9mRr$U#WC?#vs^4&=>%soL^|ABb9>opu91m|E4Wgao2C-gTGN+Wtr!2$4s~=etba|M0ysid|AEJ* zZYnFV!?xe}{j}@cZ((By^v_%q=Hh*v$Qn$VSu^Mt^TxO*^6kBgw|2$=5EhlcBao z@(&@h<7cNT)b1R#?>6^m>B38(;xj-E5*2Ba0TLY)B*9PZAW1cKO^E#^AC?u@uVHvQ9HW z(yZHxCq(IRqikYGQuiLkQGP?cdhokuU^Vm67ao%t<}M0dsW%qj%D=Xq4Qb3TW)RUT z+K(!oSWyqxYSB)EJ-XjcMp*y007L7*0o zSHe4 z_HOg&NR_^_8tV1~n1<<}3@8#M-nj5`ay92I9^RG2LC%T&Bf^rYIh9p(FCD*L+k5F6 z6RBN=%Vz=zw*+=$mUeJZP^fgNgsZ9vZgb_+LE6IL{EJ$oshcKFtTqyNj-@~Y@HIPM zoJWMTO%LoRw0C4$BwFDCo365&kS2-*t&T7h1_tT$e%$T10f;;DiNt5mzAbl(_=g() zIA3<8018wKqJzr==Tp04Lxy06Y$;z97fFy9_*7OQa4qxc*%wg`_v$o8;#1{}RZ3pw z#d(X{I=8dQdiB!8$};)Lq(+}(n}&U4{B44^<0)v+c4CZ$Rjb)(0>dcHc(oduzk4Zv z@+Hg8KD^XS8otV3DFNDJH~-0cQTKNxt1(F(0iK2l`EORst7}qlsrQy5Tn*xfQy&?{ z@h`97pU}d#hTzph8u@dPl)a<-y0#wGuwZ0sn@t+vH{sD;qMJ6Q#rfA#<(M@&f99)L zgu2@$R;ONBpir)v^WB)9S*QrA0TC`W72q8XNP}*eU^EmvCQpbOb`i7YYPwD`}3%1JV0Ei1V1?M;RZ-#`&VJEhyal{l5Fcl>wGPNyqZOr zQmM+}Rs(vv^+}`XRetOz=E3*2j3gwGz{|6a!rj`$tyIjmGljl6nemP$ti+7Ar41jT zJ={eZ;#PtB-+p;gx)bqHswMM0x|JTopC`47v^!SZZ!!67^TS!&Sd%=s&?LtQBE&*N z7s?o)EYTeB#_at14ebpo_&qr2m$dQHv8xOK6O>qtYvd!k6HpUiIYOdrA0qGDmQ3F! zH(A3JfGjlo>)UCr?_5`Bkgpz{{x;>78|1Q#$yZd?Y`%ntUHYde#b1qhs3Slg+e!Tc z!Hw+^iiyXyWEB>Lk{{1y@h8)kBu<RCwyR#SqnuGj*8t-bv8eK7MSCm-$G~cm+)=Bbi($`nxaW(od7u(CudN`|!DK zjK2c`lKW#dX*C_ImExAO&?P5-P`;<6nisE7H7V40_LrC28inM$GyUX(TUXAmy^e8S zrULEoeVUgDUV4Tf6;xabwRldmqGC1|kOIS~f9mt)*NBe<&I+|{nD<1m3;iW9 zqx(wQ_SD}-u+nQ_uy82u)PxcV2jj@rK?2D04A(nBlkf{k(Jdu>?k<{cKxEySMSxDW zQO#o^(mlRE;q1JY1>^OdE4*>vafL?dW>y*2(9v;Z%&U3ESlO*2gZAp17xsM)Dsw4v z+47s{F~sQY;t;I69a&c9NDiLeb-CPlYDW!XLVc1o*LH+`jF8!(dOCzxFfYV+V{opDOR3nqNu>CU-8E6o|(t?TE=4&Vib6NMpW z>OOaGY78f?Imrdbtm90u1w%|x*kB^;wh+rEKCd=nb5b?xFS;KjHE|CeG{vMx>L=8J zA3GRMUKDbAy@Fh$C0Kxw3MucJ;u)w4vQ9K7St}h^hDP> zYgu_)F@llW(-N$u)>>%#LN_fa2d9wJD^V!fXsIUB_;yQg$Ap_GY%S%kVi2*Dpf_L! zH$CjHY{alz3$*HwsI7}sL&B3(??w;`YJqGcl**DEj>$Q=J2ZGSUskb>wa75O?>^Rc zwXC-iQxk84!-+4K$?X8xKj{@n2rjk3dbmy zY+{NmBgsFNC@3|7D7@mcP0Q2RlbzF}j@KLFT6!WcW`zJ+LS1?1PKPBmj3s@;^7!>S zl3&)^dXiqDxozMZbEt6WL%O;>xt9?!v?Wm|?t}x>0Zf$>LaxGF#_|TmS+H%^3l7QK z{d0~uZcSwPHGSA5B>+~VFIx zJN9(UlfOapS;hcH?qoxg(}-oJ%g>d7BMjZ%X`CFB8PNz3B=$OUz^2&yn9ezCX%XFVU)}U8 zcVDURpP|9KsIPBf+>^Gg@`tL9I>(mAVAI{Wg-?!f>#WjT4KC(13A}-_3>wAXkP<+S^hhzx)oKNxV^CEUvQZg240X zZm^x&9j5+D@sH+9nE#~Xs^^|O_V?*cEN$mYhJFit`68>jC3U>3yfdBlq^9?V2Lc)* z0vUv~eKS~_nE>!#kDnjXDA~u-ZQ0_rFj&WMQirQ!BB_*$!>{{Z2GV41V}VT%YfSQ6 ztV}+=>%Bj9K6C%;9t%gH(dOpIKhyuywe)`%R{!f9|Ie4wPL=I{NFH9#+P!%_NeH2t z4lDf$Z9e+M<+TgodkvURd2@54czCftqK9PgmGyS)63kev;jtkgp!k9F@c!m)m%f`n zfGLN5ET?Ew1S6_E=79Am$#QK>S#S@yyjq=L6)piQ3@;oeP%8qTDIIdGmOS`D5J(SV zM$9x0B78>1^Yj~M`@}4U&kPQ%sn9F@zBpVhFk#Vt`RYemb@xw#9ef6m&#}6RVu?+D zOQ%Mw`W>=fO?%`p2ljsYlOEq~gC6d_eKfl`5WILEw#Dc#&}r=W>m;e#ocknR1IG`; zw*SSSyDL*u+WVP%WAk->_2p>(z--Pvaz29pH(=ro&L}_5HQ;%H@8>Ne$z?f|pI3(A zb#^|=G7dhP4;kd$-Z&MnR6HNW@x?X9hs1dQ4cYuzCW||1+^=G*A}wV{x-7-?7iF z7p{`nc8&0goUNW9VgbTEt;|41e8z8D;Aq&SJD~UQ^id$mtAd^i8Q3OfBB5 zi{%;2`&0f%FW!s3IwX<8Je}^OesjDIxK|IIf18K^{GmW)R`Gb%>D&X=1oT&G{e?~% z4r2Ht2TTNg9>-}NSgb3Yluj%)^=%91m5=SM&#_0R`sf=Ff$H!>LUoE>IIt5c9O5uf zq(X5p5{MsH#fQJIytZQHhO+qP|IrES}`Z5t=&TBq%{=6A8?+2>;Xf=S()`M?W@ zB=kzov5hOgfU@bsPzGASS=&nK%()taGJ3}>>yj=YEv#K^xAY>@tRO!w*mUO=Ivk+B zJqWXCEE$2+Z}cim19+vXORbB_1TUeOW>Tw_?*n>fG!-*<85yvq@Nq|JuPE{7^>qbA zGWe>G1!pI4aS9UpFHevis9{i`(b8Q)I=}udfJa6QBzW-EKvX;KVKipR#2PhyToE!T z>Z+{p8RN{Oq&ex5(^t@e1vahRAvSPq)kRn2H}a4=DIu2DqqI!-7=tOVKFgNKm*qwe zOCV2fQd-C@mf~0+7erh~A6hZ$mq(J~O0yVRQ821@4^pKX83n7Pl%l3LaS5fU94$dS zyAm)m>E(P5f)rSL#yU?J>E>*-RleY*$+v8Q|EBp{0hjzSpx_YTSM%_xJ$r2wq0bQz zM_zelKV*G(8tXpAh_j=-blPLnETJ{?lzbwD*u--ddqUXlb-Q96$Z<0Xd-rQl`gz^Y z+D!lH%=#hdeTE8VFYjvm3i+8tQ)K>SPpIO_P6xp1oNyg;M5~c1!7|9J^BA?xBe(P* z-a91lmrfkYpa4`Opq@koaylXvv!Z!~HgOjsPd=E_+3g3Z$BQ5L{^D&7#((NNdpb-MO7Q*_;ks}IwUTaQIeaq2k}bv z!OPKDBHF;aQ?7p;&d`}0m45@UfNLCc3ha_!5fflX@t@x!aL0Dop(>BkBNRv};`=L( zX{npp3@yo~IpD*-e*Ik`@iejpCMWtq6p*O(Z@m2!N?kJ20UCRy(k7LfN#g)fgS^Ps z?bCzUdUi9WtBRmx0akXJfkgbA=oM30!me`rzNfB9O!i`P<}PGh`O@i4n;!(s$#IpO z(~0)GUWa0zGRL`Pl3Xkecm7>TkR^|ODd?aNmGzZSojFUy0-=bgMFp-^upzM=bpmA9 zp?#{a2iSw7H!SLcxB3E2*(=8goe}LXp#Pr3bOLt{Lf?_6)R=Y#|s~P z{Z3KrTFNiAur((?LsY7(KxcJo71o|$$mi036{slw?ZKi<+R1kOyq}g5MDWqR!bnn4 zo{mo~y1CG>aayxR*%x zI9)FqJP7`11^KPe5u}LSb(meco)hLIp+^-y`xm6Xk0F!Xem?C*8}-Vwm0zurYwayr z&chPIInFEdE4mK+kj0PtQQ3@e%?OKuOdn|Z!vXQY{j%#|$|=S6Wc|Tm+Ob*s&7$-8 zvRa3m#9Sau#}9%?_{^Y@wE=Ngjx}C<9?77MHQxf#uUnxH?K}sfA8Uo6QMrA5pcz)s z;;%`NRugatX+Zq~iICiR|CLE*F8|&8=BOn2MnuNn5K4o>f(?6d|@pqe4kfocd1N|eaZyOi#Jv+`uZ zI4b0ii9+!eN+m|$L@-8x#zNaafr_*U4vmBmK@vv_)Mjv3ri5ubwkNnPRQp3|vXBGM zLdZy8V=sV5l!8$av#*Z_8%i{gf`HsVYBhD@x}S#S18Bga`QcOpiwaQ$UllV~Ca&qC zw1kCZm*-b|j=+fya3Te>3FGaKrTwZ1(cf+K=YGaq+k=cxn2Bx1eEE0~rxZKSI;#Gb z{L#!8#iPB$z6Fw6@r11O%)nOdF|T;SR)x2{c~t_gJFoD>X`#LDc?qKI)5IIyaCYP92DV<_`5p4#TlbYBV0WWxWBi<^ z@9(tZ#xu9-gRP;ounxODClAgK!w+XiR~w^68y8Ao>@5Hq8(Y9?T|Ods~9&`0~_s3bhUa>Pu9b>g(g$Co5nr zEJ=lqX!$wJh2;dyU|`%#*h-1~H93$ZS@MTeO@fx~qy6&o9n|>g-8(spvyzn5m@BpZBJ#wv#+2cb4_D84y>S;!z#X{ERaGKpYHTwKZ$Swc7gyIZ0> zeYbQC9#${6K&gz&tG#I9uc=jq?BcD4P|?{R#A4EvlhP&D+A-G49XRSVOEv|(iQfu(ep%s(QK1oeO1Ig^$WDGg66LX86{g& zSJ_MtFPEgu-`~C%UtB~LafhVpY7MVRwbICIxk|FYpPKtI1b9vtyE0VMhb!VF z%FBafo0!kUvBCMO1r(sEg`=lCK-Io2&*-ixfo?B)T?`#ZnZXXYJdV zA&TXBZ9icuce7NnH!597P$O#trXq}bA_iCY5DMb2LRUj)XZVUCPOcCVhxbL6qZD;m z_c}^JB&^8knN71HJIFGI3;Y#{4+0*lB@vKGeMR;vW0oWCD8S_8f^3uW6M$`!S%#)K zn6J@mj)}sq#8TmCG3OggmT@LTti4Cz^oYvFTZ7@QGccs?3~=Z;z_VMhs42bHMNO9( z9_pyN8kDA$KU*}Dv~d>{LNg~4kW8Kbp-GlhdKeK`ER=wbFj)+Vm(0B=-rIWLI}&r) z-9ai6Nqfa`TXuOsd+hAW)a%>5&OSByW`zK(W`7{6kvG@ z(%7r8i`SI>osK;Xpg8D{(@L=&uE10cACipid0%0wy8I^mzZmCJYqI#MG0qs z9H`ee26%^^0FpioVHyc~HQ<2rH6SN02M#XVqd{Cpe2j7K)E*NPGu62=DR!D)vG`%| zEn2!pmAAVI-R-jk&mBW3>B<>HcbVs4^MMiD0K3PApHsl+!~All)0(~9?f6;E!t!NG zkG>7NsdxTsYZ%xD34nn}@(#RUUUqIF3Su}BSWIQ>T~GYzwr`p=)%{K-wN}?Jt$w1e zKC2D6o^zMmXX>U4k`3w#=_2ALHt40d*PKU-_}l=o*C_q6r110BfL?~hl$0-bzHpn>wx?=YnqM8?Cdg~1d5HXHox$=>T&oj%psfRPDZEbVR@A28YcKY78Pvfagwi-< zo*>r!qP6bgY_GZuq*`5Wq8r;J?w;5;|0BLW+n*Q7iW#wEq)2DB`Ja*`s;NM>&7N_u ziEKM?`UOkEpv4!w3kTO~taM%{$2s&orsAW%H6>n{pnUwWap}QA%Y;&K(^|XUaQZFe zsYX#XRGp@>q+3enva65SA%wY!jWGGzrNBYj;v9Bz((>cwvn#`Cd+$b&itE|}f{dGn z=uFzqE%2pDU#RZd~GVSXV z2eGHBaEQ40cnX2!!oANVl)&R_xeZbwcdG%y5aodO+&;~W<^zCq@H$OJ;QRm&Tp8^| z5+cqCafKGuoq@RVTLDY$41O%BBc3c+E&n#tfp!^1^d7#ucy;r1K6v7J@po!NfD39O zy4k7&i><54aDaIa1dtbEzAH5Iq^eEwLZ$1>>?3kRQ7*Q}ed@K+oor87msFMNme&_Z zCYlqPl80B79I_0mR^tf+bgE-9=;3LBl+yoN5L^*?&P6`F=24epi|!mj1qOaL~XN%L;Nx(nzjGOf+@|pe?ID|`>`Ye#`sXz zB1Ql5k90RkVh?LsXE`*osX5s$-RLb-t8c)sKyReve2wy{ma-JmON_(Gy~W&1z0M&EElq{l%&l%^@OBAZ0sAhJOBdpgDaG&Y zgpcRq=cR!yp7d+TqovAqj*RWt;dc5|!JURLMA2i?kOch9C;r@t7^e<*_Bp!137FgR^LhqR+q(_X$6buSW6fYs#Stiiyrx z#jdgBL5HsF_>PFV@8Q9D@-?j;u=u1@{?)?X#vpmYh_=7-t$0=$DGdpQShq!py$|&h zy#b;eML^vgo^_k>AJ8mKh<}#!{kd#>LbG6gX_2%y5<S6OM-nSKq;~i4Eb+7;qJXZaIk~8M3xqaUMZG4cU+Q6syVMP1yCP;Rc2&AC#)f zAYnAZG~HFR=sQU0mDlR-M7}YCt9thBymNi{0*eGAHdM9~nCj#*D}Q6+SKG5Q%T8D8 zzQp-HjlFvM30iuZm64axubQIrvzB8aErTz+RWegL9qA0CYSowq zYtm-l_0EHvqs4&6#b3|`z7Uyu>Qh{VBK2GEVLR}JE>z<=*Ez_akY)EO28Ol#gW;sD zjYAL3=(-HS(Zwsuk@)=B4$W?jhtqkdJ9K7%(F41#Y89uFy*%6~=t+)Bu{Ay7f-0hO z{;Uc&QC+7CW_4j+xsn=Q>G$}41m)Pfun9=f`)td(aAQX8+Fztb;we&zeoalG!FSmg zOq}sPJyTS2g;xiXNVafzM_>636ozRAu(n4sB===ienyC70#2#j*FBR;vv1G8ucs#!)!D9oLt~_ zkE2za=kC-d3p2_y>Y>5TX*7 zw`TdtlXtI8ZEs6xCsk@*&%{XD#FdwYi&;;p3~p79ezjJECee^5i=KaDRgfNCk`6AM zw9Gsp2>n-i?4;D)lLv~x&6L*^r*;f=Hl4y2oz)qw=%vQn*P7K^GOp@_m(aXtRENI*z2qOdTe6e>5%?|t#H;@ts~n8}3)J`nXZfe>TS3d>hhp_FIy5$^ zb8S&!jI@TRVG6qDa4zG66x;USLZDaajlX-rvESKA2P^ibVvmk^?GE(}1^D4R2N70} z2aekC1OA4$AXVn%mG=N>Qw<~~EKGU+Yow06AbpLE+4!{>mw^JR=3zto=vT9DRxp}@ z$9gl|43htXST!fn%B&s4p2l;a-g+iY2)qgC;)ojmK&*aDZ%XgxN!Ko&cZ=Pq8mMEQ ztWJg8w;H1Ti+`(4d&@i_|A7h$b}XKi+GSUhP8G8)W-!j?^K?SnE*$0T(%7h)8$27f zaUViQT}6` zl+xUokeVz>u=uC`dv)+Bbwlqd=B_H7GHlL;xHG*fEhcg$zdCS$8t?`iI10*BM}irX zxb`p9pFtKI)Y=D^%piGNz9> zBoT^YI`n?sOUpqyg_ELrrF-X)fs-PpS6$#rYrLTZYKc;=rd!X{5wH>QIER|13xF`G zS7h8Xk9}yifv7VH)J_~3_5D+%25LqyPLQ(G1|-Ni;gVZ`((lG7e5hUS>*ej91tYb% zfZ2z_A^;3$f_FC$9=xW~f?2XFEWcg9v6F+ZS7O$ScVw)}@%_@0`A$A35SkPp2RG{l zj)M26_x-mQaZ3vUT=I|@m8}8`@{e2fRrmg{inXw+6o9{SUn6@(xA0N^E^G&tcV$!Q z=P_Sn{{X6FlkE)uhW+)6iShqS4dw9DmHHRx{(rilc4}BTtTQA27^DNVJ3t(+*hIIH1dRE&lb@%oFzhIByvNXiwtEWuEyB+k6clt{EUo` zAkBp+@i;(BzYQfmsCmzCCoZ`aPDJDZUm<)}&HA)U?&5o<|WDKpAUIkT|kE=e2{M+vPZ#VuN52|lvX@kq*FDn=%w`xGhzZ`n-{ z0PE2rAD)&N!5n}rB>RWE!&~K93)U7O3kQITT!_gn2wKA$Y(ATY5w2K~>JU)mi)^CT z$kfXgf3@e((^ZpE#&j-^;Le>Q1w9Zv9<)ky2usl~k4_8}7EE-T`>^HHG0??vPhaK1 zM3dzcsN__~X@V~&GG z3X7tb=X;sy92fGrev$&h>G*t$(cXS`vXU9Rk7zaW=fs!9P!|nD^dHm^V=G@pT2g0L)k zZioy{k905}#k0sNhWV%W02OEkv^0RwOuwAy`_vmSb#D_7ky*cvn3ZKxm zzU9rmVNqkRNj(g6nroGrXm#c+2yJWArveW&jMenRHqWAQpB0RGd_1-)#UyzyFf(%x zmD;o(z*-cqX4cpDFJp_gYM@4;y|SGquw}k4@QFsN*nDU84SY})32TD*nrxRC}}ij$9Y9yLvC#m zhX632Qvnc=6vZ!)=E4wxHxQukD=F8pZLM+G%E+@Z1{%}52R}M2!rv;mD(K7R?qO}hfMGa9+CWD`}2EnmDz21T!R>=J7 zEx|zdl!lnSc2EZ3;9Pf-_Is)&Zn&8`>3`t@hccTayU}T8Sa!S{r4>UJUA#Kw{U0gG zF5~n~)?2K_HROTqQY9<`cta1+3(*!2j2P7KFcAQ5L?h!7$whjE#W2@O&`A zPVrTf1iCpdS8M>#9tkB`jPOE896R0R<3mIvCAB94h`6IS^b?CFjGmb{At9bj3|4$Z zady3d7Ztg5d*>_KYyNhKN^?L)MSaBW&e74^&~J`qu?|AYJfiqOK=GA@1C4YQ#21J> zm)PHYfk^_){&9*@ASh0c*Q({ zFa$&k{cl173}}~VVVc#?)K4I!Z+n^2UL%b^rO~2#X8oi+INw2UOd4>eDRn=J<;??h z=N3$PxKwT~T$L)--vBThjsQvn3=&Fk*);+P2RFhp;^xi*>ErlgW+q=tV0f@BBIrlZ zJxQo~F>q0oS;wHWM7C%!%apg7 z_J(D0YkPC=OSH{G(apamS?DyL+-tyI32%LcUD%!vmH9a%i%70Z_mhi%tbne(!Fp{N zsq!wFbD1mo==Mr|5A*@B>;ay3vvTYtp(3|3-}_j2-D)OZe6*Z3GbZtiz3;dm!{hEm z+*|ZH3oFN)8KrSr*|9w&LA$YiXym@DX%sx$?#-@365Cj>m$xh9FGK%VwQRDreyjw=BJ@$rpXqx z+-51pS*#%U0g!Bcit|;<$W+KVLKrrW8@F+hnO0sYDWufr*M!*e84kfqauR7oA%GJm z&0u>kk^K4OL=>?bT)g*u9(oE{@MjSe@|k%QuW}W6oyedz+}ic7K4;RO3z4^~M6X@r zqpyTxoKiP-?~d;2=#2EOW-rrmG&o>aC4|IoK}wFP*MHdi=-J%_12{MxgUe>IeRpC# zy+`L%x&patRf3u8Ac1So0Cy6EoavQaWL4k4(BuI>EwF|{d`|O0U3b0V)7+vBnM@OK zr>8^l^B0?W7IN{*gpB}Z;h6dRcPzEiT8%P?5iZP-`0kwBNJXsHTWD475mT4MZ=VhB zCVe=IekuvI)lI+k>jy8CDTBpylZbeXr5}rYJm3%sj1q8NkF zsDqF_t!_rf$(wHk^fyhlfnoi(=|%(@gW}v6nDoL7Dl}z2NJ!K+*zFDWMyo+;$83Ci z3nhXmGQkc!p7kFmev7A4PfEzOV6}if^FWhfM0l=eD5*QqS8KvWb8HpA5R{!PMRy#Y zd_!uPv_og)P)zOl+af%O(26fH6|&g<1B_SQ<_Gs`qd|V-_?|On@bRT`YS^2I)2R-2O%e;j^!MHK0+)ki=%f15?$aiIJegIt{d6up1U{IP39eV)r=w}+_ zP6^MAfP5Su$74XRL9iZUT)-!qN&||NhEjzOQgd^jvg3`Wf~P&gM);teAOrY-_C%0_ z07RbFG0k?B8JsI*o3isTX;>&a6@?No74|CSy2GQ|Qk~_6n1-0;4O+@Z=EG=ht6tl@ zaXd~W4k%B~mj(-{AT)ZPCcrIsxtka~AGabFwz4AKm**5685m~-;bqgY^GL%aYI9~v zbl~+3;hX$dBw)Y7Z3CMN=Ec#tjuHIaW0gZF?Wy4&jO$JUSqwh~i&Mhb@$ab+?mS{ zLrU#~@`{$WJ5FskR@CaWh!@;3BW3ELCl@CPB9fYr+UlN)w-^nIr369=UI$R+yuj% z86QHSX{;0Lbk9c;kZ58)GjNXqb!0bXmlW9SoFeCQFKgvGMVNZ_&$&ZBJ<+JHZ{yV$ zsz~nGmC=ApfD8WNMcmp;da$F@@V|WxlO*i<^JNm7d8{j8B!|DzUtt)5JfWKP2X^s3 z;OGchYkYP*#k9XBazd#Vey_@*`=HZ6Vyxg^Y$x zmN{kfEK9!dc+-aSLNk8YRNYa!Y%B4CviHk+KVI#%N>8zt_T#Hok7$QCuN600>ZN#U z1{m;j)^`7Pev?+kXb5ciB4RD%bRyZCK+zctzjsa*%s$RV;$+}IjDIxa7+$0c^Vvei zw}ht4###sneD_&(ASRX*X$XoY@BtaqgA1~~XJaKoVSswpPE(E4p$?zljntk{o78Di z#=U_es0*N=9@LLT&=U8&Z4GUKgcF_rRZw)}g`RsvBvCLr6n}mDOhM~oX zS?y9&Ow+?(!&GjRijJ|dMxJtuu>yJ?cvJStRApkSnnva44u#mP4aAt?4bdemW9s=l z88AP;gu?|gKdr)1JZ$D`+#mO>$Gtf4+ba`s7eea!NP*O!d^T9s0IluYDO@3xWBkdN zQ4J!PsddSMuX4y2Iv`{nXQ*z+dbk#H#lZCS^W%_7zIg?CL#dE4xedM`B^BIiKxs=l z){AI1h!IS`2CBJ;0&Z-wY71Ms>W^WBM?k>X`V3Z!Yqfd8`cq3vq26MU)0N7xF7LX6 z5VXX_y8|Uk++V=RuKLcUd*xJ>B-Zf?#gQgeqlGlOi zKi4F4!Ze0Ge`Hy0KUaa`KMpb+^-Og1EY0-(op0|Y_b)>T_|9_*P)K6G0qf@zYN#qC z^#C#elax*fCERsD75ceUOS0Ez9Ac^TC)upRwC5wPP6RW^9O>O56`Qu~T-m~RyjYn9 zjvuDC%AZ)4X(Tq14Wd1KhKhgrL1+sb z=|o-TG66A+>3=F#Bfb4VuT7nQg%5<(XPZK+{g)vGTRHKR%PEJ{)>wvUR>VjtOGWp% z3)FZWpF}a!2}4VD1u+MLO0m%~74mD7YvTF`-;q+<@||6M+@XTpr}kf!y>Nt~y=Qz} zqeogMaGpnk@Xo5fh%E&7&Gi$oxq_@O51)8X4?Vya>@4r;YWe?3Lan7sZB_}lG` z9L8Q{r&nFYojbBP1vAvr(Yk$X*eTF9P_c528}5A9!8Kxu{$8PuNd~)C>!B$^y{;EU z?mQE`4u@|mnyF_Aw`_YCYtJ|yDK@|-7yb*s=Ab4&8lPj&7W1{0FXpd*w0iZvnVW`x zPSfT;xRd_3y6gX(rjDMIqs{+2q|&qhx4v4EyjH}I5AVOazNE+{L{D0H4n?u!MVdWS zhuGrphD&2Z%C};|>bp>fUmnEkqeXbgbpG;76bt!8jZzt1UfysS7nNtgvV39y+<9v zM~L<5x06hs<&IGAHjSY1g~3-RCjZ?=>PQIawR}m8bPD^+uaa+KP!_E{TP(HQ`HfV- zn6S7ay>mj!T3a*#OR-3flZw$Hf}0)H!pD-Fnl z-rnzyl9Zr9{jDuy7;vlCxX(h{lG$%WmYNd+;Z8xOlHT;DJG5kBTJo)?%WY!VsIi^W z9%6&m*kZmHlU-|W7H`+_tVAy%qTz^|D2WKV#?U+YT6G+zx1r+pg(VZ24`9W5FrAM3 z7W`1U>^@4T;$%T?*{irMX0I!sC(;s<5KqwZKvcGmF2^j3;J6e>&;oyj+Mo7ar%bE< zw0Y!cWN#)C+3t$^Pb-*Md8Zzrp9|0NANZ92`)~3;b77Lgzqsw_p3l`Uh2lt(u?-%D z^F%;oQHda^Ay#k+lm^)PWQ`2#2o>aC@7REfx%q$H>b;KJuc!F*z)iLVm#2lT#let{ zTwft<_rnD7D zVkL1|kj#fVpVJ=@q}PEuHp&ml;7=zOyamw~7v!Sd1ALqylD>~IC>9AZIPRG(RG)f) zF?F)9&$sUwPgydHyy@DZxW|P|Q{cK-3F3M5{$o&(NgJ-T>n*ho{c#a&uUwy0S(wlV zYNX}!O42BI=kmK$UuN$cT$v>pO8ph1R59pEwY0NmDKetU%$2VcW?f~&7A$S0!HVHN zS89s6C4K_(oNriu3-rM^rSei%?HNI}osD(f-jd-arpPJLRiO5H9>>e~tmSI^TFLnt z{IVy7d;ybsBR@j94LARyF?&mHbID%-&-?QFV#e+)k4&0$)Gm1*k5yvdQJ7SX8dXhD zlvAd92ksZU#F0T}EYjmIo>tFO%V=R0d(O=j2+H}Fb^3g=FU-d^9%&awyL{en%k18w zS|aHJR}HJ+%h8?)|9me_+mL%+91eetxfbvR}WL|8rh3va+?* zb2QR%{9&W(Sm_zq+x&Zqxm4G(Srdo%`Wck3i=u=fie9b%Ef{apvA?icr&4 zGO=5aoA07-jg&BmC<#aTUb)V-V*tAEd&K7zz9-+SHGrCH#d zED8#yP9ZLLkYf?5-CotgM zXYCv>Z8_ElRmjc_xpobhv8c#_oWs@^{H3VY9XFXYc90@%(yG}s%&x&PX_5uTVlOP+ zc%E0p)feaCarbL?Acr>ZC9(bkDl_C0Nl+i>hKw-B-#}yvB&=gxZabRu15x;3&e>m2 zlv?=r9$e;E(s}C=0H#B4PUxRzb0xtUm%vd7ToV80+mXV*rD z1(M)VsGe-h4nu8Nw_*kMfp_zRy{{u6SZ1yb&<>qsXM~jI@BUF&(^kbE%tcTKTSM8- z6k^YCY={+;v9u_I%I;J{@1?cV!CSU?910$BZSKf&rHRGp*p|mNI8I0LFMulAgGTnF z1D(I?h4H!Sf09as5gmHmHhs^(bLoZ|Iz6SiaP%p_6zESVpBkz7Y$i=~@4l`)F;hmI z{H4CsS5xkPd7H1#(lQUe_$$=jsic7*bIMlH6;?r5$>Q>e>clnSbTnfclhNyeSxz5L z)!cSKc4G^R?1?uGB%r_Ps{P|(jp)inDXe=QIaFfnl-wDV*vR(G0G;vvwFSKazoacX zT4A*gCA12ezln&tAIu!lofz5kkN?(g!Xuvr)^-!F_%+2adFn^kIR|`n212s3~P#(rCintU(Sg%H1(nP6zeN$mb ztTr~&#uK@Gb7f!dLaB<$x5A*?07cSth&t5*`8y=4Hi=T3j<3Tc*78Ohzlc|RmZtj1 z+)nnJAgwl$O32f0=xmf%38O!`&YJsi5~O5q*hMH#ET%MD=2KjoJt$~kG-FP+d%VRx z3pz&Iak^};EOyBtMrwMz7!CZN@8vnLbHi!d5^Y=|fUd6fQ&n#`_X1p>(q@UmKdJ zHUOEgFZ>11Pi{|!YAysNymcRI6dyIpqejp=GBQ3oYnYn?LH#d>5ux;X%gK6TwHsho z>ZvIn&1{(k6(K=B{uy6cCR4_Uq_M+?8{0;8DQmmNFw*1@l=Y9p4{$XRpo5l=m!oa4 zBuFqcgmGjYTV=^nyp(G=-h^JL>>x1=I(uyMci6}7R(<(N0rJ&M6DYc{`;S7IF^0kL z$Ui7>Kx2f4GQWin>JB-JFs5^cL7H&c!2v-0yhe5zyqebM=UNT zG{||S%e0R;>_xv9(iXjrRInU^uYevzN91Vt? z!)gfsdI|iiu$_gKi?56-- zP*)h1+W3Y*Mdxwwclo(MQoiWmuPm^~(W!}g6X6+!PQblZ!xT0sHmRx;di)f2DNlX) zvXgj6guMvgi=F@o35P~l-EQZ&tG5$StF4TSIJxNyalM>kv^$&_e32$9!!Sd4;)P!W zur7+4p-I?NMz@@=D(N;Eju;X2VW^2D(>lBI_gx@cRuzSgp9T^i0aZDKJVC1>r1UhYUm{mEgoOwKB~&0zS9mNCTnx{KJQ{+z|=f+teel2?*7dx5f4+L zd0AH6UR+L-bZNS{Ap#Ek(Voa0@*w^Ls?JBGwDho=@|g zI|yas{c!wNO)k((4iJLZZbQ_*xRBeDATVJoI7ubY+SW@t< zwV-_#;DT+c8S&=?Y}`w%ecih-$vkPYfq%kOYfbOiu(%1q)GA5CXaVkIFaG9=1CwEh zjv7G1*ZGHF(qi%}kwY+p2^C#0psNe_R;;#sZ^#bnj zKRV5C+f-OH&G3Ei^!uB(7?_0C?4&ceA_|g>$%)OiR;RiC4t8(|Q%p62y!m*;&RPn- z-iN2Yojck#Qp1Tlm|ls#mnKM5{9LIm^X^aDn^(t_9)knT3L3(*IBG&$$VFdlfB#&$E~^L$h)L4ln0b~`7+ zp)lBihGQy20mWr9_>m7jI7!98{*&J)A6`#ic3&w%ewed8Rv8@XTg7%m+fAnAns!lr zaKQJ&b-wQwXE@n z#OP5g`B^kD(2E!q&VIxDfL);*co!9&J5PM?&8=B*tF*d7{n66z$m!8~6yPP&1vhI- z3k?)j^5zB8gC;%u);z{92yEtjIv-4I89*b(zaY5_xx}9NK#5lTUst0&^W0o^%j%1kwC(+j#2YZ3;Y9+$#HK6LSPtRFL*N{8SBz;e_E`o*fYI(>8o zs<5kZ2#|J0z{b46iy8NCUF&;w<@EWQ|zqmOsiYYtk^h{W){BDY~LTU^loSMBZC!a1cH$A{z z8gRaV*gY%i8NtCUh+}%78b#8=2Pf>)s@ya79Bmw^qLLi1vGoDEMRdo5JH^{cM)<43 z>*mw<4lRGKc)4gEwktt{n@+w0SodvjiNI;P0VjSVhc|BBZi!lBW?|u9 znHkPM8-~r}0G(wK;lZUeP=I@q!;OAFT&R%UqOv9Vr+eBx0PS~Ae{eLqz?r}^zog`d zJpZ-VF!7MI^(_RwHS{i^Ct^G3&6YmI0^JZl7gL-Odd7i&nNcL}+2g5rU^{+8nHn$_ zI2^BUo@!pHb9@~d=-)B3v)S2k^HgA#jM@sC{9UE?h9v#W)t8#zOV{0SSkfIG`>kx% z2muq8CN$v8&RUp63H>VA;^>&Kx4pZ7u>51t=G~zgCp`701yD@R%sK7_Rg=9rEg~q9Vu6gkM&&V5&A zOOjkOMXpRHFv6X$-f%U$z{ed}?H>~DLT&(5wzFi4ld;gE{u({_0uP6#KUDVDlh8#h z@XsPczax5$uCVEL1g%;)X@yN|Z_HoiU){^zt7szDfQk@U#g3B|+Ky^%h1gl;&J`8#Q%L*1Z~k^U6V}|4-OEP;+|^qc_ZAP( zjWTP}ISp1lIa<%%u7LXH(XR;(=(Ppn$C%`#1?3f`ynWuC^^&;-3fu)vVcwcWdwsT; z66A4t>_NX$*ql>sRHOKbqEkp8lI}Ex)vV_;=i$m|sfa1z8JqKh9#O3+j5(a6SKiK{ffx!m1CJ|^$Xn5pim*Qx@*%)_X9qekj2IYZ?Ww=_sATC zb=>9sf?_dF@L5`z;rBJc$`@L6FLZ^LqiOBOQAI0!dJiD`^yeHIigE1S5Ni*12b!bw z($8m?B&QV~S0-+1d8ZX8btfPcUW5neFBNSB+f4G)XU)?MT*U8c_=4))2aF#|MXari zGQ~7?3WSGH8!`J}+L(B#`$@BWZ&s zw^#;iQIUfmyKmKgPoz&aav&+L8=Nxw;sQ7%dn4( z+?;;gH2N?o4rZ#TX)jN=II1qH3US)>sTLvyArTX#aLccd! z0n!*s@TL;<#x1qf!?F%SW;VngG*QLE#3-_Og&l70q8h__4xL=`^STyx&Vwe_o_hCZ z;zh5}44sj-e}oXfM1IC_@|- zN($j8s=uF$SA_Jfn%CjHcXuFT8WviL1S@fd;?Mmt=2(}$F_8wsZ_$x>oHQ@XMp4OU zU~^H|fm5x|n{%5y{DmJjvG0v9Ll-xU&tPTD3+{u1G)_Q$8(8(L=r}gjpF60Qn#QBS z2lx3?uQ&;Xy?b|g=e>%uP@~_((#zY5VnY<0tC~&;3WXi2Yd&X31-&FNGWnJNAI{!^ zJG5@=){Jf2cCusJwr$(CZQDDxtsUF8x#Q&K+`6sWc~4bq->LcwYt1?4Kp#(!R~h8N z?pN%iyxXq8V!dc_eF5Z^>^h`aa1$-kBYx%I=|_w_Z@R!mnA(G4o+0EC6PF2RHy$A)%us=M}D_jTSmSf?YyH%ewAVN(X4E>QJ0sNktV3!Qq2 zTl3d5AXUvZi$Kc8+Fd%k*WZ%=2DX5}peI>tapA8&B>Q6{i8~CW;lcG9AkY4^qs~Ic zAAKoH@&!C09cY-rO`@SxV3W{0%lluDqIHCWWG&WKiR;Sr_1+w$C2sj4of#X@l3APU z$k%9Fns{7`lRWAhT-HhL_Swtx`VH4<72RTGS8Fd)5456>F?--5PG>z3F*VimncVZKRYJSG zqCDWHBhO+Z2^o8P2B+t*ep@#p?VSxPy`iu@-}tM&|6D)V4SYk8`e6&NvI79n{uiC# z|Mv#)lGgvVDRrVIjavZ}!LRic5u@rDEm4h>WLS3Av*mGFi2 z7Z{8t-a3gBUET@KOtus6-1)P>anVaZwP=(H2nv^Ds-8cNm=t~(EfKr0LGYXsPCsUN zH|7w5rl9@Ry8#G{AKq^pn0^e7S!e_F4}W&y9&p}g-Y3n7tQJ7RI^0n`(3a=OF3@!1 zG;{OFN^DDd&j|k?UNHgymt{AxmZ$;(+}r1q=ayIDwkNOdBb(*2*#)x7Ra1GW1K)>7 zdw_k#R6cqEN1!`EP0SsszHAw zOGzzutymcG@I({zhK2)Z-~6+=1+%`624NjS7_;jA zsN=aHnu$GZrh4Cw<5uEh7U;J)D$>;3%CcN4CieGR^2sodR+G|8vUo96`B@?r(kJ0rDOgR$`%pa~ZBkz@`iUgRRsdD@r1vGW zW0A?fh=5YxO!F7XBc39==gF5%HKAi%D!8mjn+Z)TPDb$-i?G{KYDEwr{NSehO zSkdIdl)r@IsTs`Rxu+vqtLBF;oL~CW8kJ5~sr$7ZfOk5;DXT zIwoTWmSbJYGFy`ju-R*HLpdo|JC;(ZSyrbNL6M4eUZ}-6!!<&Fm4e+^cF(~WTB|vs zcu90??a>w`uIPLHQXXC;^Aurjsj?;>>~(&XRbn53QnW6L20ou|TO+etYkxEk3krBc zY8w-nWBmpH+oPQPSR^-0#W!OGRPEiL2@gd?B@BpwEwKcGyf+T|Jj-=PSQs>2%j83} zA1?(%L~uR%9?keIKWjb560_7gadH#I7sUtAPt?#0k~A;=uTrcC9CCOO>+2w0uq~BS zLco(4XYyF+1yOI1HOyKhUD%$G*Qk0KbTPaQ#2om{iT^1<|P3QV|1>*x=_c=yqnk!6R<5Ug0cCVZ;)b5jOqR>a+{NF-Fr z5vIkrr6ti;eU0TXjtlKS4Q#;BJx8M(IL3^VyAG6r99B7Y8G*V^v{_z;tRW0pER5v% zK-^aCB5+9k5tvT;qC2H}y)6#|*YDc!)8Y$HA6<=2835C5LM>BepO-}%WuFrEye-7^ z?B)AhyDh5T$nBwFfDMQK#x{cE0%NE%Fu%saiusRCkus@BG}o|Ys#{NZy?bhpc|HL5 zD6d2@Uxc$n)(1*?W|d`i`?EKLYJB_%6z_5ClRwU)no%XP{S&t~Ylp4j;CrFBs?w_A z)LL?oFW=IAw3}-Uore2TZ0s=txn#hJr_^0=2HA^@4=huDumqeczOl+iIm`vmR1>bc zV@CPsJzPgBb{|mD8WIjsgr+h-QqJwlsC&^?G(xp<`t8W@rnd0z`3a-vZX}}Hza`g9 zSqeeTTpW68aTQ!dVs0?5HJG|Jti*2Gbh7>-TvXp=lU+G6PRK?Z(_@VhzpTxUmWMQ& zAMP!h)0@cHn+De!Lp>TZqcw=N*Y;@EB3|l|8I8*Jhv19{V<&?gFzb};^#ZF`G+yWs zOD{-pR=(4=*3(wb(Z+EQp~@hktS(vw3t{+WzRv5)c!*R;Z>vRGB2kS1LnBdt8K_3~ zi`}JDfPs?^@Gjv-ABqvVK$iWImywB=mYJ23L6DM>mz0T@5GzXv2IC=e%8m4pby!sz zA%%pO;c!yCUJW*JqL(a0QyapSZZvJIcFht2OKIxCK`SqY{_TrLxPJmLA(nng>C7b) zTkwl?aSvAsdErh|c%}zMj?`+f#Kk>079)k2f8YKrt7Aw;XQC8OV*x_ONigvEma0_2 zwzP8FV2K8`8NA55yc`GvoufO>qC~?nt4A;0I0j;lK5mXaHeeEc)D`wpIoL#R@*V!4 z&$A4*4x;1Fp!NXazY+lbYd-5_Z({Thk;v5lsk*N99M%9v>2TVof=iy*y!G>{Q zfI|iHOOiyS(O42Av%uDV2#Y9BrfV*pXc&NlNFL9dPW0T0MXxxV2cjr(iM2|wY|>(9 za<@(uN`y<{AbL(EqMidViq^Br*nh+%hlt|qsNPD<(3~KB_JMvU?j_#;kFrv$o z#t{%Skwc~Wuf#Je@wd^;wszZ_v^yYgMPP)4L|}c7ez@jUn^pf&Ii<7ff>Sp!oM=ywtUlPgLX zf8fE?RfI!}f|tg=ei{Txjzxzy3!x%W^MnBdEmd^_%$n_zT~Csm@iO?nYg1|q#z0mz zecP0P$G`%p8!46bKYf=>DVNGnGoHR;PB^V^D{96ne`;76Uz-K8!By1k;J^>Tve0)C zZEE3;A|^Y~l#OyTjG7;{5rtG}E8ZGp@#8Nf_v|nJOuKq8F-nZEG+cq5rCo|UsjA{& zM`*_D&Ify(2q@AJTmImIz`HRjmUm3OlXIu9JXIB82U9o)q%!@x4ZHJ9wjrqGP*oap`5INlS<+MN!}c%-F?KEV~`tw z37Hd*ta^^sY0tZkMsatOC>32s3vB9q+e~xU)i{Zqo~_JornZeNXS6P6l_EUAv;^#h zcg2fKA`?Y@VY(Ar@Wi9>+E5eZRG#Ub+uN3C9f(Y4(SYxTjrO9=WI#b@zfTZWxa)~`tbhB zx#{ux<9sRzMZ+uugI#C~Fvm`XkS5%zTiZ^tG>4?+_tQZz)2=blCd%6#!+t9}>M19F zW-S(DJ-WxafbEePWcQ^9R)9KrsM#bNX&UjsS z`ke;u>D$Vi^349Lm@#Bs{OJU*4Oo9R?F=gi6kFO6sa<;3b4tX@o3gvXDR|c(gYR?rY8>CXRM`p`IX54tZGdajx zO<-1wSDwEZG3zWuR}huvFnu_JsnI@J0_sV5uR2Z+^pdGu9J%^xm}riXVXVD+=gfE> zWNDr&4V&z&utd<2{M=qN~9Ux9Jy>OJ`Cdf6Tgmd9{8n|p37T!aho zHg3#DAK!fsnyPshuJXjbf&Ll8s>-*rp?_l7?N9sYzYsD0-!bgpJ4ah;3U>SK|AO$O zZ%CqMYo2Zs+lyrKTN(n zoJ6eL2wi2|UW&{bm*@*Bx4nV(99j;CJT~nmOOl>4sbL6A6QSg*LbPT}f%3*Jr9uRQ zV-Y2}gYL+SPhfgqZ#{MyX2ixpkifih5?_WifEZ?4#;qM*&-GqZn1O2ZmlFdNcKH}n zmoRahKL3cB>?~9-91M{HC58L?Zpv%m@w78Vdq&ZyHxWt%YRimBu`{iC6XyQW{>HftMQtzb$b{0H@A z;bGGC45TD@Ex0kAY|v0V=&&FVRFZ`d$&BWBFw%y@S57^7f7VL+6*H9d#n;qUX%_j& zJ(XSw3(ocCxc@{tPC+Hp&6#FSU%zo)+elF-Py(c5F!LZ3DkTZ!iwZYx(n_$jj`g+Z za*>HI8_(|pQ z*Rs-e8+AfdzLr5>jcn|8vn9$aJiIk%rFPKy+S_K8n`fLpZo14mS2tW1iqGPM$t{il{eXIDf)}wwN;Z(GHH&rDs5)E$#4ys$*+`aRf`Ps4p2F~z zCmL=^H`a~mzt});yr=OFU>S8}Q%qi}K_FA6#vruIGID$_IMa_Eeku6 zIVV{^Ef3awKeUOWdVIq=a4d ziM5nZ_O65?gwYhya^>d=a+CPux9Wd| z<1Ng!{YSXUJuA*?$3Kl^G_e28L&3Cz?Q4pI-E9-a>=& z^E&CO+F{*!>XC@}?E1U&J4Yn7e@;{0>twRjR9#&4iR%TYjqF6k+uekls}U+1D{$%5 z-zr#&XhwcM(`}w`6C-5#KOuLDNg@J5k#fCdejBqhpxMH3=*iGSi%#il ziXTq-UjR{l)nBbWV+~ujX+NB~DksL z#V1ik)Lsbbore0TW|88`XlsASUoPhXd=x0!zf{iElUsxyxrH6`Mea*y4Sx(`%H+n;yh6>Qugu6 zZkuwvsAo<`7*8%>^r9WVVI3m*vW`4_V|5qOm41xGVq$nAI%ZhH5^zFIKOA$rlqKSv zMByh+C^82s`~6UT1*vKt>%9rz6ujwiwVu^)mK6H2!8=<%_*IhJNed`hBX) zqmfExZ);rJ?WV#Ogo(EF6(+5lc^Vuw1R84JVg*|BbgdBF0-+`w8YradFrQ~262`Gl z?iSgHVAMWW8u@9_^oKahI&#G|^*qF)yeMjzadbf>ci8IxpkD|)TezLgLZp*ka<*qL z?kdze^vdbeKk?wmnQz2`Fl_3;=26d}p=n$YIXkmksV-B9>>{e-tSjK!K2`JQ>YnUd zLD!D;$T8=)E&8iq&aj#xH*GlSYE!q!i)o;`VY__f6P{2REbk~7yd>OQ-)xJ?t%R=>xgU%8e#dW6@U{F|}uzT`@G*1ETM7M z6!jp5ZxALiUhs z1HVF_g!ZMU)9(Nq*8~h3co~CPB$GQ;GT4a7MA(llJMnXY@q6OVwu`-Jg4D5$J-g5c zqAd=tpmj4E)fq;uV5AXY&pmAStO@xc32?}rM&S|bT*-5x2_LK=7|JeWq6B+-pp1m{ z0q|pm+*zfUm=Q>196GR*pjh3J?lP3{lZd0pTeA^#ggOWgvV*LR_pAW#L;}NG1VDtf ziue%4n#8>|jZ~AMc1;_C{b7x1*3R@C>SbLqhfP1vZ!x~G*}RuzDKrKw_`R*qFkYfF z=N_}oD8;;ilrmKA1-)OC$+q5%5NcI(WQYfeBY=12i3@7LzvOQHuZ#~#Cf4Fr=gB=V z?j(h0%nK+O4_QAG$7a#`h7#>de-xkd#vy%^U;|M+kGYZqL@cG3nlZi3P+G+Nn=&9k zgg%*}j530VulBHZzAt+XN{I#aigE+6&zO7JWD%r-J`{3kx2&ocgIq1_BCYXA&z?5p z436Q(xdoGg$04@0gc3d|IQ^7Aez}|JLppgN>&V0j3Lt!bsVGcPjHJAEAZ@#!^vq~w zmb1h-;)%sl>ty1g!h**6iodZzh(wL3IV=P}`@zs9O8mu;N}#qKq@VC=45`fUBo0&1 z6JOj9@d!V*$y`aKjB*>ll`$;JrB%sw)9hM6Np)(7h|W^HbrqVk7;rVT4&lQ_DhSnO zhP!>8%S@Y`Imn^(9p$&B$7fI+^M z8iLs+&ZXG_)YLdUsicB!LtKCb1@P<0&s(P~AJbrGswRs*uvc(*t2V5Njr2}od;rEj z1p38BS$7{RmAl%^c&QskJKOst*dPW zC$Zz0Q<3SQ#eV6zF#`xWLZx>S=SPUCIuGDG(9dBaX?bW71XkV>#9D+ChWjN)IU`oq zEi&#rfw~#fq55fRtP>SRx(hS+d5a&2ogWVq z?F=HjFEsu*fNr^UK2DbOLtfjgv|D4dK{v@Z*Oz}*X-r0Tv$C4-svVKtGHj&}XF?=J zR{-sMPC=TW+2a|St){|&8HbFIxpl(BJG7FXOfg>b>9s%}dV$`rKqh;EPOLz}{Dp#n zLpfdWFHW#VZb@Yx)$JU(T5#_u9DX&#bEMB}=sN8w0gvLKW!Ecg!APbTu?u zcyH?tz*>+=+PH|T>mRFRaPaE>J@&(F#3n34hPi>_4MciHYpr;1A=X48{aQLWvstm|vm zEZM6&b!KSY81#7EDIcbQNxNk8#19&%Hkr{#$h!}wWhb*mK3i8Et>lr!deMRutEn$P z3VfGx*X`*%k<;mnu3}Y1pKwIj_@l|`xHqpXx+ukygRzAbQaguhe4VAeUrI-;W);cO zq?m92?fF~JZ9+1QZA`U5X%s5E>#GBv;yCteFod_Xfj-c8s4i_7B;Nc4dY&TCIAjVo zVikQ67&;N6Fa1UBK4T>GTT8(CQof;BPvf9yk0H)@g*|}9t+=rFc4{+zM4L1T^(zu% zw#UlF8d6>ZqcIY#qNNoH!3YlJy0xC=b(4c4ti~_ zL{km7B@V*ptDL^9c<4GR0$V=c^i5eEmsldFP>K8Y+G$12im%8a3=;R{vrik(X3yoD z1HJ9-tG}hzX^mzft!Am5Ep6Ouq$c#~Ds)NIMV-_>49Z(7%XLzPj#(G|sAx%L1gCrb zGt+vO=%STpSb+~oO6FFW&g_$NrXeP<3~1b)5_k@`SA=O-;qBILv$*>9Uh3~L5zMQ| zmKjWNsZTNHRWf}6h^>F((R$FY$}Yb70no}fm|yi43dRC4oGM)nARo5SzCE93&SYkK zDg;r)dDpM3D;3$gh4c>6t-?CIu9P&Oe7IWq_e}JDT(VU^u~FGDRZP_?Y->fe?y8n+ z1#3En)QoBjdvT9jN>~hELW2SPd?(u^v*VI|>!HZEJ=^O`huPh^-9bpR;z? zamf|an3jSTtfY!nvD>zL`b*%K+}82F(5h}6=DN$VwB*sB*$&oWufL}hs)>_x{!|C4 z$gDwib?keE=cHb4yWrUuYW-PckJ!Iuw8#v+4=Bk`w{16ihDd-Pi zWvq3P@wueSX=rZ9VC5DT@cRl0+oq$l-crnpfM!`}Bci)zLFqThc@(|*c5yKCLUauX z1JyG6d~^81PV^Tr2=Ng!;ldU~fGnIh^x%Sj{mmwq#w^N#sKu0#>@0Q9{ICWTMmJ60 zI;tq3YhJvg#X^Zv=es}Vw_E4C$qqY4@9~bfR+3h0%f{e=o?1Ja zHG+;7!N=!XOyL757vQw%FC$QbJDDPcIZ0y~N_oN5lDeI?2#FD$5Nx4x<0&SJlTDVhkvJbWDSvIMV-!rmj?=aBz5I#Wc?GDovZ+p z>Bo-rJzsV6eAA^zi?ZC_-Z!*-oSi&eo=sm$pK!?3;kG!+K+|y+Vvmy_Zz?c5ddQ;F z1=zt!_T}52%6}H%P{H;YBo{R-i8zxWzZM+@&$&W0y$<82MTAmB=+OoQd^E!7iqD?MqQRaIs-cdL_1O)5b&wm20&{3NQwjH zV~XIxyn8#b?Vi$+=}@@BmagtE%!32N#m6k|TTv*PSz+=5K2c*=ZqYT&x$*DGL{*(1r*g zD`*JtAU3rj*R35QcvJG(-q=7$VgnH0>#*`1z47Sv>(bFuVL(H0K_zW|Xx_0@4D`$N+Xc94SA*|gXl2Vbkv$W)(WVRrJ6kmRU_EH?|0_Y^dZCY?ZT=Q;P3A`2nwQNzo zu1AO-FE$}U!iT)TvR3no`4v;*1~O`RJA((+D-ygYwy;s*Dv&Ei{!)BKSigAUB*z-; zWw`XGC(wT`%&^I*gn?9}a6)Oh2!t-XB)smyxbCd@VmYc_P*4FQDz`67fjv@1>m1B^ z$U3miCcOO4Sc8#JS_n~?)T|D{`|I?Dhf@6*ett~AcAXs|WBNvIt6|+nU7Gft-sTo<$@%>^{V(*XeSBel7=u?pp?5(6# z1G6A84n(fMDtjqNc`QV^zn=~`7SO3n07~-Z)v)GtB`B-Eb1#c#dKb)boDpeLXkXNX`8z|s|EfY=BdJHK6?6$zHh2-wd2(xzLqTHPUWS->aW3>M!$G@K_BrNiiyEO-*}O^0IX;7n zP3Zq~W$9#Xr|+UiHz8G(ksi2f*#-qj~Ij--+JB4{U@1`^omR>k{mxMoipRSML|fvc(2f~Wb#%TPIA*Y_8i? z4v#x{#E%0DU>k!=Cv+##M``}rc^5U6Z& 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 K+ofXNnVxpJTKbGij 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�|H|C~q(uqp1aPJ5?wYv=H*0o2+b5kQZ}Q)t=4cC((Wy?O$cUbEU- z5z6Lh;+~*A+jP#bXQNXW3JzrhA{n)buOsN<^C}?DXhukS)KabHdf9gT>g&2CW2xpS zW2<_zTYKlLyKT*A=2VC5BOW|hUMmD*k6D%pS-`z9VvNB1k3@wUD5uz@reXEh3O?DL zYwx_<#)d3bkc+b_H~5~HFkXr1V1%$sCeDyaS%?6+i;yYWNO#FC@dQDY7Q=~Nhir@! z+Kd#NSl^#Dz^9y`Cx7u*j?}CyU4XftJ5>*q!td$0IO;!usi?akqz@!GvC@>t9UP)0ay<&vp<_Xj2$I>!w>XQ|Lw5R^d*|Pnz zj9X1eVPAdv*hGtk%}Belc|IP({6#P*T67|syrF;&A}QeF^{F8mSIu@t5~+A;qO1hv zLBiKZ<}!!`L!v=j9iPwKxd)SY>dL3b3vAuSIBbeZ)XAsvzo9|v^yt518CZT3Lg%C+ zpUUQ1p017!5pFXq;St>gy@OLL{biCGbF)h0N>1WZ;5^I`^{E70Ime^aV-O~-3L+%w zl)YOJqg;_6i7~e>Rd3$YxM1CD|4IgoSqK4 zfbON{B^Gdoo|VaaBkN-)xft8>$kSDI3zz;i9~XD(?lqW6ld*~(VLn_7`{nz#d>#X& z9hi4Lt3ZMd%#5Pc_YhpyIKi`EDXYkG1qvxN8}B`+-}t_E)grPJi%JM@2NOxTnrkXR z^Cx!V{HYeTx>We3u~AMLD3nF0hwIzg)#pFdW~xcOzQ#{=qw-VT{1=9+7LK+yt`6o- z|FK`YrMC0Wgu-V<*Z#q8l^=-{J%nd;EQDoBFoFQvq!ODB7KA#Bpc$boUTL$}?)y1D z$u}&?&=`FdWm7{kM(^#eo2b#vOCA#H@P} zoqq%|8J{s&4ci|G5-w#(0=VsYw6sCE?Si-@MmF4RXut~-I({I8kxnvj&)iEGg>=iv zjEakmu_rlim0sY%^xtsEm#M}Q$qX3LD3L>UHl5IIt(a9)|CBg}9$09RW3)BCyxNLv zUE*=%=?X~jo#~z2OHu(hSpWK2e4)6zbloL4|$-ENNC;=Ag zRk(Btxm4m&&d+-2XkRaxB)1|LU&UrL1z`+=R=*U8fBifi)(cCnUX!fisd1)*H=`%CsM#i5d5%{NrQs20t35>dp`eeY#-X;UJ)xm;ln)))CW!`#f^-i&{zX0wJl??oV{n zP|}lY{Zt~ujLDUIr%d`M9k?g!cUawDy$QSsFL6#wJ1pxv@2jFGClE@tFG$##DQoO2 zE9}!4WBP-66DQ>J8|kVd%LWTB6hkA#_RCmI=jS9hud#RZT_YhD)OPiII~_quhX|YzXOfhxRsG*Kkmlt& zx#d8Zws2V|yGYO3=0-@LCmrOjpk_<9b3U^75S9_1{k4P+zYss~^;~-lAaZW|%=ZQy zN6L<&B~4RaD`j^#>1-8mo~AKVbZL%$ZuZ<$ScajVen*id9|zj1$gF5C~zO!(%#e_OfwHf(IjuU^+EgXrd+v9d(l zxa`!O)_KLtjs!IgvcAcPY1%k9*b5u|GeF4AOwi zDoZ(aG<5A_FY*{t$*v*fJGKCM+Y}}KgVI*C&QP7@}^cPwN=7YUxxhxMDffC#7@Z;#9yZ5Y`| zsHY!kEtPI5-9=7SIGzg2?!3;kJK}Nl`;m zHK{_a2fs-mxL*Sl?BjdgPqa&tL(OC1{ek_%6jLhQ8A8!xM-A9ov7>D{|8{`j$RZ4Mq zo!<);NU1GO?RbZ$87zQ#FSHoh@Wc&e38(8|H#LzUn4(m+Z)7wlTdTHkyUOeB!L zH0m4kTuQtn$;gcJXAQKBdg%jF#bF#U8KjeytT<^2v7~Atcf7G54_l|s;*m<^^v){* z4#y7QJRJ7ozgcQVf$|;|*&i{kYYd8Qp2}8xbVWyM_s@6=#yrHk=bmj3b*@G-U6T1< z_K9~Fu6uY&S*0ic%6@vFM#PY;BE|P81Q03~$8QU`yBU~!sxs9bL@*{ola2-eQCuuO zs6$s-@ez@DO==l{=t~5Z?F$g!SZX<1;T84e{+;N!L|#-&cRtQsISB`6?S?ex`nI$| z4ML?TCL<iQrp3qkILGre z?xPLBiE#?!b_wY$zrFFeW+Dev>IcCc=B)~!u2ew;HC2DqA9Jy+|5y=Rp{Do? z&t5LH`|?Y1D-!}(7TP_ylk4&vK_E)5AaR1X$*4T7{jcsqUQH{FL`B)eTp+Jo@$p!i zWR#r^JB7h8K`=8MB$MtjBWcS=)k1$4P`dhFZcO4n-Yc(t{$W|YT_!wDt3()xsI-?I zqWfF)d;P`pkgIi7aj|Dhr7?mtN#gp}My|9p|K@u`_;!uBZw}vz1es6tvxlb-<1!5l zqneJfMCZ6z-;CXLvmWL!`ZaDFq1&~UhFo>`{C3N6v2WJ;H?H8fRrSj_FYw<`{;EU9 z2Ip7XnVx?Om`i^trG}poO8k$AVfsIxv03SRxa8I>bEn_b=hs%2m}09NO7nK&HVPEv zSotf+4kis1`yS*?li~afv>{CNSiB!(P+L=szBOxSVo>coMD&2An}EYQMys?9!rT~; zrBIy2T6u~|%@hht`(s$>(7pZ72sOA5f$ZiNQRKFIpH_!>`n5~PVVklfmGuH6RmYT# zh8da0;NOwYnO7@(pV7J6ZL>n~$(4##PWb%_mU1hHpt5s-;&r-&c;oe~28FLR(^myW zg~g}Kg?p?Gw&lGx9kl;tQm+WOhbNT5&tlcLESBIse1-%t@@BL@05@&{w5&ZaE=k+P z&|Ymnjxj<=Hq(MX$k+;mJ!l#E2okW;UpU_AIau}R2r*>Wy4*B=KzqP>r)$Kf_YsCH z(nak%LlnKxz0&pOR=lN!DIUnj?{;RgONQ1`b80wU&G5J#3Z%y275aqOo_(@f*E#01 z-^w8bj~Ab#e(9=%T+0-8K8)}+*t>yd zpZ4F;knGF<{`C_LR{uOj|2NU_KVKnl#T(20AJeLC-yy7ELCK|Oo^t9{GO{qS1^8^IKj3tZelduBO|nYbEnHuf8&2!(*qM@+ILyA(aZ z%f?gb!9^PE7K^F<>);xGVAdAKl=+*^oLN&Q3pz+k>%%mh$kZNT*N_&9NKtk?UY5!T z8i_#6WlDKh{f=zbbqMwa3M$zGbZ*eYb56JK+!$R`y7_lrIMOD4k0*9aNUTwE7(F2N z6xgOb{HK%$^V0W3K`E9_ZBccXI9_1#Xkm0*}G2$(Gk!&gy6}tTix>su~&{Pw3 z!hZ!@H&vGrHE@$dFG$YVQ@9^air=JVKz4;KRh)=UaNgx>5J9;i(>}Oe;^O0ZUb)Y9 zeqNYxrR(f&9@}@{oHt$U5HK~0Q9+%FcNcH6yH3yQkBojrCT*iDJ%d- zogr|qsBwDT2u8UXdXp<6Ra`lLQLic}+&IdpBU`Z=+|r)QQTAOEyEscyR@rQ*;lBNG zS!2fq_@iPD|My<+3*g^@b#om2!TU3%{l{VNzhLxP8S7i>8vV@k4S$>i{?&Q*PW*=k z`NQaYLsnfMKqv#h!dY-e_?;j^EDn5DU!nm*qZhqC$}&~n^nTRNUqDrlNx3Ro-w8>Gr=^knkW<=410JhA`AK@&VOw#R6o|;bf075P5~4B-I@o zSHoq_n2_r2+#=JXWx}B`#0eL>Bc-_40O zP-{vP-xXc5!cVXYpo`JXBhmK}b`K|clk!K=J1|I;y3k1VWcL5A^lNb~^Tq~HFn_*c zjDKDBwP@jrgcdRF8cBRGGVp5>uypo>)EsuKQ`ED;bdcIWpeTgKD>1j$$%Dt1Km6f$ zzr4INInA*}^>xT;r9uE(TYB4c?6Om~hkqxEo($Cc@<3_QPEE$&WtixR_&EG$bj~3W zMWO$sy_KKu|2jJVXX*=%leO&UgB!YeAP4CrTNLtKOeFbT)F)vW*-~pmVq(4p-GQh8 z|Gw5?e#J}1Hj?&|y5k8K@@h(;h+DO;8WpdnzO`SuH?9V%gGM=`a)nV0fTsTJVc!`;n0VNg-X3`ceLjJLP?w%IE)mgC|VhiG$5%K&7*oqC*!GDSUNrs>&iBA;w> zcITj3b2y57`sDRJ+Zxf_@fW^s<;t4_a#5^3g5XR=Qt^er>^@&LN&*k%03x60Rfh$U zp~OBr3CS4G26#8ar_KxL!p-M~Z|DQkE)@5CFvVO+=lCPczq3L{1~`QGPew@kp_kD9 z7thU4`}AMQU`X}mpDxX3bQN9cU3Pzn zahMuSb$4a8z-P;k;1L1lYdlG^Zkk?lVrc8>fn5oqMq6Xijoh1fjqERAwrrq%-9LCmnJ4%8`Kd+KSr~8@VdrUYsaToUNUec zOkiSOat~`BY9H)D$c7A8we=HmD+~5=qY0W&R4gh;B|A@Q(9XsNwIQ>-w6D!-Er8z> zZ-htiBxZ*(7G`)%q%1}ksr@8OL(swwllu+4Q~S6^Tn!OrD|Ez3%31DEY260AJI5$} zdd=gZvz6u=K&+>6j0vLfb$<@Sc@0uSUUHAU=#0_lpg*MN=vcJFPflGbu!5^#CSOB0 zuEHL@r`W_+dGp#=8M}^N#6-`4k{Tm`c1>MK6I`UEYoz{gFF^tFRpHPcD>_68A3B5QkQ0;Cp7%(4zf zQ$|9SAtQZQba91QzKF#nj+(!#aa9t~0rFvkEcGk(S>X)D7EN}Zc6AA?hA=qQ5qkja zDG&}7TEvn{ALC+K42Cs|)CU>;gh>+J<|u~zDb%``^_C@@fC~)dkLD;(MjE8TyK(P#MjWC*4O6N7@zmg_hkHt0fr$OanX;jYF5nE5O4jG z9hK67jV{Vo?LrK1ab+s?>bnoR&_V6eX&g&e$G2BQ7feIU9hKPP3xjBFE8C>H3*7OJ zp5@Z(U9$!j7G^Bk)y4TB9p+N}nrF96<5-aYhqQML&UA~qMZ06$wrzE6+qT}==#JB| zZQEwYwrx9|q~qkg`_#F&_TE*u>g@0Sc>X+p=UQ{kG3OX#sx_aDeCT*_WEUK%yS{zN z);B6}E|Gf;C~688u(0ZSiAw%+=GHkV|H+IYvTTCI(ni~G$72P3R(GpcR;txVnF_c642LeHoH zrTkYOY~XUj`8@K{`loN1+-+TY8>Lx1rZtChC-VxE0W`mNrmRb-VZO2cNdI7M-H9@0 z%AO5KN`>F7aSRkNUR}%A`*AAlMB8$S)g5i-Ci&#>v*Fi(C29M(V7SJ1)GC2*Ffepc2bpp0Fu6M$>CzM z3KL65rMNgqXsXc6J6zrP@^%Cpw{Oh`V< z8gxJ-kg%*RlQ{@&N<|T>yeWKN*7D9~@M_aSSLd#|AHUS%IqW3gjmLR;S=059hi@*W zY+sLD)KJOdRo`Llc+0Eq0{mewM^BHVYyGCsPW-Hccx}E30m%i@p?^WCVdOWV<0f_o zbUBi`1Z-2FN~4~!ip_paRq-r@ch2-VmY(!Q#t@&%?MwW?td`uuixr-I%lZj-so0X* zZ65uvG0HqwDq)FceZD9}j3F!k5SOx9xm^aGsMWC68FF4m;l1wx$XYA80+dXobLlP*~#9s^4}9F2lCnRe8&J9<78 zr)8<~k9|n05{h_^-d8bNIaex=e0t3$UI$#Ds~43M-2UBt;_7A8fS8BHGZ0fHxaj-t z!Q$QPT~GK`wm@RW=vx;e0g~A2UmiyWq92KppZ%Gs`K(}^OwV>nDb@ZV1z4Gp`zRa4 z*Rw`=-k3l`S$SJcpD&CQ=^*k)6CJ%jT(QRls@DHSX^jaVPyz+k!QenX9QS{C@$4X>b$S>s*fo0@ne-JYuL{W8^EOZAvE!2w20S=SaSC6|#uHvuPKR4iR>(+6gq zWC-3U1QjlfDk>(;t4~ZU!!TIMRl{0H;$8L7X+pI(^v7fZ!J%V6Hv{0Cx z01A4FB=#O zCDOi+LS2e0bIcaz(h82b-J2iwSWFGKOn zB8s#$FqTD6DIAWZ?iSN?@(*R&eJ*4X+hgG*w}D2`mcrcAOf<_Jcg@61L*o;u7ec(c zvU49M-1&ae^%xSlI$#Z$Urc=JrdoK^hGtQ?by$@t>|Rw#y%h;`Wm@(iqS#30ro1a5 zIo9r|=H=K|qlc0Y>Je~A4Uy^>1({|w~@_FtsqI5SN*OwdUz+~t3mdf;+7NHWpk@4TCV4UZeEmWgT9?K%0zlIz&aNF z#0v?|R$^ys>G#{25bKbw%2o~1G8>4jrKm-WlT5!vgJ0z~9q_G*OY~~BqKHTurb7);`ua7vIBQDOs&$UaMyLW5VpNDb3x@ z?jYR9xf(F-Y1+SaJ&qqdPIWvMF6=NLyiV6GO0iX@D7(ZRN?2J|Gyf(zNGq{qka##f zjg?2o89s);g6=l}Z`4@GN*s*d$+M(}ZY;lKD>Ugy5I=7b?>wHiDAAr6zb2etI%f4rgq-wT=w=Z0GEpD#*i^`Ds7DDk$9*(k`s#&)~;Umbt&zc+yb6Aw6o% zNE(yw&5uiM2|+pR;O)Bu*fMnb-ft-0gT$L?$(C z8W5gsH_yYZQ>Y+^U_{9$5L%|VU1O9FHm^C^UWQ0+$DwGw;5TfLiLgV)_jLn=nC@8i z%8%Y6-+YQ8H;%CGX7N%ZM&X)1MggEYLY;yx(6gf=jd^e4fq72i3u~Td>Q2WwNV(i z(Z%YPU4@zxfHr`4oSYCfPt?g@L?LTaB(}wGvnAHjQ8No+*jjZf?(S#HORf#rUMO#> zSW1Gv#HE}EWJPZ{&i(%Qmzu3SxK%j=_(0zRuL$S=eFg@YIXfF!m>F0BJ^%l4O@fs- z|B@E`08WURun+(jE-_aen)Cc%^>zzp>lsQ14fGE3=`JL&MW3%z^6iD*Wr88EPrgqs z<+b!D7GcL^AJ^5359z= z3owbELskD4tENb+6b1uCu6xOO%iuSOJGwpq0t4L_bULCHda_i9R z#$I&7Y~O>bs5u*i$|^%v^8NMBE})%SgG1I_HK^Dp*OVQBTC}CbB4UlipMDAnD--E| zuPE!-HHhUJ+Elc3*!7r`L_#lB15aQMq97gB+)covF{hbqAwTTih%SPUwmnKsUD^jeYhw1B?e(&Mb-EeAM28`O zL2m^D&i`rP|6ZXLsjLHyOW}Z)l}J=fWP&Cw-Y)ZB%Mz--&asttjA!JHG?Mnj@rCKD zqdh;)x-r;=5`h*|h8^s3^Tl@(`Ek;+97d=;hZCWYX%HHz&W>pwJML-%JDgg`#fqnB z^fNHKQ&?hGMisuL=3)*h`zJFz~oF38}DsjZdMgmL@y z_;71cu7%Ai`2sEP@ir+D6SxR`)5zwZkB1Mw*X_u$z4By7cEK_z<4i9(iqJ>Uh+&Nl z)e2e(SBN3A9S`JJz(}7IiT+Sa&Y1$qEUO$SH2foaI`KvtZZCd}(a_wfvTe>)IEbT1 zP1dXdTa&HPG5#!#!k6nzGEB|tWNzANbW3r_Tb>;16ewJU-pQ_uj ze@TB&t!Y$gJ2L1=`GW96y_DRo@RpRmC(#o8Hn6)ZSbupl3qC|3=CY+EdjFwbGHEe% z$~CljO~C0=riD^6^mCk>Pee=mK?W%Ve;l0pc`2ilNk&Pucy3{@->*zubGR{KZ?4+|MT`f)^L?6CzS&HuJTZ3B+*i} z%PPvh&TrA}>;7!o5p4#oDF1lOO6W19_r*sP;{Nft>AtNu!Gq8B5*6`#uvG2HkS=qg z+DNsnk|`P4A-|Hw4pT+p{+}lgNqT}8-{6>`=(T-$5gOlj`qDj06c`Zug4Z2H*DW^Ws6bW z#6zX`N1aJ#SZYv$^1P|zcu5l*m`$`RXOo4EP4GHd7&mv@CxUHe2~d|ES?c2vPQrYO zI7;&r>I%1ONC{wT>_OdrswK&M3o-} z1@8wlySf#kANU0j#opqE+%OK470~k0)D!^ z|Cm|lP}uK4;OnUfv*Pf!-%{{57ys-}|0Nd|XotlCdJhXZDNp|OxSr0l zIyuuaaSLtkF390K0wJN05A5>hmfWKZeIiEZpNZTmr{Rc1HdIe5MVL<|8ud-U4&;r3Gq%6eW3$saZ^BEF(P)qCWim-}eeB~8}% zg<=LGi1ds67NeHD>Y5SKg6rjVx?MNN>yE7n=#qVBfL#10z`~B{fwR`F<^vDNrnucu1deeSGEZZe#=n zNjdj0Hew}(TuHjI+P~R%rw58aCh1H|6!~@Cj!5Ybcv2+HC=C-t?RM+LP7%(CX_bPy9 zdj0Upn`SKp0A_{4{imufARFnZR1yP44)W!+^fI$Hgf8YnZU^@Bv< zg(Kfoh!mSw7$ma|SCp!U{194BUR7I9j$<$7UC84sR@nGh@M?1!Q>T*>sesRC{@zl4 zFm!t!5mlAXqt9M(pW4+m>-%mEuaBHyzFH&t_xkPE*9RwGB2;ZHYhl>-Sd-u&L`=uY zh**jf9C%7V`)8FG&0w5AzCNxT)rQ7J=0(9F#7`N2_9|2~AN|?xk7bJ06rItWsJem^ zuZ~D|#l!j=1q=S6f4Sh#X2O=*0wY@r|K$to|NULHclb+OXJq@2&^G-=9|HECrfW1+ zp}|#iyCk%|tgVXF&yu7a7Nts5O#2|{z=57WPF>~im&aVtQa|&yJ&EhOSQ{FqhPb*2 zRI7<&2*9!!(cr>@%#JPFVtvLD{k&NwUH9$GXGK?QpiDI)NP5isQ zeUr9p3A9d1geN2H9YR+iS>quY^8WgrL6)rWv2}>-tY7{~|LRkFK@yiY+sqg!Ru+N-G}MB2xkig##}h}>RG`F#C`0(I{U~orD8=Uls^*Z%EcS?={qDmcX^7!GK${7BXX2aW9~$dpV^EiZA*ob=ObIok!>pgu+ zr!aUVs%BXgkd<&8rbDYr-{E4S4K5r0(rAM+XP>ImyFN!sV`KYjv}r!>Vtzs^wQkcs zH3~WB9Y-Z+ns8-u3LvNVwB~t~Ozbv(aS_>5Jj5NM=nbh^H(He6oEcM8|L&^`EA*Qj zqiwAhcaVZE&AboWf-wYo*c6GR~)~PlG+#YTAlEe-C}ATdT1~)jtXg9 zxQ)pWg+Dgieq~i(W9^P&u2SbOwzlA-n8?SHSmwTngkh_z(*!1MUH4cg4AlKu2ybDh zA@cGf9r)e7Vr$(wT^!lE8-UCg>}5nEbo~(5Zg2&wv&Dci$4xrN{)^9na*gDNkm!fw z6aA?G+y0Na+!E4ZPigr(DSliF-}g|#80+hY`|4k~pZ@}<2r+BFSb(*oIdCAx^B-=p ztBZrH3(#5L)XE7sD*p#Q{hP`J zsbWJUlp?r4EbuymPcQNygH>Ber;>?02?rHs_MV=YqG7S`1|Uh!CDxP&eN$=<%1j<{ zWY5~9Gbepe18xw@2aheyZK_l(kDvAE)UT01)L#D?aoB1Up|FoS$pghUyf=SnFdPLv ztbuJ5ew6qViUDJJ*i!0-*33%F0&J^z=ohnDI8<_?Nkg<}Rk`+HfT?P%YE*bR&nGde z5jQ5aCw84GcAsQ?QsX@XXtvV#t7|B*vCa78b*7`(xJ;J#;Q2@Qd4c`Y%gN9RfxV1X zUq0W@)2lll4k)$&2D3Lu=BQs2N9zeyx?>W9ZQwq9(GBeZL1wuEQ*=e>UtUD7-8iSc zEM0xDLsvf5NR_4Ml=N69Dkn;ZvFy}Z=Agzc3D^XLdg9UJ)Z$Sx3U2VQ>OE0eOkzb=X*w?K9G*%ruz$JLeePn~i=GKJB9)f^#tGZ^HzUx@<`G^&-`R_mmszCgWl zQVrnKU+`=#u_UX9+#qCY=Hun-3i4gk!A9-x<__9!`St~pac)KP6aRS?Q1$k7f{#W> z>>VzKwYDN2rv(?XhDa?TlOHw{9)+B?5dJta2t}echRspD?~JRiBY6`!QlVWdo}HI@ zug!&;Z$f+(WCv3S#_8sECblfkS!gwyLf@qCQU(x3^fbSC#?DULYB0cKaVczCRj8*H zH-rjBm<3>>=Fs1#bcq?61^JTXAnN=|Nv}`H=r;Gbn_6#3oAYy-DJ5Wt3>a_nw8BI{ zXxZVdFXuN5jLg4GIfnTiY^`QAA7R!SUN_)G0>Kdc(U5+eV}Di6Kee~&^PLwlX6B9s zbO_xrLKJ34Z79liroI`MeORohRKkIcg}qq{ zT=0ZuR4lgq(Wz;B3GeP`joj&$OcWRB|H5~I!%Cd2h$Qsgel$vhn}biPZzwE`@*=y3 z#>iDUSwSbz6$_4vOJGYS`L=0b`nOdnXEk-jFE5nR0Cswr$jH+SY-(urb9d=#cG+0; zA7lVMxn@nak<@KOjpc@IJj2@bKZdL927ng#>o&Qy1m;67Y?ecJhR`(xl3d7cj5@nI zqb)vr3ZdaL_JHP?KkYNAYy3F{UjgjWFO0jM4Q!9`Mwi7I97S?3-5;|(xzN16%AXtQ zr(Wyr1tSKpm`DsvWqXk$SC@gXvh2ATTDfymd?4A zX0teP8Ls=yCYj$gb}Qu#xjO6@=KkHS7j;~|G{SFX_z#pl`WnZ>(CVJ_ttfiocrRL z=;1Jr6pQ6N_Q+84NTQXK{i*#E$}W@#XMxbo3i}p5=jAQhY2W&H$bUk5{LeBT8DPsO z1z1@9|47My$3Xv2O1?616!f34GvPgz=%9`r8M7vm0a>?#g$opvp^QiswI)Mnq-x*p zF3`u5YDTHa`n7_R<9+4fJ{@-zH9Ygg#p0{%gNp5tdRy@5kd`J%vq`!WX;bjT!-^$H z0itS15=2Ygp5=C65JH$BVQ|CI zKILlU4IoH!Lk(hB{D`MzDqBvuf9uwPUscr-r<&ntb(H08vE(w-fHD5Mx@?5q=RlCl z#CK3i;n38HtxVR%$yYcc;=rIWMR|Q?wxy0P(!U0#ys_2S^xYSsj;{_Lq_@E;VK4N4y}65m$_Ea)CBF~^(yXx$K2X68%6e37} zV^!9B!<+4X82v;NO4tX#Zo1%?!2u05b%D`~P<=~jtgeVJ4i{hvOz476Lgk;X@7w+$ zS`T$?*5m(nHnXP&xni9Q?nZ0AuJ3{*?AQbTz8Be*91|}_6~wy&L^o90=fX6c>pSazO{pyR!B z9ydPwixjRbQ6lr`YhtlzaT&%BvyEcN(mswsp+RF6`61i|Q>6`|CAR*>dA~90OOLP> zQf-U0;u^A|yNc^m|15cQ3G9%jNzk~oIV^#Ee5FzcRh4a+g!?sPgotYGt80hNu~MRk z?hizB-V3AW&VeoBWPInY<#Wc2cdu{19Jl)*bd0QR`VbJ+<({M*|KnFUP*gJZrGI5@IzX>=G0d@5cqk3o4NXDidqqjZ-d>Zs<1Gf zjWtP^2WB1YL5E{=(Hi7@@JT2s$;i z3(OgwJEncImq>~OP%Wd=lFUgh$=neQE&&4Gx$i(3$unm4N~Qms!u zSQ5fB^GL}jj#kMRw-61_QgI*@6RN}&scbKe?sTeGv_((h^G{yykP!nNN|kMIuWWK^ z>_;A&rvmHK<-%iGQuf}J0)<>=C&h132xK4#39X<~?+#t;E*IoMl0IEB&a296Zk=CUPAs_kgu)s~0{Gx!#h*e8tC&SdJkQ*6{#q!uz^RBMW50g(_SJ%9Yp z=-`7F-s5GkTQ9jq)B3~5`hZ#co4kU3Nln6fOHOlr=9@pX|7`Tbiogb!&BFzoi37iZ zikX-b7;h$@brAxI9g)K)ArecPKd{gJjI;jDMtX95PUq0&Y3O`OdeZ&a5%;+Hpg&RJ z7|OZEL)2wz#B<8?qLDP`n6&hOGiXhN48H#n0U#o^sC*J}7cc#wrz*>m03LI~MIVe# z4Q?N}Jt1F##bCPA8nyUy5DMo?sfC^+pv}b#oK+YbwOB-TF+XE1avBdck~3C&JrJ5P zTH^}RX5|f#^SR@C{Mc-%EkbVV{|f^)IvcpnSJu)j-37P3%{oDf{^}!CjBr3kSeFDn zngbS&%dnNde!Rraxa0NoVe%oDblp42K|>bk`w4XNbb6Ey?Z1A{;XSOI?7PQmY-_H( zxr?w?2%AEsRrUWt-I`8A0IC1Lgv5RQqvMjVt)iQD@<)WjD|{fml4mgCx<1Ee%&fvc zs{`0-WxxcmsrC+Rk^YZw+}~@1;CLY$;EfBuenA%jA!lwjeLSJ~s)I4G(@GL9VrNVr zRR}oTG;>E|PyBeCqG6F!m^GVaxt`3h=lDtTbRE&;*-&o>Wh^9ihpvv#zSiys%L%-0 z!_l=t@=2EdI6+NI(M0p;4}ByTrv78QXxXzoW$1K$o>*{zY8Fu>u{;IwQqD5#Qq%Ep zK;}gQS>azsWxddXiZ_f}BBmQG;V<2YG2J?)0Q{(WpSbC+d!Czcy3NjsA*cpGShy+q zEQ3+jrFkYr!KBBLOwjM$rXRHcY65|ExG(jB-IT*&l>`WfIC|n9HlG~`cj_B znfy}ttut(CB|kiF?3fE%@RVoa(3yso)2I>`-l0WGVRJrDGd@#K_AIXD; z6e2vJw@=BN(E~~}#;n74!siX2%&RLsw-uUpoCHtJH=dP`aZl5j-f8HT+EjxdupdnN zszsH4+kGV&um56(rTmQFBL^N67$Cm?4;?xO;MP1~BOUOM4qdPcz@~x;?c=J3OA(8H zW614s94N)CU8)LDQ|fSYAl8gx--#TM@Ymo4>d@_tuBCOiCEcp|~4&tF0 zYl(hmzKSx`BJ-y!Yk^A=*~!#{0E$GQ`rOxsCV`4HedGZ8L_4>p&c>>@VIOd_=2~ZU zzT{?BnHWcx%iX3kpE~LW#gi}A)f!|Pd~c2(0|gU7LMqu@(d<_q`quNC9s2NM?8BPp zGw{e7={G4d&$tQA!9`!CC^ZaiuOiJ>1CLJ@zR9F3J*bHp*vvzqBM#7`FxVw!!V5C@ z+@zM1U%^lv6Ui!p4aYN4joJU#^4n(<1C!n2o@1^jqqrZw!PYA@ADeX6Zl)nS)N9E>{@3a^;I|pV;xS z4{CpFUAvuW+8;N8#O<^{*Tep*fl_4zUPTW3=TD0_5EoHazbu*L1j-tP!G-nf+L?tJzK zGHdnD_3zIqM}FLIA-;qEGgAd9TiI;_GgT}Q%lrpvkAuCfr@57_t@A&cN=5N<_CV6v zUrSO|4ndS_69}Z#pz$Q*=zdzO7E#*VPVFU4R5$S^3#om053d0HXaEIIY+Ih&n-=^5 zQ~?c)&5OOK03jsUv4|L^va;GKNV?AD?98o&AQWrT*{|qODnNpwH9C7AF&U4<{w+>- z-W^cu1#jQC^E5#u1{QbhrUC6dV-72wa-liUV8#P$rC^AEAp0dC0JA=z^!GlMbvngH zV@>c9pkOO`)10%)6=?Q&fBRvzKpKgG0&i6`8)cMEK}rD~KnwU?pA41r+r&Q($Uywb z!t-H~M2{G$_EK9~KK+^4GU$NJFfK;U(Y{c4%WiXA>RZt)ehMhzMZW?=_c0zo@FjP; zDE=a#9T$LzlEgs;d25RQV{~uPsoP_OKx6drnMA5ytUZ%1RA`;WP6c`m*9fA#F+dRh zIo<%?RkDe7M=E-_%hJPrg5RLMsEU)1^x3`R4e+aPZlC$cYQi&fh+~FGQ-#1!<~V7V z0FBb21(^Y}Q~XcV$SQAIgFs%?!dd>X!_q;hDSH;#s?(pw?1|-unwf_-QubELJP$^Q z_uh|oM1&qBi8(lT2s{i-Qs2TIGnNf8k z%b(2@Yr$s7J2a2=f$8`7;}qT*vcMgy|vxIL=*~(DNC~1tQ?*8rPYR^ zP3a0YdPe*a`;-2?i_9t=^OcS^UL>)5xFb~#j~JalBz4cCk)H9kndZsdw$U{NUb3P! zJzU%wgxUMUpwz|PB|)RwiGEWs7}Qb7(#Ik7wQulq$HaX~fNN%3JpP@DLr6{Ps~st# z#nZoTuQ7IkX9CQZFBR(liM-~nEdGSIPw zjCgir2wc?d14280?sfG>huLNJbZY6nM2YN7Za@0Q&STR z@;1Z6RDVjYTVt|aon;iaiH-oc59$X?w{JL52y{6fODX8Rtc~>+D2Ewfk#Uq;&89wJZd-x{zStf z6hwj$Wq`O%l)aa%{r%V1*C9;ns$CDx;d3J|8T+|Br>N-EXviFc8sbiZsamarC%iv0w?=nEZMq`NvHQ-`9H8?9`e=*eetLQ*N~yKI2aN^gPYql zCz;ODBWq2@DOMVy2AN+gI|$sq4G(l*d$fn9OyMu-5sm%9ZK?K_N1sqKw52$GDSD}^ zIcIq|REV^NQ$>Y*?nwX`-@`EK{r>6luA*=)$57H9?dO79>Z2wR0zbc}qW#$sfIT~$ z?byIJGttXmj~{S_e{FL)0$;8F=M|W?q4m#NR{Yv3@r}IACvBR7&QXg#9a-@8D_$g@ z3nSB&3ua>rpnf0f`1^!ZJEf3{n`uq8tWVXg@8OPg>JD8=MQ?I!3mzS^xG6YaWZ%G> z>NA);(hXlx|MfFSubrh?rs+qOJ{+SfU=A0K9cuyiRAXM@ePwP#5WhT~C6A<6^YE^< z1VNDZM1Gi&j=emLo`aAcU()z#O0yCUJo|I>fd6 z#?kZA(I>+;Zmxj#%;1W zL3a3%OEFyWTR7F>96yeH@31HSw}rTf+vTPhSGE*_-^?=p9=d8W=GhY>X0s&2cR!<6 zbDob7j@GU2PKdTF>S})ADMHZ_db0*%@iCA*y7_}+aEvsUOHa)75_41t+hPieDvXj; ziGN$x)0}CXz4Gd=m(vcNnPd6}`Tp%Q<4@oUlYJbk1af(d8gaK3A@QOa-jRx%AavAj+YkSCbU=tE1%Th8uV*5zcRFu|ux3jD|ZW_c! zs}>6?5#cX{}_);wI86T^O ztSLB)>bA+!NiB&d>cwlOrTPe;T@1ro?(1Ozcwr^zH3Sbn7X4LR)MpU$Pee(l9E z-l!|tQgq+zvtm&=DaIBbD9QP`Y_Iq(Eg$n}?swAsT-Tjd@M7Aeyh}#!6tyaHgI-X79GI zoFBzO=*8n?96L)*WuCW6+1-;V9m;F!OEB&MwmvKcWL5J>AS~?J!o>cFKdAmn)itP_ z?#;dxV0YuksDWvtIjdufHRG5vix`vfVil9_YcQwib@aV#;xCn{GR|@(cAytpr$k=A zvDRq*B5=Aul59NpWzsU+EIn+h7xTX<=F!P>DQ#oDmUc@yO!)e62MRR4lvybWC zpyQy6eTw4Dq=+UV*TP}oG#TsD+?!;3@G=m5a`p1>$|<=ooYByi7bD=bOY?fj3@*e_eOCH5Qcq4RbV@FR>km>*1fm z&-l@C%8r$u+aSVNTc_&D)2VDi(r0#@muO=&rBvGX^wx`Ro1mAaCj91#W{naig@B4H zcdX+h%$4sJ7%MO4CY~?E*T+D&uDMW<&?C1+?8lXXmODM}y4kd5tME3kXIS29lt`9P zc9onzX`mAxo1B3>#x#^9RmDUvr4lkE-p_HzbUAG5#gO=?Nd66GO1uCa)?VxK=R!= z2*z5HyLN+2S6QrDo!YImBFrP1wp3I?=S~ zC^=XIEVEfAlZvIfC=i7|j)==u$(@bN_S><_$;+amp1!6=?T!-tDf2XYpB8Pylizjf zIU5|~aOPUGE4QkKwqvm&=$<_#6;-ya>a#Xhz;Ne5lbX)98j6a!xO{E;u5HBsL%=+vKXyW3sR@KU-!%y%u^dq{20Of#;9gBQyzPiyyC6&erqg5S0Ho z4#!_LZ5;H_b{5K)AiF>jLBhRUu(+UwupFbN-aj5gAxx1b#E5QUZ#XlLV`0=jsl~5D zM{aw@jbUY=L25fKSF>xMTLW;cw|G4O;ia*>PtK2x)7K@$gEuz(1vLAUZwf-Aq+wD$ zFWnG2?2$FoYU_OC>O_HuR?^$I{b$j(`IX*FC){;g%7DAw>@n1HiR$dJ%y$gz`%Gb8 z+Oh8&A%uV8av8I&?yZ}(83+x?v+>b&4Wvp~4ujA?-~y&aFTz(aS2voDj&OA)&Ob$31O=u}dl|or z*VTxG2Xay~LSiZS_$l3jnF#1CrOZcJ@NfQnGr+r`H#p?mV2wKSX9qrUbRG+MCiV2*x z4!feYRi>>*9$^`LYato+)Q?|Jy&S7isTrW7o_BniV9)%zRf?{V^vzYlwY6%mU_$mf zMet5haZKtF^(~zt`b)Zj0PcxI7K~Esi|!db6eUNiCsNy14q>U(J!o;tiC8BDF}1Sk z>R3qPmYJVfGO`jHcQ&;X%^et*N?4ybG36ipC~3O9Ngj(C#ktw z_x#;dky4XI=utZ_*ye25yr>6ZLus5y5a$k~^?Xym)v#3B$FQZA9kU^z3(hkOVOc&6 z$LXBcjecVcBLCKvm;A1}S*P$s!VY3&l6Y@fG$rxY@+r%4(10!EM$q=QfMOuUsnk zE7(NHRxyX06f&FHTp933efNpq|1#_6bF%yt2S)U-R;k$kFrrRofWOG4z=4IC-9Ke; zNpVVl8TbcpztY)`F1_>9^dO8 zv^(7TEaEk-EJD0(pgrJq29_n+#p%I`+BB{Zz%lL;$yE0);1MKQ!z-$#F)ZVeC^@YD zhSYT4gdsNyDZ%nxjifq`#SC8KY~zDz3zY8EA-R{5h2|iHNDS$t@Y~4UHf>^->u}ht zKEG*p@0Y&bKpir-T`MqIKxKpHNKgrq(sZ&CC2!U5A&sKofOZl!OVHTyru{KG7g?ya zhbo;AX?8%ag_`V@wrDoaW@dCDQS%i#)&!aOIcotMb{~Dzn9+EfZ?#Y#Z$fh^ z>H7JN?^l({Bh%0_jpH6yWYxDLv+2Y-;y6D(c&HWVHxVNF>bBk*gT{yb*N_)l#3UEq zBmgA0ZgM_|_s8qi9rQn;KiRc+b|tV~)CBjR*4;Y+xxe-Rga40xWPeAYRqCsD`y6P# z%NiRLh)t}?NwN|ARMCNvS%ZG(SatK%ifA~}`D7$0WyEEUk@6p1De;)AQT2@vfyD9d z+w$W!^C2wSCwNizN{ zWHSGH81A;i`Ily2zI|A)!eu^P35EE&;HFMB-_93dJI<~Gs`A)vmq+qQ%a>$nFZBt*UR)Y92T`W=>lYerEgQTuf1cUe< z3Ig-4H_F|e8GGyFOfSlw@u*<5iL(n|?r3ZB(8J4<^UkhV#hwj2@;Wp{&>QU)>&vo{qIlW^?V zxKvg^XBd?H#p^Aauq;;JEWv*Gu0Qf;pi9puD%mdc<&y2vqyd#05!#b*F62i_duqe; z65F^+zD5e`$}SDM=(OYFwj`jLh(b$Td!2o6h2hQZvi>NvhaI*v{1bygWZ7&iA`-%! zVF-@<8i3z^#Tk#$*kEFM?XD>NA1jwitD2cSp>`hDuSm3`(zVJ=n7k4Jw;q z_6(GzOjfAV94W$ny3|M=U+~pM!ch)J{20#1x!oBLDw>ld7z6!SKdxUZ$*Ow%w15J+ z_{TU{Zefy1CApKH*(E|rq{%3Amu*uXJV)$&3VyJ0Z?9l|j^nX=&-a*LT{>z?>szH7 zkDmGlt+;vg8sL;xl6PK>)Ye^!f773 zbdq{fivCpJUrtVO-hP}jqXp;8wY0q*9)C+=RN~n7s;OMeDp-u#Va+|lvU2{eEe~4y z;A=*a=<25{5q-3ubPM`mSn?Fc}x+Z@BGek!k7^ z!4NM|V~6D?U_pTjLWk7zmLN8xD_iV(Ey9FSx$|a_80N_~ogf@(xx&z2&8)`VIeZCa z+!`$1&&+*rVujO2{Wwv_b`(8i*xH%CBZmma`ct*qrK3EG6Qky(-4I7tLPlQ3z*PU7 zy9-W5$Bt#gK=HORzaS3^eOimPL^(ElGYFCXR^m0CnNr(@6SKIXNN7;58kEGT_!c?V)hGGDK6KJ5REYf|>?zhmk*iJ^l!onkg^+{DN6p}X+ zmAmPX1EdaUdVyua2MvW>4x1HJ%W#CzkYZ=(hT~2uQ7c)qmyqt!_A9U7sICi*)duZ0 zZF8>-w2Ig~#bj^i?yEyZjY0MccOaKhBP%5N*7z71Zk_9k2tR0G(u~8%amp7htz95m z6s81YeT2+y9<zB zYINq#;Go46cOqPJ3w)7gu$0-*WyX#VNg7rvxgqo+?Mg`3*j z+qdbuT}x?mMp}4Nr+M#Op;~o_p%r8_Fm{x|bQ}{PCZ@s=Jnp=o7-O5+O`*Rm2+IQDaaRb$+f|c+mR>HdNFJ@FYqx0ZCBnopbFad}g0q zIX7Q}0`p_%>s-*Nt^SJZXfG@=6#58Rc%LS+#sNJDmTr9w-Zx~~LAtOs z5`hq8UnvK5-S?(V`ln17d4@Ku<$pPgjelR={@!(pbW^tGdD%EWR zbRP%3TRR3+%=xd8?3vLU?3i-&ih6ZFeIogp#lG_O7)CaNMV1C+DB>GF!5vFDJ`wRT z+!C~A)A)k@jb9 z?S66iP=Xw~Ts#f-wlGf+cVDBrab!B_IXt=hav8lAdsr}IAZG;_CAsyN>Z#%GEMokb z`tvLN4=?X9nVbow#07IgGRMfcC~*c|55hfZ z*$OKGsGMvRFWKNQ#i_o?F(s`&S1E7~+&HZ{p)E5ZmjLgT_up3~nAm~pms@&UK!2jG z-06WvH4di&zES+yp>}zWkK51j;Xw&C<#jCb&^^>mh zri0)%a&!S#ojEnt=!RS)KaB=wf(g5A(8Fh0t5a_rTa%K^2ASd0gxxf|yuML)8}*(Y z$JA+%X$FgPU2K9YPdJd9&{<2gwJj6)?(q-hfbRd=gqy`N#4U(j3bkMmsg?R*rpA$H zrS^TwMoGmfyn`(14a;^|Alfaf9ULmMoF}uq&d~$EEYLv0>-44{j0vqN@_0Qls=;!ILZ0H8H81ijzZ-4&UQ^=YvH&#>J**~VVH6Oxhq+t!oZgB<9*t-O z>GWA}XF$ggRlHl!7qq)&wpXFUaLX!}c!6WWDx83?2J!Bog)d6BZ=!OzqTl~?Fi^H1 zwW(MR_<4*nFSM;XFpKV-G~gcxOG(MrVPjXDY1zAK8HJ(nyqRDY(Up~Dyo9h}4UJN| zvta`4ZMyBE`7GE>^THv^&)@KYB88t*e*N5GE5XVbhzUuA~7<=*yp(=pjUiD@hZj z53E6`*wh@$XuXJi{f~~+wyUCjWgc|m{;D+2GQCWvv%F`XBwJCP=GjqC8DqyzuNa~k ze~HMiFBgxy!y*+nSz%hI&m0#5-=A($fGKwk!9b;Fu(Zc^v^7>@T>_r$7Dwt04_aP9 zDpPk)eyTJs(XdE{P||i)*d~mxGEX%Eg)xW|DmCpGxio7=H{2kyf=f46y@M?0nb~6N zjGO!(WGQ~SY@Wsdn}qw-(K=)-K*ctP^a#37Rhb(OX?ONb_)s%D!u>-^tOeeUV? zB~`0dRldwQ#+YM_=lLPsh#?N8Rh3m2UDBFl!={dkfHy+#Y{Ao)xxae)89^xAZd1c8 z25ah|@}~qv5j65QG)I|orBZtPV`IY7*#0aC*QJGBDzv}i6L)golc^CP}n-`h(|7e>qTLa(=voHck`VU=s?g?^|lD2pnNU!JU}`uqz6 z`xoY>S-%D=(;& zGOao~lh(-5N){rz;YX>^J?2$=%hI`zS{zE1+2FcuCcGlQWrGa9TaN*wpXlbu8q$IP zt7BX3;s`E3KD1uXsj{M1UOUz1T} zytqQO=$k~tHjm$^cQAlAOYLnzm{(WG**<%nVPAlyL<(bq#_Wl%R6FO$ zu++GyNHsa5)(Q6{pj9FtIBTkSCdFgAD642g5KJbc8R5M(&r||BBbWyZi%ZH<=t0`E zgTNw;FyC9;L^<~vEfq&EA7P%r@t*KE+H)hfuxnt#9Kphn^NZscIrKA}DZ<4L2YM*u zKH?uajT|GvH4W^W{dl-xN71v1d}1L~Q8XF@@B}z372Bck39ZATKbCT+<=d%!jP4<8 zP-q$3w|=q})?xV+_iY4)zgmyYN8J{ZL8S`zn3H1CSJD<0-B5v*b`@0&ERWUWPGZYX zzP!6f+bvQQw05hj4A$XRO85+LIlgMBh@-+@zoGAQ${Bphap*lN*mnw4X%*M_)({p* ztUv#vFXgE17GDp%eG~3T4B}~i`)%|zW!pBO@1cSu%9aKH6Dwv5ceQfn z*tT0@dl1+NKg_|q>PFH>mB^>T*=h+&LmIa`+Rg`$K}Y2-e`ghFjW@R{`Lc1Oh;+(W zS+~eto9h0My+a=ZbfTM#i@oSn5iXrg?mU%4nqLE*L4-zVquDootqJvhqlxjG2T>KR zv7b~exYaNY@yA;h0m6){cS2M1dc);iezL7hh!ojK15v7-MnbggiQ<@{Km~iD!O8^z z296@ljq1f|(o9~K+p_ra=p|fL;~3;7N$J6OYS*ZI>>V-B_PiAp95c{7>w$L3 zSfp!e;XvmrO34hiV;*&P&|4dWdi`&cTG`-~O8dUkpV9$K=wJ`Ym6)4m1Qe)B`RNAi z>-capLuW4-nXq~Wi;e@b5ZJ7tMX;Hd)*;F7)A52vCyS6>65{J%-P&nGZl+yiaZNq2 zqne|K-&KmoFskH!At_svb?3W3Fja~cahl|!gSPvZWr+8(>b*e^^+$V2a5?<!*g=3hq4Q zGPjW44NO-at0r`6G+6;fVOUFOPrVdtc$f#B1cj?KVh&x6_ojB#h09NQAyHJIhS|FM zF?A#5{afo6?9CTT;`6B0b-iEW`oy;#iQMl1E8K9ACl?7QFx zsJoJx< zpc~z;((4R<@x;f`PdLE%yvYemp*m%cpr9hK1eMdNx98QUat~20uxpaO>=a}Obz8Gp z#ok+5L!0Z}6wiid3^?!hXDPd_MAk_#P`RbnuuB-|6y@rkmyWotyzh5tiXHh?e9y3Y z=znBr{r4!+|PuvccsbZmWa2JPgW!*3>fND4Ti4J zyoHCXkdR!W;I1ZPo9DFBUXL6H&l7L-n~Nt6mHtEWFXqC!o9v_=n~ePXLzU#tv~^Dy z+vHZOHXALk19PC)*QBjV4CZt$#K&8f*lA1O9T%A?QSTuXl=HWCuYH%M)baSL<(G4v z=e;#=TF2Mr8(_d(_z?ai`&_Y(#wts|v&`byXw7ODbJbjwBCArEOMcOY1>>C)&>}dd(%DTvdo!E5kq&*5>iDvFR|JJMU+*EPLod z%NiC$*uc#ZlF>&dk>Lv?2H;^X1r0(%W9I$HAlRTXqM=c;bde&K0v9v8f%y`)3XGqz za9Q`;F0K;>8~QtDPxdTmO@Kz}CKbHDYQNDOgO>P12F7=FXMm=Tl`TNVq-DKn*}A29 zE@P^f_995@cnv0V*q-;T!YOwqU6`UO6#NW$gRX>DAE^VCkugTk)q(E=htAr#phl-} z^=$mo6>%%dWPfn-b6MoYjTfH0Vb_rbE5^UYke=i#@~0KCo4PP$%Erp?-yXPN@kXZh zLv>QLp70>(xOH8B0)gKc8HmOyNx%4rpC;N+sP^8kv}z!zDfNq(R2eYKV2nkYMYZxa z@`NWV=d4myLs75*t;Fg@Wd!8p;@rErzRX@M4(bWNakn752m72r(uTe{T&etUW}=cn zE2uFb-lLH$gg|DvtbD1#H#P^b@35V9_&T{23uDO8?5xbAey&h8vN;}R&E2vq zj_tJhtQ;dKm8;wfX^u zgXyXM$Z^y3G5s+sIz}`o>)v3Qk;(0;zb%NR5TMVOF2=18-g2d zMYQarK)^2#hS8=K`3rKM0rgyxQEI2NjEV|TEqh-2Zoza}zRvn;WCep)tS$O)&>HRW zuxres=UN9?Yn0!PRgS*h9bo1e`{$33KesiRWZndhamx(0kqw%XNDRW)7zDP)HN!+myl$ z_jS#OkuYt-;Tp%=NVNwIOH$LHbB{k%t;m=CwYhBPnOsQ(SNNJ$8@8Ny?$cs7B)qD= z;=RP~&lkJy{zqPa>jmDuZh&uzIkMY{Xv2Ao;}P~p)ltRgCy@?WVSxV+SQhD;7`c@D z?f2W^ui*&zYZXB28rZ|p1|X-=E`AJSzBz#8;OJymJUPfyLTsPrv(x_kmpKF67Pr+u zwvp|C03q<-&eaY^Muz`Srv8VOYhY`uqzDcKJhsGU9F-t#v%v7bRy7OkM;&=!ZOTRm(#8x-ys16V)r#h~=@AZ;NY;P*9-gg|;5G%n) z&v2@_$}8__z>3!r=AUu%{HG`!`BD4E)c?e;`n&HUST_mp-_m*t{o^HxmNR52g=_?H zDQc9ao(NziMQMWz&v-miXbw9?_j4iu1%}k;st+%HxShh(cPE-hsAcMiqr7_gE0*C&6kE*&dRIOgoNNt&llaW=V=9YbjPxrvwO*T{U}rb^ zOqbrLO*a{aW#4r0?m7`c6aIx%uJ%APLXWV^R^E{#o&h zTBkNMC?xUn&S16NB~E&F#>MPRZ|Fc&Foir&b42T^N3ftOGh*C6L270^`WSdWqciSGqel45-@N3&%}KQKE-R9XPO z=%At(JN=7+I{538g@Zuq2o-CtNt7*UU7t}8$*$ajtcEbHD&gIpWqf`(q<*Bnv19zs zl0{=0|NhSVFU_%A{Y#v28T+B5)eRrY#y}~ZBBV}Ii3Ii=SzsK`n*h}YJeqb8MrR%r zPpOPMyo>3Kc;EHZ)5quXr~0$&EnZb&nPtu%lg9^us*e2I-{GQV9pnq{P0bkxXw?Ax z=80b%v^=SJ*9zf=O1Bo~RhxEDJ=hxmy6b{tb=VP${rsqn#1yXdeXV2Z>>{-5=sYut zi_9Pb)zf~Ocuz$uX8W6W`Ck?vHF*We(139qKRgf+_kSZs7}?s`0|wy$djJ!FakjnN ze}soDWq^wrI|5(?2h+h{ncLOqrHBI>wy&#ID30Y40o4A}FK&pn1*t4PQR|xM^9lEC zuN`;Q-IgTSWJ;4gWWRB}_UXa!mx?DhhxgoK?r}8pT&U77QUOAr%91 zpanpQnun8ysQ~H1&7W5Xye$h*qI#Nk+Hhb-aS4N=f&G$6O?6-lMvQ@EJbAnh`AmK_ zTz!|KfVTL8EC3Cx{Xp!%hWX z9pWN=H(=+zPZTP63$F#^z= zPr15$`X$&wno~o1Wut*s;DGq99$u_P-}sVYX1LPvprhbFw{T5YoD~wuEi}XaM~{7@ zUtPF`9#^z5gS;iNo8T2zn0)Yc4b&W3&p1;mzl7r*qktt@K-hX%VmZoKd^drkp3(OVyJ6{~Qp3Q=Q7WY$Rr8W^U{K}dtKn&8y1M3Gs~{!?R@I6poM6_NJk zui)_}8eHhg-yS7kDd$?@cY6pLgh=FZkMBu1LtcJyP?r?^JFJ`=i|ME*V$$mz%K_@a!n~xv>Maqlz)sA|%hjOj zPB=OqSqYhwMPGTKWo=T;vPa~|#H%{WfbW+<=qwP6psa?Pt_X!-hB6D=0ET|P!Q75D zno_$;D|D&lb@_Sa`CR;O04!OtE+PNotfDjWis5UyrF#GG*0~7;p6ju zvv7V4MQyKg-+^USq-Yf3f0fwDyKt7R(xMU*`{N`#mI-V7udhAlh?J{rO>cV#*)^Pq z!gqzXPL;Z{$=KJFAhFkcWnBA~YQ?~>EmQ++;Dl9W?a9wx+Wg;5v=W09=1#ht+iV5s zXtQci$FgWR{cCrDE8A>vzgJzZ{2R`g8yl{Sh|mM%sl^`$eDr!ilCV>oZ-#UWNox7V8}2N7Uq36(<|wE4{8@m?>F{ zaxvkoYiiE-ei6tor~o_pN9M}g$J3>GzimdfYXmNy6dRUz*6|(+&!H1ho`cM;FEQCN z%OaBC7*S#dJCK|(F}Nu7G5dEQX2A&RR^R`kc032P`zee#riAiSpsq*WfbK&L(6EH| zt(#_1PCGrnf9hH-{tzU)LPXmNaY0*ipwZ{Z`8WZ%6$e26 zHD(k#?VYz@Vw1_lM#Da4e2Jm{<^a4Jbrlp)wp#G}f%RYPa2s5dK0K;Zl`lM7rTmcSRoaU-B3$X+3 zE-+aslqApfg~fstHvIX<&xt^0h&QRqB%y#$q9?|0kv+NIOtuoN@?3h?iTF0x{-sfV z+B|!+$6tNb-2<)hbN5&USZ zRhvjp-)mO$h$$K;S|i!KRIlZbo6TrVQG=~X?KjretEJANX#2Fv8ue7^@ez4vUGz?RB^?_D7Vs;@a)%4dmIsT!JJ%?M@OlU5^|tWuQwCW*7m;7l z|8qzyAhW#M1vtNM7(hUL{|5=v!Pdy&pIsw|e?dX3{x|jfN~hPDpNP2mzTU<;K2KVM zMm6Jy(-ImaNI{fxEw~64gKd$ ze;MHTV=PYfk7n9Y?UPm(yNV0{FiC~UE0GZcFH`qEvjl-S9TN&etH74}+f-f6SokZ; zhm@(2Acm*0Ph3XyF#1@oq=SAyBw6-#nav4bwU63i`*C4k^B1vwKNu&3LT%wL$$(%s z)LVkofyfRdhDX7!t>`=j#Uos?q0D^ldWACN2i!EoF+^#^8w+U{$(edrX#{fGJqnK! zmk4i=Eci*QO4`QdB6Is0n_$rZA!l8sqD*%{UM*3c;fK`r z&#L>r%*UqE8AcRS-NQJI^O5P0Fg|7#DiXI5*Ej+Y@aSEPk(n*qR<<=d10)sks9j8w zKb=7D>r&u2F=ycU_FmF>2P^ga*4xepycCP#6Vk@q%Tx;Fs{Acu?s})R)r-2$4#CgX zzzc#utk_7QGzu7wacoI|Ws!(NGV>HrhEi3apUp{?IaMK3cyf6#7N0~bd&!-u41!|) zs*WebABv}*o-@XqS}o(+C02Rd9kgHVTs*fiHYS~1RmGRQWS1TGsj~j!@fURTMWCT4 zHhUyZjYTC~TBCe^bLun?@3=h&vLs3AsUa)pe}y60!QHP{!?F<2$-8E-Ide*{>6;1B zu#lx9{ptLwdTez0-GawzwL>s2!kxBfi`a@-s|m#o3JYdqjJf(uBRF|F<8=Oa znS0dHSv|sf3`(0BMG|*VbHFi%*Aa1|0({wBSI`F}#}~%n=YHKnAneg`&$bt~g5QqL z7(qoi%nT$Y$bu06^Gtd!i;O@zW#L@6AdK(&EQ+2EsxAGf-uNHgFg1|-$<&5_FtH~-ymuF?M92~JjVU@O~wVlZD%gF zR`f(nndJ60vw3}8XSusKWW7kHJ9nLN_Zvbah=sQ}nb2+bgf=z9DqI%Y^AFGSSxP=C z?Ji4M^@$giZ&<8s=GIBx?oZ?WogT{I=g4)@l<=1zrD$-W*SaEkOQ;t9mSy8PhK^t$ZXh z1-m}!2ijTdY)8|xI+XR^LPO}pT z`i$9O4Sh2Bg@15M`(*BcTJ`Q~`~j+JOx_J$O{?Ax_5o?aD{6 zD+sG0knX6L)rM&z$vg;x0+}gK!9z=y?iLy@B{!;jB2K+(daLrjaTgCl#7W!c%eK!_ zJI=+xaq;val9g+XTrw}(4ZH{{0EAqi9IzNtgd;&UaMm7gkL*QmTGlOKr7C7Q5~;`$ zdSWR$fvtA`6NiE%;1x(3A2Hxc+ktAag-qHDuXF}}?TSwukN&>jQIlJSCKi8PFNUHd2zTakTyPNLw255@|M2fXjNKqwW zh~K`exo>ZH()5pjsxmuLp$hV~`aSWLA$P%Q{BlMDYP``Uohq*He|4p!5Y)ei0ZpfW z#D)LU9Qj{My(VR8n|)S<&T|zhgj`#Bv9(LHU6P-MR_NFSlUT~lC(^l;V?;!8AmXbQ zG;iBnC`F<62TLi?0!Z^rHoRLC1pt|FFH_2*z^#?Ft_;kiPe91pf&3{DEV?H4AX}3j zfM0r~s>QoCzg?Ej=$kYc z3*5ytG5?{nSAso3(t3btoZb7eYxKpUMz6BHL_h9?RFiyf_*ff#`(0C^boavT^VX$G z=P${8YHEgWmC?LV5MMx|m|ALK666C0L=pno396AmeZLW8= zsim?3UJjDOxs*pBI8z`xEyxUNfiFQlUp)oCFmz3OMz}3_ zHR>B|McBn$m&KP&gdhV=uV+6XyD{#`IAXhbTD(!jtUwjy724Gw8D{lg zz+Cb-3+jJ>pOKlVp`v*gP3sH@3ZZsMkFg{~1Am}d_rsM#S!3Fg@|#)kkE;+qgT($Q z0fkG!rogu27lzr;TZtNymcg|_v+M_#3o+|Y|D>@{$m`yG4xVI0QQLLN@OLT`nbcu3 zx;e4S+d++!Ityq&<;5$e~#VwGsB|YR7hmb&5hbMM@|>~*L4THDt>8rj@vq;M$f^R zmw%2{!8r0LW>cNnT?!hkAwSC-+R@2jeK--MNQ$W z*Sm~omHsc-q!P~-wiN9)4m&k_CJ%kA*GKT=mc*7I>A5|#}t50P}5MIgZnl1>!|K>vh;}q zO@Wj!YeaDU+slNbXeznqL0_`udU%su4#l=MdFira%@Ise-02yPSNNO1}utwMHC}cz=P}D%rF6uK z!^`74){Dz8Qah1e;+gS;VbCM)!?&2@#MV!zH)48q*h}w z7pez&!$sU#kI4*Z7@6Z@2aa<-s!#}>L@kJ{so)7MD9%plZE?8J2FAf-WLDaxLUKdT zX6O@RDXM;t?O61E#Om?tv}|KQfl9t*G3*o}#-MciS!(iO_wz{<6$}Rv4QXlhUU>EK z#-Q>I@>9>R!K`pLs$2Il#^v?k5WnF)^`-I(ML9UJQtUOZ2==LkXd{)}f~}rvwEa9T zsp#S|r->y|QfY#5bc6QD!qwateHA9}Dj`l1FteXgPgg#%T$r4@V`4yDHs;&zpS^YW zj522D;aXbam24jFnZXgn(O}CTFuTgHwI%jNN z`pJDiXINQi$mZYXO?WchPfoNLG_Bj-u%V1L7@q&`pPBbw2sl?16QqjpB`$6>tWY!n zqJ)?Ak4CT#l*Q6SJj)_SES?ano(bNj0H^`lWQObNf5D<7a&M!r5A07z)({#piU7u# z9xfLroj(YB$$#vaRp_IcWtDojcdlP%CY2pQ{RYOj=&88 zZftWl%d#4oDf9m0N--iY#O)TJaSNBLf*Cfi&zk<&8zqbd;rmWv%sZdUO5=w*xARxO zQEBZ86CKOAdn$J~1df4aow-JLFV`Sotbmg4?n|%OcgDa@qC$t!ODP!}{ZuQ#3kbbg zsm&tZ<4UPnDAX_i{#rhpZKL6>(>yudwd${yQTKh zE}ueC6a`jKYcRvp(ilN>p?D1kA{Fuc^|o>DG^#pi7d1-Au z;xm=Uyb$A`PflRE0f`OI*H4X(3GRRGU48va>vqMV%6tX5LKlEVo&U}($H>XyA6xeS zEpPkhkCC3$e?-_KMJ<~Qegw~Bl}hO0VbYV-4)}86O9$aZ zE+QsXF37Hwgfv3}2W^^Q>k%b@CU=9HbR^$n=8EKA9myvImRww4p5}U>56nR?J+%0G zIJ|1~8y-wvz#IdJ*k-(vpxg;C1xgvWwXO(~rybH#w@=SpS?FoNZ1{t|Es7g7s}$_- zIwdD!%i4~INw!5zH&;K3P+T_8cH}P$r5wHKkzYG&sjaVH6dv>`pd2KkHS9CFNR}rY zFW61fh4>*BATC`Vbxm$M)_Ngyk}Uo`&r?j2G>Tj)sMUb7Ufi2-thODApYyYtkTz|} zm&mBeT0*o`Yu_~(#t;t1oKo`rPjmjd1ZyZ_p;Qk}@0-8ciS49YLV9xhjvD&MLDjlZ zshHfjmAl`7E2fA>nSu*{lj!-VHpa8geNJj@loeo60GZR5SpeEWQIxqEhI}cS zo(%TxG1lytb|fMFs-RG{;h`0Rnh=s|@+)wp{z=mHX(RmfCu|NvMLM3eXf3i~PE=2= zwPW0bn)`A8T2}a`9vkfYMO|!yNhoxgTt0*))LZX~BSsrmhhCW-JQsONMv}L$iv~~h zLH1aNulmwxUT$gas%xsYI*VEn*K)gQxK$;AtAgQptDZGA0y94(=6H)fCIl-*Ajn3jCR z*<_USjV8(41KyJ8{&JSQuVP|6Oq*e+g=rv*Ic4Zn>ydxREjwAV@|{a@dVrmhWp%H9 zkEyZPnl44>iAHBW;bn!~SPtnjV+sfB_ULg@DBLKfhJ~ zHAht`ZrjZB!+1~Y=&_oalcxj4Y%(_%Ev7P$HCjft*mkmyhCR@=IVk_|@5bFOI*;ik zi5-!QZ}@z@H+jz|@yjA-xeQQJl8%Lrf5c|LEM;91xnP%zu1t3c1b1xX|EWlviMbE? zOJPo4HBgdNj>{7Ye-;2Y?}*kJl>5yzf*|nQ46SMgUP48-JeZhn?vy5D=pm^`HFg3B zOa$AQMeck^yk3)T|L-&!wgzcM?T6FXSO^?3ew>yxZge32kmaKnZDfK ze)eR60pWirKnZ~W%eKo3l=~n1ZB~Dpi4*M(>)BU_Y!w+oE{T_V@>MPIUzbk8^BPri zErJHR0&aN1J3{Lbr+QhOr%ERMUC?B8VUS7k(r;aj9ovY8>|)*=zHV2_Y*LYF><8bx zc-B~|UvTPI*_W}`t+yyRw7I@0A9Y)S-(EBO*NDZn8K9k%+Zo*8s*qsssZxUo0CoU9 zH!Zj@Zl#R{1-OMUqrC>@a1^9>t38tq_TFkQH zcXxoaEoIa^wQlVix7Fon!7@uIQ6v=8lN92c?3?hn;iZ9}KeyN!jINFOvCq(>)y_af z0h7!&i*z|v(unC^s;}D0sjZW07h4ZKasS3HBw(Ww(pMHM=^2pLf$}{mTk`NeqUp## zuNtDky986uNJkVR#|S8X>Wv!?B9j5=Vbr%s2`Nd>%}~EL*eBh^m2_JbOVLo;C@m6o zI@k<2FhX0TiiGf{T%XKTPYX z(#9Zy#5hN?T7u)qS8WX4?eoEwnBiA!l~o90fxWG(0L^PRoYI39BaYyRWdG^e{d^BO zfB09&U5cV#?-&cP<7WTgD+Zmcbqs6(qA1t@^sb-eu~0Y=jR!E^!J~B-rRMuBH?~5C zYXg|pM9aqj9~Yyf7VU21 zDTnkb{QDPYwfgzmO#1IJnR5HI!$CA=Pjqx6ylq9&7}X?EZj;0Kh88vD#0x5oM0mZa zRX6Tqv)+)4Yi{~I8Y3G~hyq$Hvev!KpnJDw^^jA8%&mHnO#YaL`O(2eLq%^&wd4j4 z-JU-CaouK`aVJLa&$r!OJ;#88sQQnmrVCaNCa#|90NM+?$JavWkge5IrAUd!)BxR%u?F(+YKEOCigH~UX)_vk8iFOt3u3`(Afs# zBA(P(Z-n%H9Q20h_j`x9Hg040wG(&0;E!FneSkwVYw|o?RD=*TX;n#6En4Ah_DJXq zv>z_bXYCXWvgztQr`}n#1C3G%J|JgC=T?776%<}a+M8xp8Jjh=`I(vdH#?$vjkzwO zdnzZLmxED>*-ahunBb%J$msAT#iNrV5X+QjPQRpZ=nzL{8}5iCB{tmIP4Z;QysYr| z9k7n?+yC_sHf!A*#7Y&XfO=|d3bHrX{>}|m?_nbyI%;qWfu~3^*G}hM_HPj20IIhH zP^#if^mhrpFS9ajQ>mCY)!3H0EPXI8*1Nq9Zr?~XZx~p}j+l-9*r)SlU-iw(*39{0f46;o z7MB$ZfemI({V|-Kov}b6VajcTU{o{9kohg|X9)I5z7P|w&;_&}hjwVqCdq7kybI=u z#iS>H=&lNkFXEi~JBc_Cr2uz#LiB1}*Y*S)gzN%YZApLfShwxS67Trl9DG4qzy*GE z&%D?WK9eWVZ1qR^1WFTNL5P9!*BQN>+&yMp19(RWn%yikRC`|QZtVC?HuA+gO|)vf zQ7hgI$#nU8k^dI7ILup$|740ClE6G6XwtC0DhHk@&9PBZ32QbsLDX7T4#Lod-l*Oe zbN6ff^mQ!CEwnU&EZp}_!MZZWi?5cxK%|u(B|O|N-*!VcZoNv)9_vzFCe=lXU^hM) zdcx`GBZ(`Mp^uf0r)RbXZ}X!YP!)`5$Y7CfjN6Yl&W=&txFZhuUeVg_I+Ov34c1A{ zAfK^Ye{hyB+(j@ljM{>NE&0Gds!5o%zNCm(2!ah@0iOo4Z?lxYf^{;=OBg$H@|ii) z>U#us&eN~)hed=|;oE!@-SY)${qGeMx7nD-?C2}AG5`3+n3+Xdlb_ClT^fN~2w#hv zznfLNAGb-$bCy04bZ&lOn{IPdNT1I^nEYk91dDB>sfst$I-=$OSPE43XlE8?2j}D7 zC4~xznzz@mXo7P+p*vo0@AzWHoJ3K#}E#-S%fbKjKdCraRr z9+3OW`)UG)nYCb*Lea&UKnSB1s8|j-d%RLqTl(a&Vk7za-_t+q8-tjea+0dvBj+{A zdpH@ywRvrOsys*5fV{iXGqrQHv^}ly9c-?#U~$syn8z#9^7}(;mJW$`;)>Ov3V_8b zb$JRpJC$|if|)vSAzw^m1{f#xQ(i&Kc`*wa>8RrgexG}ADp_;cZn_j205 zq1zNGBkkkTL?Ft3H)PPb4>Sqs{*GFjDwI4cjCU7?1|a=}Y7EsO2_#c!b_v6s$4J>E zmkd6B=BSX$Izk3Yf6w)LVHM>^4jD8GHn`6A|4?IU-ECns?ZoTN;kjf!TRhD9hUT6P zuJ6D=e}ZDV5KAkpMs>zhvAD($cxy#+v{vAlx`!dQ!e=?^vhxhVRM%)$#qu<_G(Rs! zd=Cpiht8BY9zz_i4R{}v5CjFyngWAFBugAG=LaVT6TjyLQHNCvK?o%fwSdgK@h{E) zZH!2s3mM^uArt_?dgXr%v$a->7`@*Ynsdpl{D%5P*$0llk3bdf0g3-p1*z!vB(vSH zmmS<7z>F9XCn>&r7s3Y1^^u!~@z2k%P=4&qIBLei!#JxQS{^rWq1O+s$fYL{w{WDB zD`T~dR|Ir$8Rlu-M^I@$;Mm)2^6)^elXEACUxF`(Gx0DwyOwQ%2{S#r8w#sQaNjFf z+V+*jC16}_hld`wWfAp)GN>^1WCS0no8%PWwy5J3%%q@{1n&x+NhjR>N7ADOm07}>>#6$ zxGVW%)b)nH?8dr%wJku&1^qzwBE7m)d$8b(wsEK-aJbE2Vebt$%^2+GffLGw`%#Tx zCb5mdXKM#fy_|D+sQ=xce6ghn4V(Tp7(dlpQ zA!Ypux4L?OSNO(FCov#2A!#)UeaL7W&onhBf;JMJtNj~SBiM+PuZ(Pp9Q;>padn8D zI+?Dc%mOb7-0MI!|8!9cAZu_9Ro7GH+~2bw1_Im>Z-BPfq>CF%Ug+qS)C9O1_HRX! zYx)9t)`>@@MTmp)br4U=d|_=Yn1JG1j+%U6Jl`3Qf6C^yiXg#=3d%{9^@_)zaG=ip zz!LSVE)i_^E*-le+clpBf}|e|E!oAwNQ+RcnxtZdJNY9c9_Wy`!B3xId94@s-2ecg z6XVq;F#C^OtH%H<&Va(?38f|Jt_P<+p!Wk*ovq6YJ(zfH#6A2XZG3ZG4e^)qT}_C{ z&;tJI#~<2X+;bSJtP4*^2pIX$w5Xa73X3BH(zuR;tm(DT$pEme*l9MkE5k(f83e|u zvvB~N0Z;=v@Cp}K9PuwRerjw=v+>I8g5ngjCL5Q7o}h+Y7*RcxtRey$y?h)OVlaNv z)xWJ%ki_eMfJGh>My88bNQ4cNi*9QC`!0$mHuvb>9`+z!n2#-^UU^YJV60@>a3ZPP z2vaj79ZZQkARspx&y$5(q4fMhUHau;1Rd&2bu8JLk2s<58I{VME-Wxbca}8zRDA1J z1VUXghkAsGnvYp?DHqKy%pRv}6?-M>)VTByiu7DH`MG@(2zw|ze$VoiL633DMrL4+ zE%>3c(l|<~qR{^?Nz6xvKOQG6z*S7;ET{H5{5?4N*Y8(&l)0ChrL?&+SFZWtsH#8iam$VC%a}Dj$Ep`+N6YB1zD_WY*J}X zvaXX*BiM!8)qx?g0;Q*h4FUpCnO6TA#|B{LT!Ach__`rq9L`N`xWwAupJuZy4jjKC z`4UXMzg`=p5^C;Y9DnEk)ww`|^nU#9-+r`nVG-&Ao!_)ipQ8T2GMlt(D<&bbmVKVh z`rgnpr&jDUdl3XvX}HFaC&akm=2C1zv*7eWUHb}Z-P#BZ7S&rPGwByX1ia)fH-;pU zqs!+@lgBNOQDR4G&Q;5=Lof6bet(f@iLtj10WYl;<&+UTVeBcf*DhWMwKVkmBSvks z5LsUKF~Ddi|F)IjIHpXU4KGWOyQL2H<-8b{LU7scIb(lb3^M~7MLf=#y%a{j)GJMn=yOMa$6?1ohd2Kji42zBxHL>7gea312{5P2iyPjq zZ(muMl9!p%2A@yt#x36mb>`>nK7f2{U!b_EX7+G0j9OSj>QSYIifR6K&u^uDGm#Kp-xkM*)eY=q;}&W8+XvL!ON3yM8e zp>h_0>o?~4;T-Ty`Dk{?>ev_XE7x*8rnZm;u{G*yXuE}BpfM5+^2ogR%A;A4>z`90KKLSy?_3mV`qJL?~Y3KdjYmIdmOQZC-CW9E>W7jc+ zj?DG`MmNT@oW(HbNG8?hr$voaV>g?fN6eP>$0}+ri-f*sxhC6ORpPMK@BDtvH+rL( z3knscI92d0XoNf-Bh8zT$&itSJ=z~-`MWH_c==b-AD;@Uk;5r2PEU*62DjBa!<^Sk z^|bgw!Z?daJIaSD^pRvbOXA!y;}z|$n-DD^YgIlF2hF6;;N^JHfq2Xz&;1W1hgGLT zgNItk$r%|5s$j6J1vjhGzas0osX7FVc&PzkWNNRk= zd+cE&cGOZ_OlmfaYi$Hf-yI2J5zk8Uh6(lnr-q8^4D(^06pL(Sgae{@RHAD`@-2!& zSyAxdM4C+gZZ~#Y(2OloaTB*TaUQ37&^@;hIr2~gQb|Zw))5gfrk`VftYh(6=q0z8 z#I^i{o$dXaFiJcjQLy#d{Z!>h`|!wln1=I0_Joss1Z;hw8YVrS)lfkj>Jdz-d_ZHh z)#~(&pP#cxvkO9Q8x=Nin%NwvgW4!~9iV7a| zh=gd*YS%qGNOr)m6szi~>KVOnJFzuPJGGt~f*8yI_ zsE}OCuLT=52$Dswspa&x`Y-BM1A$Nq?cfzmUHe5qx#ag(<%xKN60C@6#tfhFGth!}^_>3tk9mh+I4ubpcRHhh9nuuS!BS zg$9QgAnVsr*uYO|W_L^#uogK;(H{Gf`jMiV$tz?$C+`Q2PVyUQHbrV(o!rXP`3ffmb9&Y`6VQmo$Hx7nTMofF|^S^-Z?fAB^e4Jazy{ij-tCN|fccktw1}X&Hu+8%4V2tTxn-A}0`79EGy{Wn;xv zOy{TFMDbMen9dauyoyr(ow-)kyV5TH?9^7HAhg7I(*tGgwk~J127{z3tae<9bBT=4r^e1Zi9<7!37E77QFXcRo6@La8m}Nd~HcKW1DpcrY}Zpi?=8!fFpr# zOIeqm!@ZYn5B;8qZZQRn%+%O}uKqr^+58DFH!6|RQ7A1hhLxX#UvV>NuAg2$Nf^ic`wwBZjrBa5b z^--G@kX_2SM@OZxKaq1eU1gn-5*>Sml3Pc~9%h`>yi;D^ZZ}k2Jy08Zz09z(-Yw|1}65M+7Iuh5n$y7m5-9kvO z1w5uU_0fRD0qz^&^C{LkOy?cx6-buri{>yd3i2(}qm)e%j|diWPhdH{(V1EC3YMVI zvyo_Bbj~1hnL+yvF68G+Ab7sJxnO5hgUzrGNHDZfbt#8Sh`wHTWKME1ZenXtV6@(` znvOu(`a**;a{{@Q;<4ZdUt{?892aVk)j-WVG`>0%1XW zNuV82H{cbSsrz$(6aJHpf zP_x-({X|Y=Wv3g!pA)F8YZ!T?Lii)PhfVdA1-yZb1OL7@k+;{85T zqur#!V_9!xTsSG<5kOVEQn(psCCOT6kb{iyJ!W!Pr{w)dD08RyOthw3S<2*nx4o(S zFQLU}co6Fn_m?5n>hSerR(Ts1PvyBCo6%CUO%bPvniHtC{}{qw(o)>1zvBgXHn3~l zb+}qo(Od^j;@IjBJbQ)}CLQ$gXP#A2E_zngCEpqjR>IXy!+vDFIB6$nA1^J zUB&T6Wh+g>n6p<1-e6fga)?*mrpuOpx@4Qo|Haxnc3Ivn@0yjiS!vt0%}U$0txDTw zrL)quZQHi(%wGGPF}nAD#(B~E-~D2Jf%S_S^NyGi*R4c2b~pL*VS6HAyql9~(|L0m zEX+}p-AxmMQR7ceCfPzaLOOs`nn{-wDgVva+R~wK?6nn{DM(H=wOPr%c;^PASU~oPI^;>Amj3@hJnj8^r{INW6m^#MAA)2d4`-mZ2geHwgqGsymsN1@?j;AYn zUO{#z(Dm?;Tgh59uda!*OtoD6Q7v&_87D6{fJpjA)vS}sU!D^FQHG>G<0$tvi}2jc z6z-jGnbkM;Gl}05e^7~HQzFAHSQmT>#ue`?%w6OZVq0!>To|?1+ZSTEx_=`p*`*&r z-i~n@S*k9g@|>tk*5Fbva^S~Og9ec~NP-#CA{vPlZ(P1Q8c*wRpQytve0%sjgCA=8 zUmlvQeM>2UqGfTaqmamb3Zal_eMLFRlEeXrm5)%W31T)FSGBzn-GB)~_qkZNY;h*QQQ8yA0*BJ2PTr-EgORN5qq-FpkeTySt7221Xh z)KL!M0%97_Us70%7H^6dWwU8&98VvYF@s4Q-WzHBOR7p(2d55h5#P69kGQ!GdXIWs zWmv+7%I*kFrUr~n)Sg6;Ygpy1j*1R)JwiaGb}F1TXTZ)QZ7?FBwiw17v`0ifJ*08f z%|b>e_@wzhGu3C%332tM)V-Dp=uOT&9^u?JEsW@Dx7}8l-ROE18m`uWFQNuCq&R1k z8mSm*4j^J^9G2ISs#d{g_9TV(j!>{*Xsuodx)L5X=iNN*@9_@JqI%4}^% zU18KRuuj#niT`$W-IG?Oy0Ho5nV9OQm1gbApBwgApQeizS0yrHfaSEedUY zikfE)(U7l=R>!ZsB3u}+2kGo^l@65i8q00O(;_~Hz1UT3!e&=gW_v|fKcid5_G_bE z_sFwE9|+b=&T7TlK&|Z$Z)6j&kphtde)FW06~Z#9Uo7F$dj|{)$gd z7<`9Urf7xbE#Ag77n5d{T^5@OwA4WQ5%J-|Z|qsZ!3 zv|ED;R19+z@T?O#@HSo*p9!3r2`%mKcFPRtrN5;%iszQ8aipR3at*P>p!42k7nUV` z_-C&YfcX7bc3o+*>djeCy@&0})|;JWALCt=R6h%}>MsNc;Ke&Fp5%PrqhHH@^58w# zdR?`r24xjFxrF-g`MH(`uwW(^%o0_od44Unq)$NTO9Ca-G}}^enb2B$LhiVds)Rn6sVsup=DE?8!nFH%92Jl zU`69yR=+S&R+&sCVGJhZs`;8iv5sWCmf1M%_W-hoo40$1nkzWSUtXhhKI$%YEKFt; zI={gB37VogT%wMhH45K9Kcfgxkf<1>gPZ^>p6OAO#7dB=@gzJV6B(L47xA1z3Hr7k6QC&Rh3sal;IJnX%oV&2DPFFK?E7 zuY3qy8yleW<+q2Mg9rKdIp!@rI>sb&L6Yc%SwXFB;M$nVj4%oack%kXh(R>0>3#bq z89BDQs5H0U;EhnIbQM#7^!gK^G?`Q0YX>H3NFa;CTJrj#Q)EP-%4jE&O@xYXi(GI{ zp&LyjZMdKINCao9R}8uu6lgwbK`7?2RJtm&1(pk;T~g9McSaWKYK-~MlD&I=KVT0i z#+Qr4l=qo-O4FE2FeqwEvF&Feew{g2;0HnV2Ay70{9+_t+&I-&&c=~Ox)-%EzZ0;v zmvl9L-H<7+d|ouOjS7&r_Yb)>=9mEePB)0da#1Ab#^q!PZ1yT^Z=VFU=_MEhb`(hI zL7cnb+a;8-yHEVdO-|*!M;4k*q+0RnrJ`ZHyXL(6+ZEFw09>3FM<=dyp2mA^P^WHR zN$N*SY2`(1FXK}$7p4!Mt!2kLSa7MbF@^oF_%}DvHK4d%iot@jy88{Q-yJ@3e6#i6 zLkAdoj^DIDu=zD5p2qU)t<0ThQ;Vmd^?u;PIdi@fcpQk6%a>9ON0x~Dk-jHoRS6j4 z-q;6j@F~?9=5dw|N)@^rU_5CTYAsHw&^boZG<2)RUcr^USpt164i+}|Tsgl)pYGmp zk*cvTz~zeV@*MKNzsHjIoy z-qRwOC&Pl*fhBEztA5}{Yx1oX+;K^B8|_TkW2FPzY-SmU^ATuP!FSmaQgnILzMFzA z;6Q)WEd?n%L7u@}5~=tcnATR1vL4puV@@wcq%XBDuR4E?+{I-YVnPvf%d3ERfO&t; zCs+QZIdYh)6G{WP5}yLA@8r{@a-LBYrB*4x-VRY={7khC5_8K|MH!nzZJW>8DZAF2 zTA>hym}u(5%bPxQF|q9vmO$v13H2zprzuI>HnbwD&zpT^o+96IB9J*eXj_Qn3LUI=!xHoku57Mic^`-CK&Ec z>mk01+FMvKwo?3=PmzUOQ zsMp-GLN%%CWuZQYz}r&MP1-3k!8p+3u8)o}Zr}t7#Pmr-kS7wX^phA;oUvjrUUhI$ z+Eb^vJLaHQ0h6RPm~0FRvs#=Ly0o`SWswwDt3-i@t(+TNl9@GVZn6v*2zL-U3Xr}% z`T1A4EGj~ysIs)fkMLNh6X;uiir&T=Z5pIBH?3qDv|O$>I}OY|ruFsMZrWA%zNv|u zmhWb^b;pmfP+Ih#bS;E`qB7M56-SH}K0Dq%)g7X`P&B4!(=*e=ucs-r?x$Ge92e%Ho%T-b zokx9!DBo)vL#TkdH`fJsG*eW4b+FlZ-i;=hU#WnZF_vJ&wW;sY1@ok=Cvmhe-3&u& zRahl!>`u%uF_6%VtsnTAxxGhk=iC)Bc#V4V0AuV76)!z%pX`f4^DjWMbs}Pd-Vds!r^h z7^=^6b<3KRmXiPIQ+y#cDQGFR%{-Ne#dbxnQ?xj)X+`?E$!Nsa)7H;*eRMY2!n>Yf zd;Tfj;|+gfuHeMsjV11qCA41cUkabFcGv()2^2(^T27WGYY;LPz)(&F^19*?R9b6J zl_SVYCHIyiWcs9|4&1g*O#^woP#R!-X~5pdz-_Yhi)!+x+x=kZAyI)i@OiF2C;BGrAR-`@r$}X zF4vo#^u`LrL~y)^1@1lVdc{B(+*^i2LtU>@0_ai7B}=`=Gufs5m5fDowcssGl&R$O z0~rE2<;1pc#&^c|)BCaL+F*}4PuQJLa+pf-=!}q6VeARE?0rhSbCS!gG&11Ab@i$H z?YZGMGp7F=4L<1kgorwiS$=-mG@M_Zx%EsvL2V}asYXRJuog6W*jz?2bEo##hK&d$ zR*C_H?Vv5}RzSm%ctG+Y$*{@ah||U*ef+%MYj47aDfrW}pogd+!if}8@ZWUz1}DxB zZ#Rd07Ju{}@rn8@F1{PS{i5fln9{!ZCvM3DL}*$H{s8J6?xmyGK9?q=9{C#qa&zF>Wiyyjq29| z0ri*${^0Tgmp<8P2%~)i&Zqxvt#*}vh?y%ky)|Uec;c+^s~@R7a8sx7ZlUlPx~EkZ zp&YVX8xYdN}2_{S5@Z7+dIM?bgF zdF;+|_~S$R@xGLI)F;88r7O21z7-6*DZOr=DKBGentjkf__bkv$bD4mT**sIC!n|N zAJSFn)lbM=atCp@nNE3n&tVBZKL(h4>hU`d^!{@y^3BbbXc+(z0YUyBo!oy{mY3=P zQZ*Z@?{f7HB0*xPi0%7HF$k)bENDxe*=T1jHKt}hZ9Z~Qf-;Vgxt|vTt_2{&N-%q%89vu@gT5j|tt zl>Q=8fWsjwENRv&mnyohUA}r>$voJ|5t?2eVfu#aofObY|A7qcj6IHqKK2!AHB=H4 zh0qE4beb99GEkcFj%c%8=p4#hj{Xq*T^%ZX0kQeja{O3<;y%r>Ne;}wGgTIpAGy*} zI@yvRkXT{kYh**bLS`=`#boePDN2f*cAOu9W30qFq=+bDFs&yt*cf@dj0PqTz8^3@ zZA+3E#pjrtlE|WpNIdbFE zXp5C30b%MH>Tbmcc>RjbiE19iCv1l@>xe!ukL9L|B2!ZZjH26;HUV2!j^1=WLcbK0^ ztCgC0M}3MlS}ptj&r#Hl{V{NhZK8w8K|Wz{Xqs|W(X%HvQglGD2nmnx5-3ohuz6>f z*S|k?uw^^~n!<9KZ6bWjnVD+OlP=%`n!nJV_~1L^zo%e`nq&J%qCe9uEH%jABFG9p3GT!Q{I83eqH%@=D#i$zo(=rVFV^g`rA%geUas%5Lwv;wbKL_s0Eo;3KZNG!2fat*M z_tfV5R)pbGuMI~$Bq}V44s1ExSl|RcVhZPk*WWFKsVY84w|V!IlX52YM@G_4@dgy6 zf*8eZGIe;z=uGR=O_H$Q%Ookb(mjVvOekv)+%ahhFcUzBkS3k~tk|(qQ2d@ap`B!z z$udd5LLqCLA-jNzmIPY?gGh@`?3T61==uP&Z7IxV%k#M(7I253FfYVRk)He@qnN>T^s zast-!FZ)nhfxIZZjAu^FPu4OI`7pSgKA zYz?r2IErr7cqjT^#&@-zt@n!+pNEZ65Ho6X73Bx9G5m*T&{Tl3?OtYdV=>G^CjjmZ zw(m1*Yc^bGNLqUinR^cFdxYk@jqBLnD=>8+lc-zMf1K*lex;ePQg(S;5ET@7&@+Yv zY}Mr_VD~OQKGfc|6aT@hcHwqjk9;s5-wH2QQ{qXze-`etMV($c4|G{S&0;?Xeu(q` z-Xyp=`24>A#5j0Q9PkMX$>FD6KoOMv(EELT6N;LtIS#Q2`t(7+PyV0zGCTq;nhLO+ zq4D3jHanRcI2r>yhyKHGs8V_Jf8kG_^&Au%DOX?2pCzE-AN{s}0y7E=d#MM3u5?#({~-#ux%tQkz0i_g|crp}a34OOyq>miC;8TA380py|h^I?|tI56DuDhC@8* zyv6lEorst)oa8?w^QBdh7HwH@Y}qn<>)o(1+i{v2E~wfc7S!Fv+R}Wln~~n`fmurx z^Kg50-e!(T_JoqNI)aSvk~YjvKM%&8zg{@o^=Rr|jqYw-xH2PPz$v257-8?+0`O=8;7`{@b2lY`DZNulgc8pUFF>t{$f!*C-v zXB+$on@4&Y5}LvSR0?oApY_^<@i?f&h)aA8#oBf3a}v|U=Jni;H~yriDP692Q`4XQ zWq^-g-utag8dS5c)dC&-VHA&5-X6Ccy4fsOB8zfBEbRCg6r*`4r@w=wkhYi9Ihk~4 zNA{J+0;}ohBW4&(nvQSIJD)w)!JWW~5nNbgv#(xwPUHSO1h|EWjcc-+00wz#1y7t z6updw8B1J8dM~%QGL(LwpW~t(DO9u}(Y=L#Rza|HragKPW$X{k){fwD>SXJ4zukYv zpb4^YSPfw9@)Dr9S^o>Q4TwK$6K6YsQ_{Z!0bP`OZL=58vCW*Xbirxw4YqbuuToAxJfJsKokyI^2H z&tqBq#FicXmBem_R`i*1x@*6ea2*tZ-NnJF3IULW!MF==jic8AFE0)Z_V&reD5D`K zB!tBY&JF*ojAGJuow&bD0rD{V9e)w5CIdf3XDM{&vcS-Tm;TAX3}KHR;GVKfb!@!sTE&;s@`5|b-9+<(Wg-%&?RIG>=I?^J zi$>F@0Tn!+G9)%X5vU8F8QClSFpSybZ=sV;>gln?cj$J*-+#t!^3Q$!La5b}H$W_m z0W{qIEEfJ)-yW$&EE`T?P8NyOpuQiX5VAL32jPRxA0V*#} zC}OBESr7LE_TCCLP!qMO!=Dw^MYs-JPxFkD0R+0)GVplA2x_N zjZL8OQ|7~PeKI6}X}0CVx}V>Dh|w z?3$R7j(gaE5|bNb@!gMc>$VTJ*uB(2BKYIpi+5u#16%|o=x=|+2)o%Mo?a>%ccY4% zb0tS8LCjYq(uC=q=+E>+6--C%J};fir=gun{@)mfa*E-+Q5vF8WunkLvR3YaFW?uF z1?*L~;UZPqzI__i4hO^=M+qpt#Xd2EKkS8qyXrcEl?auC$nN)PJ6p^DR>!|7j;O!TZRY)t@Wd!}~(k!P|K*Dd$|1s;7wtw(kIJs|fyCkwOQ zkR(6>vpS!xaOgl2M@l?;9@2E(MNI0FI72&rH1zZI&n^FUltxD1tertdWpd_Ne}I>Q zPY8Wwb(Bj~5c`}5HNIvnSOZ{7s!OPaZOB7CbIxspsG?Bd(jJ(9hRcE_i@ZK)a5-w} zU%AGm|55b}E=f^g$kD;8yG!)zpX2&C zE>l9I&&Q)>XFG#7nqOWTQVl<~tJRbo`=$!f%V-ggh@MiVE@v&P<}i<^8dUYG3Wv1M z=15fLwQKtudIapM;A2MOMRgNp?y+?G!LCkvQH=6{m@315{q4x_lP=3NDHa^(W%c%e zDoE4{$j!$8P1u7z)Q;HDEAAg%QdezG^R{FO=_;K4SKg2Xvxj2uGS=wf19l2SLo7vf zQ)KX9#~0_I{#Mkxcbq@%&v&;Q*0MZkFRT6W8kR+7ODy#vk)uEJ4-d^|Z zWf!A^^Qb|moys{G!T8@b7@VL+Z`sTsKU8V)6j$W93~dTDbfz()3^$}{1SpiTS-lbQ z>pw9)p&s5czH&QWcehB7@0Ucmy!Sso4`SAQ{a_8kEuiHas!4t7Ne^B(KcCxquCZC@ zl%vM+vK1L{;NI(X_MO@AbZeNE;rS;fVwi;^=!`ug=3BbvQyDmsdqicE;JG(#G@pg zbKkzyC9+upc_rkl+y&XV(JSVlX4DIdj*zC=f%GLqsOF)0 zPcme)rWQmg-3A>qWH{F20jL5;E0P+g+9rXs=76-O=iQvgc0LOcy?tXPf5|v4p%%FvhyWGHA%18~I16f@ zNd}_W$5lsg2o`i-a+6bnFdb_!km&yN*4^W|=UR<=Eok(fNV5hWsHo4*;8dTK%_W8b zY3XnvtI=1|CQ^sbNXA5~L51u_pT2|fh@3>vYFD-*x+lnUsBGqsX!jKLCY}u8FdP>S zKA{lxxxHSxG(#8@bLbty&ek0t>qKDBSoa9-O*DQTgw(#S{vq%Ze9*8P0?Wzcv{cUW zXCXed-8K2DvljLYTE@ieq+H2NXI5>z3s^>iv4rrwhceUGUhb&hA1BAs!{9%s3;8zT z_@$y$Q6kCsh^YL5t50P`AqUz?*55Eb2~VBE)6a~=B~#4k^ndb)4|yyUkA%Vfu&fbT z9H0Wm%MU;36p&RDiuue=8aPlX&)rGSi)(3Z;iPbe*ObqsB9^p`VI)H zX@Fq*FRUh=oDCeEUF`Kt+>K1^|JA7cKO<9v6&3zBwxYU4VFgG1!Zp@{k|d`2r;z3u zQyY1K#IgEBN|duLme}`uA%|>+t%)b%oWu6!vyU5%^R_SQ_Ep zhdUjPl&Q#5fYr}qGReAC>phhdbnJGyr<%Kb9)uYrn6N$9FNQ58 z%wvFllFG~OsZfvNMH!k(LYJjSsv3~f&u7V7?2vT*opsfnLvC($h zeDu2&%vLjz?&a=Mj3x@c!aey7Ao#JhDV`I?T5RQ?xAYi5-mD8#zYx?aVwoh#UC&>e zc-DVp_)#BwFlN)%F?mVUufKnoYDB3sT+UKJ4HA%f%{n%xGNs#765ErICl<`a1iY`! zigSP(fUd#v%kS5aa)Up+@#_utSpddsTh4WKs#;#qa03d)h2QSGM(pJ=BH4>R81A9j zAe)x;J-e~c8dk8{!B*F6c-keS-|4LL2Ib*t?uu7EyFhWU{NAl$NkNwh;BHj@7Mv7L zPl53Fs#?flcAAcaWa7@@Da6&P`K`Nt?ybLvRL8?BU_^uWbaymLbS{#s>RzR1<)xGv zUU0VTZ{L_Itl;3?dsx z1M#y&O5VH^wkDx7(iMVRHTgSda78Xt7t5CCsPokn{OJ8=8RhKA+*k!AC`;rM*OYc~ zP5lU(*kW`g0PRBlM)4vq568lO`P#L=Vbfuk&m7}lzgzz(u8&ba9+^Aw z@D{@)2ct?T5<%(V(Tc)_!XBB6Peq(s+7-^JG%J5p${3zD$f`;lHtCAEPPFcPOXe@M z$f4;UR6-TE-l0+4CD)m7Q8HXdhjjBoEu4Hn0Mi3yJ78lmk-5cP3xT<4hVTA)4vwK^ zOKUs;*C^{yLVEy!E#e%MjgVd{nGLgzj3UPFnJXDlFf*nO_b?cpG>5mx_Q+| z^BZGuMiB{At+*ra3VCc!ttEo^SDRnD_9wX(|HfuF(!8`-u=8PazXH8qm{rtDVQb|KFV-+tekQ3f*gd%A ziQgpbA5fbrtLHZYz=xa#{QhSj^50K#aGZj4|G&J6@2Tk^>-??Q@yj8#v{v+E42oY= z>kf+HtR*FFONBqKi@6X*8LN-8vaSK*^yc!giq}Jl9ki8TRlC2VVCc0czm~zjW7RDP znyY*UgcTCz7#PSc!*dsDNh}}E9Zdct&;i|al*Is_l{f}cNXpGRnD?hvAX{jf`r%G`hf#Lt-&4!x3Nb=LA?Vdseu&~5bTMCLx@qM3wQa364( zt{f5MA-brT6Rf*eIz3fywVO?0&hFzy$M#CqOz%(iB(U}{bfa5*wU3E0;SxmKXqYxN zw= zGpqKo^H}!-{&#smR^|FHYLWj%KhZO>H3ooC?Ck%e@fNMv`>#@@^PCzST3U$RwSAZj zRdIbrfDQYs;bQXd9S1r`Lfnvx@Mw4S0f}tg!%VCCQb)=2gBVTBZa%V2lWLV!Kv3de zzutx-O|4-bhUAzEZyP9SbCq!Pzhdq)Ye)xe`7v5St*C!-zJf3sd`ID=WJJ$3bm#uv!m7~JR+F@Mh6_zir zaMuOZMKzr2C20P+`w%yGoY0vuq%Lf1#I5u+%3egsimPtK(h3okKFjXMeVMa{=b_9c{#NPXe&*>scwf(pm-_m1wRT3M zc0>U4?>6yquMWD>t|QRzKV#%rev+CV(216;M{HRc~{un0|T1*h3(hXA)9*5eHppw51yxng;4y-KOuo7UXNIw{} zp;w2}WaPyPHf`CpHSL5;mkNYv@rKP*8`o>GBB$}c@lX-Lm#N8MC7{#F=a|4?FNDkq~e?pmTpz~>e9kgvLu3UD?&19GCRvmJdn=ar9r2+^7GX920=Wc z@4-p3zU%VQ0WGn) zU^epHcboQ~eFxjQktt);3KIuXzws=;=p)-0+9?VF#90)(@Xy3V7OJTf>q*gt%hWoV ziVLY!h)t*ComSlIKL58wQgpIS#7E#7H_wr#bPuYyjcnc?QK;J3yGU&y9@tx-i@ z=2R}w47i^xN5JY|@FIX8Zh3gX0ohDtc2A8N;{!76e!cwH~JLH|6E+7f+<>u zv$HGWwtjx9DVlX}a*x|oFsG}4%MlpRiM2Dmjfa(zDATBCXVX~^zr15$?V})>N=jR$ zVEDG@{-*tU7*3_WkStSewv6Og1uOf{2< zr#gsMOH{Tu$G;WQVInC#lQbRps?TiF%L++D>J0=PiLjK4pR)XQs$nf=E_^u9TS8rToT=DIOQ z)=%s#n^nXWc*PDcZcH8n-<-Ek%yR3KGC$kcPPvYohO5=bnqOpC^)_7tU+1cw>v4Pr zQ>v|gRdO(i=7o{YLbuQ>eGj~n^mbih+Rm8HgB4xfOhm_D{uZ{dGWn&S-rGW2fOF+T z(@(RU=`MM){P%KH)af0fIo^QJ7oR!eap-aXIEDIQS3Q~G1$+p9NL9l;P<;wBS_>wz z_@(*=)OZNB_dMhjHUH?Rsz%CDM4@*5r=Q)S*eB6NrCebDE}QG;^wnB?o<~{&sq{1e zWJ_U0%XU4>&9ztpajVMgd)#{e53!`iD>i5dxU2~Q!$AMjWc=@PDOu$jFjs*1S=GIF z@uSjaMU@-%a|aX%nOqCD&>yK}{kP38^HXD_0*QdaJy6l_=j^|Fu4Q>)-RcLMonGG0 z6krCB;@w4a^dZ+w5Yk6`7Z@!R+Qm_D6t@vtW-m?lX##{OEIUj=(nS@4(Ndc^KZCUJ z3K}?qw`bL>NW8QB(jdAf%>yB6VpOWqy>}fUC^3|4HFdXbs*bN#{h1I^K=kQO(oCi- z+9CTtefhUjHjlYO=#mfZw z;wC4IX7@VhSoruR+35(49z$rU-0i}vv2Buva?4|Kn?Op|;Z&M3sul#;3H}0ftD$OQ zewuyn&|%Ly)u}6wkW@8X;jUP0SCOTB{2VIzx`nGk?s<^&B^1(U70`Nc(Kr0Q6p>yHRgrj1 zTXyY=3rvuebcx~Lp->ySGXsQ0sQ^2g@o_Hjes#3DUOi5))jgTWJ_bgmQ<)mt2)~dx zG|t5O1$(Ao_foJjM(mU7luN{$^h3>^{8b-s@2Eyw)f^jbxsMCjkZ#3!(2zr?#RM%J z4>Bdpe8w@@VUwHB?YqxYpq=ue#8Il{F%Gg#LneO+rgXNmaPkM*(&SN?x0r?d2fD&Y znODXoOaqr_(E6qVA-m2a=3NhrgWTyqL=YYak~vMgwmTjNq~*cOgQ_>~vq!H$yY*}k z$Gjm`^4mb3Ee;S0UuR#*%KN9~Y1No2E;c9Y&$&KTL+aU*Ds=7;5!SsU%SBrS%Zzs# zB~tfdc5IsBe*AEM$Ds`F8#(~S6kVVHzz?1)o#$NxDppGXevswA6;qBTrvIs=lKxk7 zYtSp~g5R_0O)fk#v!)NJullhA;;!l9Po=9Ii>EMPW=`y|nKtP0Sq; zr>K|lLjYhyXrHWGtbk3XO9;HLZDU2I7qlTjNTs+zf8AAerTA_wXt5*mV?s>4ZfdJ3S^AH5gYxNQLt$}q&q0E(2k}4{&3pjguC{(-%e(-@xBJqTK z=C-m#q-LGv+E=wsh+{#m#CV&oh(B*Rn-q+eEk-Y4ueos`v9G;@W0De%Bl#-2>?8-? z7)*7%wEZF#UhPQT7c;mnlNy}G1^JA1bDvucvykZ&-Z!I z1l7B?*!-tJDUIMfmFNtOA~Od+$Tkw4@tNVvv`u2@ux2abuU|1!EW95i{^4FMYhuy? za|w1XP! z?}LK#4V>=X%-K=6gs`T(VWX6}L8l6)xekl(qG9SeXis<9zv|OI-$9g zo7899n2C{eY*A|oZUi7!n3Fmc>}GEV6GhwNTxy52Jn*%2Q^tr3E7-V7jtv!67Ey-7 zXXWpB&HJaV;bzyK&&KoOe*Z9K8wXb=y$3vGqyrqf{zoV2-><=JH5;pa4#cl3y*!&d z4vQ^M{CN^__RCFh&mtBtz(o^fI9}Tm?~}06pmw)yXFOVW!9m*`B0w|Ab3YMjYHY_N z7HyV(XqRP+5}u+SGD?3^949#x3=z<*EFs4pOoBwE4)7R(64a}gk!YAQY#q+Z^}<3X z8~O1m+LHTISgl}mgnIJDN(d3Y-#XRkNo*B;kOeGy@$SmNhdrSh*#sxJ=ZC@R;si3K z6C-Xcz&FRdpdy;73m3a_hboO?F{gxODYn@U0WNr#ib!TI4Vh0=Z~0kRe=mC;Gi})1 z&y zi<&vvp3gy5kUC`FVLn(98gGc3$N>il7s|=zy)whl&LN!PPi#}KV#B{^ztVuQ?!Y!@ zQH4$Gm^dAVOn`xw17@AeiUKjDo_Hgl<0OIi)Zu4Bf?5#c$QtNK{}8Bhe}JFYkVHh+ zrVK*X!_wFr`RVumr9snIqpT&8jVHmu)c>2QKv~?n1im%C*s)T`lI5wg2BT0{{GA}s zbqG2c4RP4#B26=q76$|-tuBN#`3MY+GV#8ggNBYQjddn_m*E7FbC~YV4h&Q%Hg&Pp zC*DuJAPf!toV+VrmLUsA`Aq2M%3wfo6+qT``o<4ZblM z+D}}zu+E`fQHtG-MRXcUZ2NAAQ^IP((PYNI+S-M4geov>FAg1gedPj;ZRe7q*>aEm z`?9CfaAv*5H_W>?xa}a+zZ-u1eFq<~?ZoHebr{oQZu=#zxuXQF>WJEh9Qq??&k$_< zc?(Jxkz4``Cz*yF?R*A=R)_f-4kc?Opgtsbm!09r%cU15CZeE@qym;MS6UtTp7So7 zxfH=|a3E#e-ai+tWOJcxEz9aM-q%i|?066OE$Pls+;x}kIo_qetW_5XN+63R>)dr0 zre)@C=bQ6p@OnH5`n=acU{OiUv;X5B;efkH)?li`6}*NARrcKz`9;&rHEYT=PQ^J# zdKEt#R2qU>lbM`^2gycgSVsgd2l7)1Q7#EbPz<_Gf)O(=8;5+EXpwb#Ipom7H=aHby2Gl z+cFVdwKJHadDL4!Dqd8bp8|?kZm=qtch|a2Oi)ONf|=S?v`|bnOX`g_3i>kFbq~3O zk!NqEU4H-4NB|ir2Q08R;h|(rqY7IYD0=m` z?Qi?T;YP!^CAsVlfP|p9oc+uG@fh?Pr($(Ne^CpLMxEDRCEF*^`P6w-j?YE(;oZgc z?Ihleo`tBaU?d2IX+xMc=?_O1^vlPpk~!*+-IJCx6$i$;VCsX&vOk;P;PkW>0*e#Oeo?4>WUITUBUbRUY9rP%>ZtPH3pge4<{o+OT$3*0|l{Y_NM=ZHk&5mtkN`U=-N zLjfioGT2`eEwxY+- zTR+#2Z0%1)+*N0DW3Ex`m`cOPG^(wPmGkVjY0O=NKqy8d|8P}?(I`amSsF;XN7NvA zI&(j!FLeTrS_D$^QAlxyUZ-8s!zxLe5=^T>mAYw06Kf6fSrZ@{z_p_utpFCzl?u#e zT?GLFEy-*>qn}>`Lw83q+CbwkZ!$C~v$nd&J87kkso+wa9f=&cOG?E%$#C*laK0LB z`+7(HNT}WaqrYKV>Tt*?ew5){&kQ*22|@(s-@W1^i37! z&bV>A?C1HFF{^bmB?5PGRB$y;sqZrWSc`lldr7C$5SW}f*kX6WTl;F-?Cjx5BtIYj zrz;~CHZ57>+vwv)6^o}@C@%yX+i$t`vDnE>*^+M|8!rkIDeR?%?vQ7FyK1hLhq-mo zDuKd=t%AL=TnF8rMFS{?^7Eli^x$cxD@zQQfz1`@tfh_xSA|Tl_h{dtmWseCX=@CZ zvUJ?xQnI6NWW#U~bUx+&0A%6BKA5PXL(Ml z(wR7Yq#E_^(H@!38^E+$!>luX3;m0Nm<3Il1*+K~Ov`EXuM@7?Oby9@3VeXu`YfLG zFS+XfY4@q$f`ZcsrR_sV^ z4AlBpTNGJdZ@$!Sn}z~zg7b%ECxTf~VO&eNd5y8KJrm3o_Ef4 zxejV^H0174*S!Q4IB|FV%{yR1+OsSs7QtsBKD@9Zu)O5l5ObQfN!!o5Dt!LPhhzxP zX|DXr6G@fKcp4nxIkb$m$FqWy6j+ZK_dv#oOmRRtr00?`FF%?oQm zNSFEw(7*$f1*<3flS`0yw<&B`!Ab?I-rKL9wM6Z`xfT2?OcHz!KOWfkpPoBdZM6m~ z-@1rgbiM3uS{?JEP70Orya3F~P%&#Aec`f{eeMU0UV(HNjFofK9L;@$>6d&{i)lzZAS#UOTr#HId!!HSX;{n)Q%lKIl_WKYk49 z{8u1uXA>KHYXfH!J!caq=l>^{|9dE1YTMYYjUj(cRj;g{G`V8umdw2h%}K;KC_0Dl z>d)QJp=iXc{#F@&YD_I`Mf(1ndV{;cwi+f0Qj%8bbvH9JH8VR($1Rz)EohW($c9)> zn}S4U&7bBYG>|iGI%nPKt=dIeZplI65p=Q&&=E1k%wB5}k2Bnk^O_v|Yj?78cSHCV zp)*}W`yhR8RK6?UPl-tkunW)T;1avs%4sz=c=xQ{bP=^A3#p6|%{nK?pOs1*$dB!dSB|SR&O8mBj)dg}w6u z9^R+^ksnhOX`qKGeIxj@ocOe(Bud<`OfN*Zkv#HqylTM)r)NJTSUT#rB+X`)JOkH~ z4`~xzr2g{UMANqp=?ZaKWQp=0gv#{&ENdL0WbiRZ6&0YK%IM_$sKa_m+)PS zWwOS=R@Ud6LXVPG@Qq$bn$dvwq@_+lQwia-nZ@E}O_*r2kWkxNQxAO~EWu~Ykxc^; zYh%O9cDsbF4WK;U?T;P4jr=5iXiFV}sH0wnd68@~aX4TwYMx!?N9`_Dm1J?d?R-Dl z>$750+5Yue=93rZw?>DZ7wcDKc~~1ue-|t+rky~T_5<1b=OA-CEQpm1O!nx;aFBIm zh&zpI?aL?B-3IzwILr6=$H#+OmW1H043m)jAMXNqB1aTaULYEu19^-q>9EpHCw^R+ zT5p8VfM(YGvNh)g_RS5YZHSg=-@ zi67LI!I!BiM!XOPm#Z|{w&VGtnr`o2CNI?ai)J^CXHKyf{PL^xCeN$kNU4dRpg-j` z)~DsW%FfZ|5Jf%i)^ayk>`qJ0HqaWa+ApS7%8T50c@q!!(iHmn4G?TdYpiu%zk_H8 z(S!4&54WwBy^;s6|FqOCh8|);i0pGF)iPj}cf%03k_Rq~9U^Y{=l5jfeK76{pLzJ% zQ#~ZRbM(h`7ta3HR6@v#Q#aiy@-CIwEMgl&cr@d^OvR#tr=tt10K%pMLbK!$|LKDA zkmizDJ8-Lhq4JF*b=FFP!ABB1Ec}KzOf_I?xr6QtpQauL;V&m{eQ9cj$ML<$+m9VwpD3W+O}=mW~FW0S!vt0ZQHhav-iGd zobLYCd!OI1Vyt)0h#5~4R2$w+@{ zG>P^HhNq*zYxugPG#-zO!#8Dz-$s{HR9vW^-Rb+TvMXP5>br#`)rMK0^Pj9y5YzH7 zi+iO<^#<#go(*Z#n9`xINJVD^Kgsh)lXTj~^z5pIYMIb%&dsbFJ*Jw=tZsj)u_#{> zYlbpxJXJ1bLzh#g8$080A7s(+^;jx{z)plPS?xp_mc*>z5hpyu5;S`ZVDK#Xek4r3 z1zmOHF&XWk1V{^aa+r}e=V;X{Cic@Hl%+h3_F5NDtec6nv>qk=C3dR?-=@#iW8B9l zmAEpREF#TrR8I#7#V>>TgoF_Kc)}?hqVokMn$|E(|2N-M@xHYjUK_P1rmmm~dI1Xd z*HbXpUm-B;miz!Eg7(EOLyK$f^Qo_BZMaVDM~UHGQvW}xH~zk>1=*e~p|!bt0o{mQyDwyW z!U#-D1E}!u-JISjICTqrbO+m`gk;w%e5PPW)GI)*sz@a&MDcmZA`xRVEQZryn!IWb z0X+fsv2)r|UMCDBX?mLl-42RU3m&SDI2WY)_FK^)I1}LFP@6y`Jxu4>9PFn~$f*MqCnQ2PtGFm|7z0zX^5_Yko$L6q7kMsIf_EtnniS|kQcoY~(lg)6>*g#2KJi&9 zOUvi1>*-LWOzh;&>5}*Gyxc2kh8wt?Q8b$AD>~|X^xN76a9Za*&(8Yq?)F~Nsa>R8 z-$oNHBps>XBdveBtAQmA$_eEjP{;p#rH=fN`SbXS%TvGI^fRqD^;0T#TErxI5f#lj zA}Gn~GD2;TEA2d!X2y)cAD!6yR8*3N-G|{)}6i{$RkZ$;v5G^f){J z48c`dci$wF0a#-}PqLojQn8A1Pa1aFf#Mo{UB54hs63SvS}-p4hM!)z7^+Cqs6S}b zXRf)|pEOc^s>{07JDz9J6WT`FW+p<`F8=x&?;KYwv^^5Xs(5keJy*JRbn&Fog)Y6r z8u6wUs=U;1q;$fc^w#V&lHC0ZpuzAy?ro520HX+U9Pu8(F-XXx^V3@4A9(CnS_0~adV4Xg5D8bM7rM}uz{D9!{L-F}@*jdC8D z|K?pLEIW3N=3VD56y|ya+GKO6x21~lU{|PW{xQ1kO)0?E)6|tEU;n!Dh0c|K;REv% zv@-ATI0w+@s+iIbln3<2Bw%yR&!$mv5WO!)dDpbHzQmND4IJF!#?*`3RTL}01!tJ} z&5H;>#q7-ubEF2FFIQq^M(|{?;hK?2Sa6e!D5nkuu*`-^rpY z7Pp4+QU($NB(}Es2st%F99jlN8l01TxgRb|lpWk=CbS zMQzCQvo?1P{3f2mWS0Se;buF^khd|Q-?Dz`Z+eVIo)rvB6BeJH@4_{#=H2w^24Bqo`@KCpGrr*y~O^J5B}EC~UlA?a$MMtUP_o2$R;fwHmh z2=jsFDzRcro>5`#`lZrKQ`h{2I~KLfCd2Hi4)mkr&zVRC6o6F%B@Oxd8V@6ozFv?> z!CbJ~x(KSm2f17x{Vjj4iq+n+h7}?y!sF1sK1$S^>L)p675omEiktevp&1vBu5f4X zA3Js|Skcbj;q9KOS=$Gb@HE8OvGb+{Y}Quc{6vKElVV^As>|*051ZW~Y(6c?u=X64g$~U&Esh-v8FskAlvu zkNB~{LqFB{zpli8wl7ig|LugARjENF6lh%%sGfJ4z)Sb{_)da2Tpy&#?>NwiHfYDp{Hb9~?X*2Vy$TbABf%g9dM0TtXOA5)DR_0X%;120RDE zd8U*yI{X~!MXg#Ug9=5+*$f_@FNF8vai+2iy3{XOQ$8~Fr6=_3YFxTKXezdAKRbKi zlu?D(0&0zeGvrb48oSb=SEd`L<&eo3Wsoj8@C$_;u=j~E;Oe{zt6wzKV_x)bk26fE(dgnVOqdCiH_d`zQVGfjexZQ zdi8v`L2NtRDC%nLQmU$cPT+JjE`90lSw(T$@{w>h}omPgK_=Dh5 z`#Bsh@IU$YI2fCn|3rG-bj^P}?7z%Mv;Kc*!gIAA7eOqrsLgW;8<@f{Kai2QzUii~ zF#<|hQ|MTth=NN!>H8&T#|iDY#iLQe@sMMeBO!PKWSQqZo13u_G8EHuApTc)l>*{W zB)soUx?S&xB&D6N0+wE|Q0Qzi+YwOZUgL@fOuomS;n*#PS8rrOYF^9}xJS-{8dYT6 z@%t^y?Fm&bb^|G*-Nqz3e0dN}7bFVfK>+9oazJ05TxcL?!l-w5vu*(kr%6Vbz9VlN zKJmF30lUiI>TfPq(#&npRH!=ARQ8kkvo9QK%nyMQ{6atxMcpi0fs&p`_gSG&SJ0!r zNA76tVAi{iYT8xOI9$?EE4xJOdFKhwiqiG47Fsc5?9SaeCxki4DSLK`z2l%d%L=f%cQ zb%1xV=%BGEkH_f8F@#U?v83lQ6111hbm%h0K;mUJonYhxyvO~Ku2E*6IdKYR8&axU z=pgNeGFQfa!BbxoB*7;-_N6*3K4FRw8Z+(f$t{lG+R~G6S}UU{wAeB>0 zt#PQOxwtPceywc()8eKzg`SM0?+7ChkZ+G|Fl1098%#VidvCWwwlZ&SGW#l(r%ns= zH^i_ZM2N3%{pN2R@oUu!)EW1tT7LFM4w@Tczs?PmoEmaC@O#?RBDW_RYhdqb;dm}^ zPFExvhhnx4)z$1PHP9qfio{tAM$N#GO=0(5oR%5Q)pfw0YG)u{bNGzP5;kNmQK_>& zxuHfC-e9PaE`Kf!qQ6vGB}@oM3iiqbL9D&|T2aC@hRwE-IWq<0fMfpyl+8>?mF1Rm>tm4cP!2NF9rfX7O8 zPZaOhNl93K^11LTU^b!^$#%YfB)_bK$qpTEk`{dUyt;zeMOZLTuLpir%&FKe#_qE@ ztk?^0a@Heh94sFQ?YbrcCfn$}1jjZ!-6Lr*2=JR-5v9*!D(WCX8FQg$n#o!S@Dq`f)GQv`sXpwuKi@Q{@n~(fM;zYSo5T7P>za2gBLiwp9!B{b3sdl5VqJ>(V>wdd zevjnL8xqiyv9WV`tO%U#157qIS4{D1Mn21$bQ&0{9xN04j~8JQy6YS$d12w>jk@F9 zwum3L7*nxBKr_MsjYpOHbw#ddWowL=R}d|U^L+Dfx5`Tt#>mQY8uGu;Kmth}3Ozh6 z0W>(vnbG5-pO9ykbh2PIl89f$5(zUP;{I}n)#cex0nr&HL!?4ZEp1$s9OaTJ^>xru z??`AZap;O&17_Q4E+-#b&%oP(ld7~{1^AG>-*U|8@?Dqo8)11UlTRowf!iV_TbM9d z!8z`}(}kES?C5thCzjGzye3pe`+O--9Bv!x`xUoekob{cz>2tNZj!9~FkBM!a3y|u zwO5^LTyQ443ahE=daJQL4Kf}uE|%2tr~nDC=_-1&g`)eII$#MvNvyn*gMha;w|L(? z{5wL6FDb>$ki+dkKL(wK;*(lbi5ZXMCSJfK#e2fcw`35wlgc@gca}8e#(kWHTbi4_Jm6KG!if#qy8P>VjmYwkx>NEk2dxW4NI8VWUP$;WB7M#QBXz&r$Fvi@52ErpS2e?QEMzD3> z`m0_I`6wa60O|IvQb~r4)-E5D$BmzdM9w9c&y{O-wC#*?t%r#|Mt6qwg?H^xa_P8^ zO0?LXheHMi*mvmZV|veJJ0tWs9*X^z$$qQ$$Nchfe`Lh)%8m?(7$wHgcHgfK*zI8_ z@SwHBhX_K{PZxzC)0ZE@LkCly5LoCGK(Yey6sM}#pyXNV7Ah(!#778av~H-Sz@>eH|!UgNod zDr_vhUIgRtJ>OLH+LYh#!Uat@f)sLa(4Dw3D* zJ2%fem@}nsYErA_PL)`5%M`w}MaRT)IulNsfL5zEJd@F`DH`j#&bi0QfT9zemz{5; z^Oi3rv(PqeJ>5f{x)4zFgI4!WxU0zoJ1Q*tlg2V^XRXn((D0Ws%=y)&oJgfe^HKrA!B6701Z%HT^4&c;`*b>h z+&R@}(grbW4aCea8>o^sxwxod8by~b;OZwpWI2a90o;m$fl3wigtBO#Km+<7m};&^ zSBwx|pZHy!pIij2Xe){^ zr}s{>`4=2IdYoqMcV$oKYJJzA*9zUGW4BloS=f6wn-$p0zj@ZJFL@WGS>XCrD1{co zIVf3M^>&+pbHk-{?kDD~eh&QJBf@4Uda6QKWl#?~*T-yAS(hZ?5KVBfrEp>shUMG) zGyi`2SF_aZ_s&o5t`rvlfa`yvG@Tsu4K4r8;Z~~uH<;^3V=DB-Dr%a)l@Q}8ux`Q_ z$sqn{%sd2)u%@t)L{WuS>PPQ)xY7u>xcH`WUji0q8?Iwc^tsM{K_l)2&-;;62a;Kk zaid4HEL4Xi$64UMAMBQlEtI%|Qca>Au_{RCxFg{#m+pwi1Y}zdq`p7QELk7uBqj&c zb|7~pX)3b6UHrj0tVv8F&8)vk4}DhV^wDvyXDse?K_%`_xzpVWPZ`Ze_QW{-)QJ{ERPN3+?=7#}D@`H|ivXQXFjCkI&t5_Ow z=I(`@PYekngG>!U?EzaW373{N%l=k`XCRG3c5M6`iNT>rQ{-~$>}0cj#XTpIVe(K8 z=ticy%C1$KBc-aPW->ycq;v}(g}R)`96@vfOu*Zp8IQt^_T4|NLt?-468A`e(dR*| zp=#Z;{rkY-^j7dc#qmmT#M?;oQMg7Tgn-PRJgOliPxF=y|40vjkrf1@x-+O$`RN1U zb*sRsmi#$;OkBd0%dCAM0!Igk%^OjNh>bNzNt(KNmahS(C;x%L^M(U=-pyOd~Tc-cLqGce?mrjJr*=H!-Xq^-_ z?^Ktkj>Tk&PXhi;Y=O9n^?*f2t<)QB>$~O<>J1B5yRfJL50m9vp;3xlNL5#2*mJ>} zOwkg{o`>X87EpFD=!D30jq7MT67Sy}tbGmWaHLW<%T-tCaoL|lA>935Ts38gcuTR`qDl~c<@Mb zxp1fD*S8~G^Mo)m3Y2qG!99393ewqh0aRQBVL5=?0t86~SL)PMaXoy>NU1EigK$u% z5=ls!Zmb-rYV^jcRiT{gMh6ae4a>DF%JQao(7~u-eB70cGBD4g6VFNeKvCmH%Kb%y zq-61>|47(jbB~#!HA(m2^qhU-mu{yw_`M_wrfvt%%JbXyOf3>egC_=-OA=-Pn7pAf zqaFtLS{w(4iYHiy9^)OM++Nh~Agov`XuY17De;kTJOUvaz_94UW4YiHAQF^?3i_DD zrJK4rXY3-7F*CaE@p3G?3A0~sE(P0Sv?~zjxm>Zbcya{NO%yqsh13G2e*jD(M!K=s zsGxJRARuH4p~h0B=tV^fIFhfZE;vbpJeWidUAe$c+NKDON;2*>4DvGyrJ5ec6wUCN z)BaRKoN#V#FJu=p2y3P^if8r{hu&TvK0hV*rp1}}ez~Il(jl&?dggEcW<4^f#)&65u$(|2G# zAlgG`csST=YxdPNa4ovjd+{%l51%hEZyS9p6Xx-q)4^QM71{M%bF0R5O|F18X0>G} z;tR5EDY3K2Sewbcj=?xw^u`(BrQUw#ju(^`r*5?NDcciu7OaCVt;U0OO$ITN@&^+) zytUjc$8P1HJnMvw1?k%t33Oyt%fyT5fPQaC6OShl#VdNO`W_)2a=JJ$Wk(i(WlMV~ z`kSCTsST?8WrvCLETXD=GV+tnw|XWZx!zW@pW&?#3IDh zBF4~h@bq3K8X!%xmT2@tXx`Du-Tt7_`umWhl6z5EBT#xMB{#6rg^2&5rm6Xz3biBxRXIsQkJtjLC6;<`fjqmULYWK_;UiD-wvYT4Xi19x5 zhk#uk?PguGb4DsA_Xsa=t}K}?c9Mk@r70_m03+9BiwEraYT)*d)s+p#W51)1bA$3$ z&BTw|j&O@4wZCVZhGlQXoE;gHQEbJA>M1HyIEmPAe-mK6(-#*%$Q5)tk-Qd zKOP(#m_NEP#!m9+z~t|L({tR3TwHH1oaaYdFJ4x#RDr&=>6h0%ZZLm>b0tIy*7FD1l3EA>ltYuo)6#GmkSub$rm9F9jd ze%2$JI@vNTZ3?Wx^NcOruPADwx{_ZMoI^yPm$+TxiPW5{mOmJ}D1s*8yIs4Zv|YhA zR=k8E%b|!Yy>g{EOlA2uQwR03MCjH2XjLi7-fRg_dWw4t5P6E&-K_^|Qb>jk!+4f9ayjZ*OO3{T|2oN>+O3oIO z3nfq;81QVH*Jl&5tp^4zE`n)%G`xSpwcOkW-ae1dj;4LD(lD(CkihhWx<}2&X5!bt zk~4RK6SU~{)#HPYp0%0UL}Poq4o~Bc{deb|pLa(#F7M6d=jB`A7o!e;bWH=N@+%_! zJi{Z;hp1Hv9MYpEp9>EPL-o=K_u>yB@e74-Unk{_r@VjbtCQb$eQ^lAO7I!9gMV5} zhSvCr+52TVw1KJ5Kv*q|KJSbI6{O2ULi6XF;x=4&W=BKyCB+fBuG})j*s{x1_kVUC z_me7frLBmE1-F-I91S5ipM+vR0FQ30MCdH$2d%;P%E*o??8C0JAx;5zv8WJUlAz!c=kkr}HnD4F%Z{>(okY>(ZEN3eJ8#at{^Y7)X@2&~QVpMyu&O`IsbE*h5kwM3B?upqD+Y;#BT)E>`6evLdY zZ)uWTBQS6GpV1C4O^|+9M|_hw*X9{?)5Zm;#9f3xcIVr;$WiBv;_I){hqr=4YjPld z%I!unP?EH&uR!hNB`XZC^LD8EOH~4;OI7j7Crgtye!U&MdtC*>z*w$#v$&J|L0Uku z?4veTr><#`shq1FyHM0i``dt^rT=Td+1a;4D`Ay(Os~p`*~a}On#z;fPH6si`8PsR z`ZYM7M?(6fD?n|>Ko&9Rty~k9X~_j+Puh_&ieI95nsK{H%HP>igk^dtu3dDG;4jJ> zaz98`5_W-{>+=$oY>nT)p6SghvTAg~8Jh8n{op&$$BQF{6FOU;OCk*NqBrSkX4O|H z=RD%B+WY&fx4ql1maT!QcPstSYIFfrC)X7PX@rbh|)0?<~*JrXs zaD^&~77@uz@33Q=R6~`#Ht2FCsO!H=K6qPZBr}n?+~g|?CzFObnSQIe{}A}_COq4m zQgSTIREfoaJC%i!Gu9ZrFlQ9;+2f`HxHF{W4d)!&G!7FzJ6-~iL+(`&Y_jQ$%edUf z8<_`-H%FIIyA4^2$;S&OQR;Q~o%rou=l6`oU64nGM7M zu`qGl&}k}FYY7}nfeQr-I76~aCa&?)^|T#+ox`>1OAp=`E*QgG8fd@7mRP@4VuTC& zQIZZLGrmnbwuOoAuO!xZw_NHa(GOBDd?w8;SJ#gvslhOp8v!Cp(xG3l6+K2U>WwRf zTlAM;F!B?yau8}qEfTzi#+nu4Mq|1bc=tJUNB3uVm8UYPgwVcQ2WbCO&J7{> z8posY+~v(iCVOn6^LNg5`5clj!>re(Z%Rse2m|>z3Xx}`6Xaq)twyr*FF}d725416 zJ0i{l;bUwg_jfo?2IFlLR42g~pw~j2{8gi&?w{Mrddc^3beIrF@Tb9%AwAz0jT&q+ z7QicHm<+=rC_`Qf;;u$*BajbriO(l0FzLBeOFfLXU45o3*3r^Rx%U~WH>S!Pv^6RI z8~gmboV9r#So-s{ZGvs;Depr$-5V3}dFTAKn|QY@t7jxPUqez-XG4TdHHpr~b=CnU zt@_!n+KJOh-T3w0X?csf*oD(fRV6{GXt1JiJNX;8h&h?DFTg+z@FKORZ!Acgvv5-> zlQj#_&z|&4zJK-oq8fdrp#dM~aB6M5#SEK}e=@y4;N=B~g{`mUH;UxSz-zac3FH*Y zVuN&1wuNkY3h)_w>VAu_iz}bCmC#lElC`R9DE;3X>oL1u;%l;v zu~Z2r+sscIHy&iZ>*>8rXXP>8rc&vs^>C6Hognb&W##}@a&S{I8Xdq-kyL>`Dq+?Rt?l9X8{rpqPuo2!) zvvkjD*GOR#QbR7QcUk7X=<0e-;;mIpsI$}@VBOX1((z4x*zUSayZ6l(-SW!_`5k5O z@tOoVwLfd=D|X6~G!UuXHVZRMP;uCs{qo`O07?=H=q9&3@ z;R?SItAwbvZd}J%2ipg>ZnbH3;o3A=!W+<~Tnwoz+_Po8?KY_+{PMY%FP8{vvE;Oe zchKj*;d#Fa0c&c1X0w(*4NLz2uzzBrZ*Jx6VElh^U;i?wtBjZbL1X?vTRy35#-YVX z%%4Y!#1ZCbko?1QN^RrpZAKRTvsR~o%3iMPknz3!S(XWUA?s zvgv*v>L&U|=Y#VXaY#IRPJzFKj7}2WP_%Ewx1b~)XE)&lDwvqYVzj)b-4rcq5=urn zpT0k!XRQs5Uw!%S_o=WtIn52OeYH8vnH0JDOw}^|=(CvxZ4Ev<7yXguw^Cv|pygs$ zKNAl7sV`K^SS>-=D?;8W>07#R`JvYxNe0=eQ&VXD3w<~~%cwgALmX@k!%M}b;{Kz1BVJ$Qa}OpM)0df8K46#f+FO$QQn@9@D?*y$Y+>eBl~I@C zr|!EGaHbTO!CBpY%1O6tIJ~p4zm+q{w32Q(#t8Q1?>2j0^Y5~2#zwdNbI1+V55vj} z^nZq;1#fU^>rL?M4b=(b_j_IoYG@u^{60T!Mjw zcgb0Bp&f|@^HR`+zu!xUHG)P18hRHjT)pArdwqh_L83QuMetP{FuQkr4aozEMkOtUrVWNl^T9KUFGFZ+Qi#? zc+?vP(X8DYyM6>T?#9e;Ls-iv?_{a&uY^%%^2sh@&UsBd*DelwE=A!=#u+i~MyY0= zA)Mbw^AC#j;`L@+?<6Nyu#MY@t4$p`y&V?4=kJnTmxc^#4&Zx=^|2W1a^JA|50~pbN zMb@qL4IOO%I|1;|_48w`WY@(Ieug0Qz60#2;yX_GS7z1m^kCGWWawmtNirHVQyg3U ze<~l-nJiwfSuHsUA*Z0dIN6v9kd`<(tEU+ai7$7N)?1+TQdXW9F6i0I=z0is;0JiAU91#2E?`zb@7cuY*`Mh*D zNSU&4{(u0+$o17)E!St9079!?D1v_Z>o z%7~=|?h1}Z=)AHW zk`Hq%JG*ZUjkrE39VaC=01siL@SL#;Xy%Mid6Pe_UCfX z>1y?Zee*&Jk@XbaS&LWuak{mFf8(?MV&O+Mps|EFd7-XcSgNVPdT=X8?2vW{2C%lXrrCgyx+<&GSPE zk>^%{p^@sqnEu0BwIakq3L&bM4&C0nPdxs({Vc*xSmD%IKq}Y@pf#LW#wfty19248 zJea@a3+J^7iFiix%<`V!2=8qXBB7z6R86wkk8O%g6B79UYNc_bBYsa2n_O=QQvTuo zT{Q3MX(hAzkvAch{dKt5N^p4@7f*E9TW1p)e%WH0C5qnRJ#9aoRSyq+q%?qyW>ryg zAnTYy)$#mhQf-Ix=r(}u)Xu$rAIrotl7ub3e6ect-S=c=>oO56sIKx8r6Yyiw8 z6YTH>obuF6z&?i9rn#+p^e^?X?72&LoYx>+9Wr7ICzs94En|K!iv0J%tw>J+l(YdRoPU*zzJ8g zdnyBiX72ay@Uf|T*obw)&j_94vr+Cl<3`NP=q?Xk%s(!g-J0%3nzL$0rSgo&>q(RE z(Ca-%SISckRdSzl;r3QVF6`Hs&|n+WUbJ9Cbr8w>Ei#+I`gI!Xs>}r)u%CPYhbOmR zt~csp(ML6B)br#>`yJ5=(wdS<@YD&l=Zue)sC>S|hBu(I)o_qqhU2##??E7b99 zlqw9t*&%;1jm;9yYCHhi&z~mPn_7Q=8zobki~@hoksA}<$8JAgezQfVF&>P!Sf7g< ztKZ)nHDBMqFe&7Yi0I!M;rQ4#Doe3cnV0>w*`2JBHT=Y&>i^cCP=@$6D(yo2jW=aW zAYOpzP>OyL1*}~9+A6Dpy;AqEM<)A~*>hAuJLVDw_xsV}_M&#K36ppSv`+apsxSXH z?^tyZp04gY^GWx=zEdd<%82DZQfC4N0D$d3)WQEJtoASR_n(Mp=e{a7A9EM^cR&R) z!C-c4gm7z@34G#YVdYX5#KvT>b=yAx@AbsP0!&_vxB-u=*7oD*2|bRWsr1n^{@V^Z zIzv(l?|_Ik6opej>yCppa=c|Q#S-CgC@H@i`F{Y>80$@-^rw(futaZAla3U6ZV&p6 zb~Zquh4jRUQc#iMwSLYT#Zy7@$%7}c3~(B{uM=&P^t^tEj8x(W#$RNyYXJbC7%e^fe3#RNy+EH zZrD4h;=1r?if9qQArxG?3DrFGa$f5w-HwJ}LDha!85YM=r24V$V((xTkmKhll$dK> z0Nd|M3bp3B9OVj-DMLu{hiYB#lNZ$8qQ;X=GCY(Hq}FKU zABP|~ps*N7J^O_U&W|&#l*rQn%+`WH@Qrf(wjxi8XCiA*>KEr-Rx)EuAPF-`IFD4+ z=U~QlLnV9-QTY#tGXYn-GVujOsJ6FjEMGnO42 zY8E^h_@mp7zy3uQ)>tP3WVZD1{ZBDF#~m3)rHGq%7D+pq&>ck)k_qk2a!u3u$5We# zYL_~p57CG2h9n)T?NAPhU5b`)r>Gd6YDM9)f<|4N2?h_EWrlZhedu54V)m31~5!0tQ@Rm8A-Em%2S<& z20RJn`QW}ir%t_-oG=w{2TjQ8upXQ^e0h4{G-_a$A7|q*6WMv z+O`>D=v~LEnM(?RxQg=VS=NLNNL=i>T(VYqUn zeQsh2fE|vaWM*MYkjG}PI8uftI_`|)S#FBweJ-Z++a2Sh1NFF$PTUQ_8sM%$k$797 zlxg_JfI*D9{7dj@Igr2Pb-6uwOz-V>3;jc9o*}wgWcwE+>)DRNPH6UDK60WHO~Yh6 zA!zOdSdK3XFier89gt^9{n&5KHA1b>xcC+Qrkg()r8P9d9`qstr`D~f)m~&pI@KDK zbT3Se7Eh)`2xQDM?H))D!%}8Yy9eiE3#ca#NepSFkiEhBfOg^voO=B10m;$liQ7U* zx&-3E^uy^Src9_M&Fvf{dEAxKnBRQB)FZP<{nLwB(mu zCHwCn$ls|4#T4-Sqm9Y+I%~zJ-#}nOo?wZ~Q-|x>WamGNjxNaI4zAHHTs>h|Xdh7ON&Vi3I>dFb&OtcR8dvi$nAt?+0*l zr2EsT&_ET`=KicSJ_u&94>#y8+(rtm-68olSX|q)->iHt=hc^`i{B7M!+t3b4EEcE zl~^V|@DFxtE2TV8_fL=Xvt(bNSfcRq;T-6wfqSWFXJN%Z7%EQ$y)-!H*Q~{qf^C%Pvm?g;_NGDsdN5#N{ zfZDBrX8DF|88^?V(x$^MS+X=wA#{N@WM+SwI`Mwry+I5dcy;AS->{mAF)oIF#kv}( z!$mX!Wp)e|S}7k6*()xN?XHek?bsYx(nbV$4{=~Gd}GUUlY^WN_GIn-R@Y5%lVu0C zy7r-lI=8i{i8QX^f%RC4x!$bHkTEl}$Nm~|`a&rM7)ko|f3}$}fSdMS^mp}S8j^Yh( zOJ|TR+Po4z*Mv&B2ldnICN$2#5f}cAKaB3k3HaX}H>y1{uFY8l8~f@K^Q7QXvB_MeshjEJ24mLyWb>|r!{S+XIM*$Vi$dvjOFC~7H!8x%{6N_ zdU6-gNpazJ3^`QhxMG#2dGcw;J~eZ8B1+gco?Z-fwY$0e!cPHKDkntU|*q4ekj6xw8P;k<*dw9la;(%FrA*>)pM?bB2t*YEAB@$y{PH=ds|Q@T3C!^=fT zg){TGxqo&aqVz>Ek*=bVUI*`nBM#`JRFjRQ)qbD>qL!c*K~S!B2mcA8V7>1BfgZ~p z_=cunomAaU5*_-MDMYcksLJvYaR2?Ue&%wyk4Pmmb7iW`ilwspi z&ZN`%Bj6s_c>E7(BL$Y~sR?g=@~kOdb4L-g|DdP+CeBS>?Y%x*2qKk?3Q}EsWHe;p z%qwM#{)^ZjMBiLk$egJc5zG=5X`D-ahYF}VhmdXYiF{3_eH^7t<}3|P2k822yLk9k z+0BT{boo`SI8>!4D45odujoScP6Y-2ozVmSub(Vm$qxkdM|j2H{6{yW{;O5$XlHDw zYp3tv_-{$p!Jin)4+{1thGKu~tEPj*zFOQ{3fy2G3~DxS1=$8@PC$obja*BTRB&NZ z`M&O2uq75&S8uTSK^P{!_3k*#S;UIv_sA|gM>b{R2ze|NeE)aHnDiJDotx_=9ddM4 zkklMR9Y-F{L1tGu9s-heRH+KG_$D}r3GD%4OOaL$sXxr;;<*9iI#_`~Kb2Y$iMRF- zm|_!O`1pN9c?PtucYLfJggh`oovI~E3Ipo?tXZedJG?~t-<#DE0%#e3Lt%~!itvo{ zWgk3LN*rwwrev!za{T`C3|7$+@oR9jkO=C$8={4$C^c$|m{Eg*Zt!?0%+SPOeub7KQ4pLmu$;2k+GJ8d-@v-6lMLH0~X`n{Ep%83Y6u)_`4HY7^NvW`6*`SIb zMXyDJnmSXdOU2@x@q}MC&M8E<^6Xj7)*D%@xth8??A#OQFO$wn)?NElDmexw~<~lMB zkswROB1_KaGrmFkp(}@5@}mhN#wTV^%QN$8$@OttY8t_}7V#9D^@qD_ME+jU zUBK25RU}f*siK2xhj)}fTW0TdCXzefpVw)OihD%qH^_gv2Tk3O+1(+~#aD3x$VbfR z3x_045`HO$nD@M*2k4(Z+SO822bt9+a#syq5%WU!P7iat;p-EH zSI1~V{R`f3Gpn(wq-%!LIe3$veWYZ<6^wtF8RqG1$X^yzs6aCv2pg8Cy8@JTrswr_ z_w=#6bJ_lku4BD0lNjV|G8=EmMx{gxOOr|I;|{9!Olp_gi$Vbbqwj;?fk29k;rT*` zp<%QJ`Bt%fgQJlXxJe4i)=^`hQzLRW;rkVAKuT`xa_&%~Y<{9Zhl;|OC?;7d4J%n| zqNditz%CsiFhQGDZWvMRAUlRk?J8i6W~0Ps**9pN5*-d(poN5GEJ<0oBSK=#ir+8F z!U-<0c)Xs6JWDZ(=3q5G)V8knN+VeyiP;}I}WJd49HRh#SE$1}1?+%_(ZeR-KDeMFiY%+CT)hj91cZjNePAn&9Z8Fbd@>w}yk;ofkO69Re z{dd~R5Wq62ri9Vk8P^{Dvm%zW<85!7jx>GmT41~zaEP%z+}DBTi`snj6>qll5ALlP;|{j$46y%OJf##zvio? z^NsEbpvio=sbxR#$)6C8L8-pba5W(rl|~sq<=LxX!O;9_h3V;pEAE z7AZ}JjOt9G394A%MpaYSwQMrN%=LXa&^-;&-Np@%jU&s1ttyTJx5^gbkon}iM|e5h zJK}0eco`BephG*q$)J;@F$&vNmk5H0C(6<$U{$FX#Y&Boq~b1xU`5d*KGP1+PnTet>wk9GfCv({ilxlbwU>f zW%u9VB;0}-#&sD9?L|sB<WQy*=U`3~eJ1~TK0@fFVB3%(uMG2N@Fp|Fipo)HKd@ryU*=WbMroQG{_VgzKEJlm z#r0m9z!&9kO#as7a;9zRB_Tc7^0~IVdYL8e)O)f6u?7LZXPqPDaJYYUB4knm-_#)c z?vn4BUxkY1vRR=AUTWto=HzY}zQ7?|x@l4}cqtzB|owxr|lfvCU7s{N3M-V^^~0#>(8iTvJ;tyMlW>E z!@e~BVX%$4E{-;|+Sagl;ZAFj+=Qb}vp#+f0Gc^YeXXLi_oD!}C4Ervo%wBuBxcbF zZ;)fhp{mPsHtW@PUn=3iXLYBkn0Am{dgdKAP7p8jxD1+6h*Z347Gf5XP`m&!$3&Bd zCQ)IDoYf!hp}lD7I{Mtfa|=!jfUe?bKh`Lf zKa|gZVb%EmDYO3*9A*D#BK}CSdC#gw@e3OJqdnDY6(My1L3U^_ba#o2q!%rhv>0>I zQ19=!W)(48lN+$Xw@=@u-%h35&z<+Lqf&kv39~vQFpiey>i=#lXJp0SO|F{>3mwo0 z3YMPp%OupIG{zOCbcQxTumKe_zeVuLs~41DKmFwzxFAC&_@jxCVNRMGG=-1KQQZa^ zT4=WF91E8OD2oW-*iYF|?zsNs**$D9?|rk~F=5p0q3(r*_g?(&uZtL6>w~*QfU`wR zo-GcV!K)?ODuyCaN2L(K9c)JrS$i-}pD{G=hB0!`@6Fs5TRVF2VuG^m(~G48+6jV! z#2559l*1O|K4XM7+F!#;oykDnOMpn7h|;l}2hFu*gZf}V-p?h*$0CI!?Gm7!6fWKk z{bRZ(zUhEi+>&M>2vi_#nH-^NCeTcIW)2t3>b>w1@CGksM1?3yzb00`#sO2YJZC z#%O1FtgLqyRnN~~X5SZ8#nq&FUGK@&-88Pt>I)V`M^pN~+LVs^!T0GG0Hs_vq-$E? zL0*gpqHQ-0=YJ+1T0ddu%?sHz&i}s9?jVT`Z--dkc^CIvY?Bnl{~lR>)2%3K9H+7> zD`KM5C9A$`Z+B%K-RM}-_y9XL+ax*YC9|LkJ5nL(Rlz|kFH?$>ZM>yVrbEV025KaIONs1#$=_-e9cU5hBOIX2-wbdDo#DXQ^2S^{nClVnJa z(a5|v{-6_0X>KbM!&0g>A#n74pqB5kLT(08`MY5orQ^$D0*8|&RM<^rX}H^Eu8Zdh z4o>whg^E6XwmW?7aB%ZdIw*I#Mo60jwHE_0$MxPpr*VLC-0Cb%6#l3?Nb<4Dk7^RGg|`OPpYOMIY3Ui zY@Ehd^2(!LjCs-4)AjazXQAO;Bi=6#f)rPW)s#S@tbDh2dg{`dy-m<+-hU;x)Uu)4 zYTD+^-iJG>>-*(hAe^Q(%3QmkEV&ldrM@lApU}^@z&*jrKyn<Iz?stO|aA-YW(_<0wH!DK?U~CPR1QmG|3Bdmx2Ews^~*I zLB)X=Umj_|fBbiKU%y$iK8G|d+9Af5*Jp*#*Y8t2hfiRxoXAf(;Ou$qxC2GE)Oj{1 zWqLL?onU1w{~5oN0f(8?R8-4U`{$^e1A9n5IK0}@qm8fQW)19|pErB&(C@;16&aa-=#*bV zk(#o-p`Y&M>hLZ>;6<^6AOl3IPcQH^siTR`{hs51IzvVsH6vE-6!CJHDXCOB3npnM z1;jaZyHrJu;d-bON(;=!pB@M0c<<8SNM(ky(_k6R%UqnAMj0EtZFzX{mlR@#Mes^g zA*|<5Gtvk38sL7KSI~hY_2;T6ARdV4F4hTjt z*yO~BUa&ylc}k2(W7j%sIR?UfD9U5B`-M1VX~cehQwEP*Ryv}8al`yAD~NlUaD4Z; zF{x|w{g}H`gSFOE=p;ze8tvYmQU*}DAe-u#ozJBdAnI|a4I1zA1j8^glDKw38M_nm ztee9PbS8T6a6YZ=%@eXIsD7}mc7_Q?z)o$Cho<#uEr`i;R5V5rJ^+rT0%AJ%Ob~*y z`(Tyn09Ed-Ex2hrlr2D**Dhg=>oX7-qVU4HY(=3C{gMd)Js=Oxd?iXAbMgm2lmI*q zsi_zi%5x$jthFOO#AkP#RMIgv(BI}yhO!~tD2Hx9rke8w?8 z&7UAhbvg;i*=fvBIpJWV!yd&f;VE31D7}*A6u1 zuPCTuV|Rvp;4DRzSD9@)H!W5y=i{uIck5fdL_Ats+&Nq%Ia0^T zd)0|#0vZEOf2ru*g7cz))F3$8eF(2HR9pzw-&(cMCdF+4s)Eac-1z%{<}fufUhL}- zT`9WE2;*A$d6X2ru@ceEXT*67ctO*E*a^{3{HoZr_ENZ@G8*e-lJQNTvS|x}k+83t zUch)Ll-dU1GG;kEy2qn#Vv1>DIkps8qR(g*>&Fk`c)(&NYtIW|u6)_-R)L2~T?mQ? z;<<4dGoFGs`%VyZAR>CG?*=ruLH(*YeT3pUH?43!1;)*f9hNE^)n0{WjpMDC+i`6Q z=p${+d~``vy3}_<>^~+A!wK{RRP;y6F?A(jd~P=c4^5TMkzkuTCw%u1t}xrWSINnR z1;@;-8}9`|NX9l(zJzyF*y05Y z=Bv#P8Qmu=r2F!nUtYl=#<0)NtTIRFS^U>QJ+CGo`^Ad>6~`;?s3YQpt@4NXe^MQ7rNER|uT`r$nZ9+X?-@nm?`X!9XL z#hhP>?w|~l&F_JE2kE{2zHKq>R3yNLkyMP0l)jPewXV>o z3yEP*n2_9gu>kx_n7bCKLmgg|o44$wK}dUX_KdFb=0a-4!_L*^^pH)t!h30aqG6v| z;i4xxH}|1B;-fjvcx5JiJ0fHHu3>jZRFdd^U|X+2tcPFCdTmYekph`kBWKU~7ad!r z@*BshzZP{F1;Fdeoc0%KB`qs?NhJj=_)t=5+?a(nwMRn_^+;(Hke$0oi@;k6D-FAYAHnGp{H8 zd!WwER*G6D2?xxTgvRGiq$j1b`|y_Bto*N#otQyPrDWI~yk%pL#HZt8|?gD3CYq%m9YKJ z(C_X@+#3L+$4CT1L+-EM<$=KMwg;Smv2JKt0kGq2fnNB5Y8#nySry|Z5D$fw-}q}$ zz17I5Fass0b6e|b^O^oOcwl%~OEOJi&cARO>P|`uY1R#IfjW{7n3CV{52t&}D2BH< zeC2RHKHNM9q2t0{3!-I97OloeK&JhiW=;@MvPp~3A%1bSDlv_!)?|$?RbYjmt>et> zl;S0Oa#olpM`IcH8@xt`wzPla)?Z0!sL|y*owiH){svc}iWc-(23Ts}LhH|Wkt>V} znR4zr3Uj-i=$T25c++94f?QEn-9on+XSZzjSk>=j17>e`$9%!UXFns?w0e$g5c5{K z^h@8dDc`ZNgXnp?w1kJf9FWNnbSWDPPx-Q8mw^9t>GOh9a0uP{RxBIZm}JC8RX6aL zPg$KXuO(p8a1~5N`0E$<4#j`dh>XrHeKn>0vfK>kw*-OIhLGMu*Gjyfn$bdyeH{ye6%^J$@k32K$2=NOIwPopg zX=q6gxdKK7h9db zgboHdtdsT%BFk-DMiC9VSC1{b^eq)TOaVRaAmv@3Zk2FoMJ73PHMS7_Y23%YzObSO zrjda}dzMrrw(tBogL?~d5Qg4~D1p2}w4QuJA2(8UwHwwec$I~T!&D*Qkb+3H^ET9D?n~y%k|fm06#@fml*I9j+)~6cBcq0G`Uvgh ziL1Yxa1UDRNNR-!Wy?&-dFb2=3qidid;Zb}7G4Vg#0ZuoM2>nT&`16L%TA2Zi&kfU z4YPNHAw(K*tBX%)6QzT-WX)q8w8Z5!2K1SQzbiO8DFhm$O8K!y9b05p?u(;|f6_ay zAP(^XSZb#Pt%O>o$lsXfPFSs6;}Qg?QZo9(ex5@mCez2?VK^%cXCTDD;#qRwEX0Z= z)(rlWiK(U`fazdR{yEh~;hrK{9broDj7M*Qz$9RTV0==HDmuYF9pL9PnrFc6$^a{* zL?XpdIv~~GxVkt$96(AlJRx#-4Hpj#SW)zkUzf}`5Dq1gBNF{150X`Q&ICtbdr3Xh zLTl_hzQl#9U5UTb!#E!(2)ABTc+{vnKknc`9#h?-Rq_$kY7rMR0#{8--JHVNZCm>C z25Z(dR?^fxh8?9u>upA8f@zLl8p%P4}EPt(*=;q@~?box@nNvN5}YptoHWm9!6 z&-F|jC&pWI1U+w|pyD>UFwV>}N5VF*29y?%B1V2d+SpoH@xR`LiAtb8dccRo=zRdV zPsY5`I003dy>vq?5k{xO#da%vm)E7Q?czvU+HgHI5CN z!|YRX)=0uizW13?Qi^2dG*L-vt6;Es;fzn5>l5Q4N=vc43YctK?P0d* zd{UkxJJ2|0wm0Q+MD7!Lr#%k{Nv|PWGMjz!yanyo0nK$Z|11$>#&%YJt@6Zu>PXXf zIHw+D;*crH6=8ia6a0!9_*Lev)ZEYf6d7M?$p1!3R!37RxT~A8N8a~PCboI<+oI58 zu3!bOUO;QFP*b|VnNk4`hrKSpXV86WMX*?U7WGb|UjRv*AWy?cBNZxWaz)te^xXu8 zr-Ky-A03!;r4WcpL3P}(5r+Ip78KG)*=5Rkl7^Oyu@g1#0-LBCv5$Z5Joxpo6h75A z(HCt+6@9Wc^_UG$AI4S#hK|ZrqJ^`ec^rr5<2)K_^raBcBNd9WR5mz-Njp&otyDPb zg78S(qUj7>$fDL=Qof^%LY@}7Kr|QqK&`WIgTX-C9hY`#O=wA%61q#6WiRvTlMQwA zjeWctI2>zC@t#_flx^~LT2p_zz}v&Msqb!rh)GU*e&HOS#1L9rs?XHIGGIR0o|cA8 zIr#t`-Pc6_Hjp-a_<=qyEUSR5$}gq6$O*%}zchV0_yx*qaMclS$F$ z-Mv11-e2dkKcjv{Pz5+q>rjgVr^>71oieX9W zc8guCzc2oER6jh&Y~UR+sWX#14|s+UyIx_UA>4=}*$57{f6Kv`y`H$hV$rX^-0`Y& zRhJwQrxN&?U5N60b*mS=r9PKFZ1rb`ox`}R;x-be*(i?w@$23Ov}ZL&QT1nP*BQY)maywlU9!fWV|!xD-?GwQq8UOSUofB!9UQzt031!Zm z8f?fa{rBsN=-jq{FIj7%;Ym)I)N17-a?uXPQ_5vn`Hb)#2|aYUE|X5%gVqNvTEc(l z0#9}#Kkl~qLYj6Bl*eT*)gzSVs$J5^Jv*ETAahya&zf`?`?^_~Y=(H^?XI{b(afMKywMS}Q3r$<0u? zzxoCbD1`&*w6ePFUi#Ist@XrKe!#S~d3Dk=na7}u=On7o8O(a@utny2Mtg!~ zKV%iipS8@tu>Etg{c);y_%S5^hgW@Yyg=jzJwovH8!E7W0>7cHhqR#Hii9gHf#tHz z>5nGxf6VIRM~d<2M8~cg)eWIyu{9v=Ig?)2$xgSkHYYan2%LXDi_Gg zln!vs8@LWT!+el1pch;L0#>UVGs>JN*?Y8T=NXhDqj-i3qv>9>>t@vK4%ePWy{z^$A+vTyt z>y!**YEu!zX$I<2ABwu!U<>?`SV0Q}i;(%=FVmt0M~K6WUmP&4#q|cta1W4!3c;B; zMG(I8ddc9uBc4Qy)TCs3Y9WjKqt4T3tCUf_3W6Q#>qK`z?oK!MF3`u>+7X`>_=sip zm~)9oIGg<>tzA)p-qoObGx>~uLkr0|F>oKc@d5kKo&fq`583YL39S9_m3aU6hy2bq zhWgH?W={X_4YK1u=Kaa>nwA6n2*EqgsxU7FzmYGc`q2bdnqb3F3yN*^x1^^8H(@)G zl_bAC*(_=wI&2%WY-iFj(L!$a>=iGoHPAt{;;3izl@#@>40YJ$W2!Wkf-wJZ3PCI3 zM@8F%gpZq3Q4c6d{DGU@{q=KYD#UjJdZD){iy$Cw&YJwAgSHY^xq!?NYa)R%7t^N} z#|sEyU^@;~FabMY*SQ5&IYLA4f}2y3C$G>Ao*F88aW6k>~ANQP3?44huJL_0UA zK4qbyiYbW79fMveW6nZ8B$Ttd8KpUwZ#aACry|jkS6IAIkw?!gz2SX~&*t;gi*0f3 zSweqT4uffv5dVS)j;&IU))j-)RcqnWnN#2}N~4Na&x}R;VEyabc>Y3~Jv45{9ldbk zFLp2D#U{mhVZ4S`-h$;I&)H=}L)~jRaD4wI(vfvLe|O|^t4Jrdrg!5!M(_Yf3il1s z%oVL;O8MM}>twh=G! z4tA6-bIuCV&*xAPLE2+zK!HZYX-FiG zHg4~unr4cMwa_fu8X(i2369JA#xnCN>eB@gFuB1iS8MFphYI{u4f<{a-AUEKEcPZ#!+-qN#i9w&DF&(#yu-6ay5jk~lzv~m4W7RbPbd4n z>)ShC>(X9b`Koofx9NJd-R|sczeQ%gJ`Vofkh;daLgn~w+_-(=mYxh7R5!c#BzG88 zo>>rj-%zEFH98tCHv(fiL`Q=C2r30FaZExP9%dt$&>B)O=B24^yDRLlQiBbh3mHq3 zSWh!iwA&#kjS?NqGS>PrHjjb3sXUe!$@nW}lO}GDdk;m+CJ*oReRiaO^*$H6<6}t| zN->ycx8*6y9&At<)xYEg7q3@|V@V}QE}89h+1^J7#o5UmVyQ~V){fDAsB zBGdXnFyl&yFD;50^0WyF<8dd^4*%FfopkyhZ^@`wq99SFSGuDwiDx|ZcsJ@KZ;o;J=*g@(+qAFc%OzFq)gHgohOY_sG5jSs6R+h9bE-qfQoGfYS z%^&|tA?CEpIrwx|Q(QSZ5BeP@FQ_K49EFUJ;$x1$?btmQ=A3mOp8+1A{d#<8! z*U{0@#qr8-QWOU(IdWfP%khFOQaSRB*<8;X95nU#JDA6Wcxk_=`~*a^N$@*V3v(bU z8J7EaX|!WetSgAHi)CYZabujxRF{JV1((yd#wO}zU<9Lex^5I2@`GD!=<&GbgQerN_WVs>~ z2_C3L-u?>>rO+8K5MuUb)UI;{NwW&F8S%Yu+6dg7D|s3t7P16HHcml;;_H1_xtS=# z>6PQ&n~Ece8l{i^$uNK_3Sh7@=S_y1y)-sGDuj|H2|ai4IFmC$)q`{7#F(wLBbRHL zza*oQ3(T;9A-JDDUw#iLHjoCVhe~S1KK11$`6OUCfzC(3Ta<`!b_#t%1bz^TUE@*M zyE(U?L~jMa7bydhNQeD;Gpy`>lze$3J+P!BbrNe(QKS-v<$E}Rr%zQ2J|0Ok`-!`+?1z!zmxC;HLj25z$)I|l)d5H z^@)lnMNEY!wT=eSFql{oWV*zDpct1dcS92`H7T!tYzy+uDg@+igkTE;bo4n;0rhC5 zN#mBBa7!?wu)ZeFz^Z0S^^deV)(ZU^cxps71r{5kbtT)y7~GJg0-Y^9Pnp^~95{$o z9zqQDONiURmi7{OE+M}Mei-wFyvvyRAX4_7H^w{W(*Zx!V zb7PHN)UJu({?|nw8@P%Jy;_rvgPC1RqN_ERXHYfh_a+Aj@KR8n9#Ht(ZhT>mC8y6e zs=V~1su*f}HI0s=0=AR|r8}hq>dPrVB~6-oM}q{NHnCUtB*KOYUNal8=d7z-7_t=& z%ix-NVVll68v{500Ypg84X^k(o`VVV==*wJyJ$|sPUUsht)tcq7VW~2B5;&)YVn%l zv&U34NZkg7inLh9qtcIK7w;~hbm9T^NOZUByn`P5snz9{qnXx?@)bgmg`!tPe%}^j z4$eP9&e!l7R06S9>r}X$k1gEIz?!yFLRmSSoi1w27tr#?(YlssCe4i2d0?HPR|YHd zPa}bJa%XB+nZnp|J)Ct{FLT$sR}@8xm1&?@t@}})E^wF0c{{D|ne(kk2a6BJ#3PzTwSVu$GR$o zJbgsFR~Ivq7b$%mNLem9yW)O#>yBgS?^5mOk(bOEIoGWvfO@&CEqqsPJ3=Sx*WS?m z2l*-WJ3N<=ZV`s_-*IDlwuI?2#P60!C9^TJ69jV^dlX|(u zGS|oxm&jXyFD~F*z8h{!TzEWRiN0E&|HVajdw=?h{*mo)LIeO1`}gSK2QnC&8aw>| z!-i_L>;Ld@K5Kdn=7zQZ<`fdY&&vQY^R0uKEfU(hbh6_#H3_SCO%&lP+#aEI_j>RA zPLOH0nFBhPLmJ1N>3TL1=iuZnn!g_S6C16O5>RDpBzyGd zOpEnUQsQ_-P0Y2#&T?Mdqm;3{I%|Qhp?<=QQ#K}H%oce^LV|E|ssimz{*(l@B4GG& zcxie|dH>7K2x|fX5E9**h$_4C^5Vv>TZasKn}%Wfu8vJAc9DoRTiD9}`Sxy60B@k* znYLLmIAJ1ort(Cg)LKz- zl?8rklCw9Oh(=XWwFoH}=ZT!r>%NFE-HC^?szWeHuwjx6prn$12I^m686Pdh>orn( z!%0u=^4SERR@&TY529^eSXkfO04-yQ=+=5`?aUGNr+a)XV-2a%CO4;sjS@uE_EC*> z3TJbs$=#{~44>2aCL^gu6%O-*)$lPbs*1CC4QTWjgeYBGGNCp{v#HAJy9C6g1?Gul zDnTb`{d|$3VL@g+vQ$xwnZs2sqiY0mt+~>@;pMMP83ZE zsNIQFOZ+1^E);diNg3H`>*dLBJ7pk2&6gFw+{}oN1Hf|{@a;n5hkcEY*gFTuB>JcT zwjl#YjNk=kZhg>PD>A09*e~@VXN#|f45m=*_2@aywF_|g%;+cSl^X1J zQR5h_m(xX$6!~)(HC$??eM}yJ_rY6ccDLYc)_vs4KYL=qX!wkNk;31#CW4 zvXO0ge$&A?a|5a9DeC3QBiRNW#z4zd6n%|U{l;Yae4J1| z)d=i&4aw^70U{aN&U`!M)F+g~ztHF6XAKT2FW=zYXb&^y5a({ebT=9JkLsHEkq26C zA_dr=N^%HoQ|7W4gnYl#P1yv32_7o;J1{sIoykT4FyKxps3zEm)&vMeRIct@AZMN{ z=y7xtwU3XF^S9i2a|$}*H<#+josEg+59asfPRmNYb7gAZCw1`kp$W>EytJj;(BzA? z8_$vNwEdFR{Z?sjL_1mlRm5OgSDxbWbZ-tmT4PmD-&J!H<{&E(sVaWa+l;_gOSLcM zuOty~)u5FVIb8vflJg1FaX#wUHCFzT{({;iqF zKs#uc>hl}_T&LIjL~9n}PX%bhHFTz@+=*q`-EqoNOVXkaUUush`N}MT2p%&jUOsO3 z<^agAefniua$#;^`v;`C3qP#IZy{toh)CbLvTQHB5(4bKwgm#S&z3yGi>+mmnGZG&6AxCijYqwiJ)(Pu95 zx5dNoj*>3w2NQ;WavWaV?R$2JBHUcswdk-pzx2mwgv2EFpo*hab z!dua-X}=-7eHR52Ire~^7?BQhEVnZAC2~b@9W_5%R1@4fFLIlTvO9d5OLab-9nT|X z-KNUCN&&>ett9P;W4C;cNZJr#dH+;6ZjR{`@_7mEO;+~-lXI)k#8iJVm0A||7vH^e z_u_CRR<=NSjqzm-8FTx>T|5oZPr43WC9%R z>;%~6`E~CH5NLGDq39+zV6M!GFW(*k-N>jW?%_bfqVMRlbDFW20CPUg^yH;_>)XV0 zU3!HbH2x|qqmlkT;REvhFSoLroN9ITpMeG4&oGkpUzI+4XJcI(eQV=?G|0^f{c?fy zC?nUOR5}C0BycUb=!OFTxRA>fgKm}>C}sm13X*o;-878okAA-{{{CgzdH2!PiNpc# z!I5Jo8=sK$PpzoZ@ZTtx9Q!#Pp4A{(%U5I$jX72ds35lrGD96I`0Y(eAxvG^RlIT| zXgmoLTHIYX@7Eqd5zIU}R4?%wev1U9avnYhZHKdZCgUF$cM1|m=_H{-vD9QadiuW2 zi;+QNbQ)!7B!On)6fz~;b+3DD804O&SfkcorZq?!bHoYRpq8JAzT56;D}{u^O9I$` zCB)y-i3?eePU5pmBxQ+Fs>oPG>h^RHHBmS_tEGn%lksG=tpOzK4%(2F7bo7yA^CM;BuF%bP2As#TfqUzVvyuRYwir1~EJp={m)3R^ zgv2#&ETlWk{hGxWh1!nJcT*44mCAE}X=mr|n~P7Qjuwr_wRkYJmq=t*IQ=+Lkoj1X zsPRY07`HJ7#&FyGS9!(XrGtSyBfj})7y~dUcg#}s#SiKAEO888%cNMbj{V|j9%oN1xJrZv0HLgMwP5q9Gj zKCc>+SWYdI7Hji)al+D<*9&qFL)=1*1z~ zeHJWF)3hKlGH_QCJxb$M$#jjg-+?77t+vK9_gvC?a3T{Fxp?vp0%8eFN-Ft_cF`)C zpy04aYivwjRpzW=vV}L)zO#>evBz5*$-^yj&QosBAUxenw6_~%$7hR>m(q{d?Uieg zpMy^{!7!Jv#Cq99XrfiJepIm0tJCLFumYg$D>j15l&Z*i6l)*xh+`{wscIKT zSUyW^>Sy(%-_GsJ;O6=gxEFs!_3)@-2q_^K zJyTd>8Hl;O?H$%54L`jq#`nJ1r^(HK0HJ2F`+XA=olhn7zNqj`-Fe7QgX31H_~--xBF)f5B}Y6@v}wfzE*{CGtVbo zH*5lx0fI6JE?USL$dH~=*n;g$)Ij|1?o`1(>z}!u_O#vRK6<|~6;!@%R#OEbDDCnH zk{3!|2vIj6hB2?VfPgkL^2aI@#Go>UKvG_au?$KdlgIM%Be5V#3hG(8Up<}D4uIgE zU1~XUpgY8ptgnwS$CyoAEu;e~CTNB9L$*v*7H)?0@@?I4r*fTE^tjA5R_8nCIOTDS zFhcBho<;0f1S0v7DTmX`n(APMJP%tSr6a&8-XqrRkuIe6)*V_isvj%4w|l}GMm$#w ziF3;wN;}m2aa_MGrDCT~Z4n_Nre#GlNtJ_WeGEY!hbO1vkl+ zM6vT5Y0JUE&gs(!W{3M?2>R2M!v`jt9^c$Hw@x(prwu`1SH<+4XqC1WPha)q)Lc^t z+?YVJwR3HS?VqW;?GM3&!B3cOfBMaTaggO|Ze?Vs?_l(E_Uz|pbcy-&5$kLC_?`^IqL#qo?i%6q!@J6o2 zM&Ow1!DW_&;llmMB)uVW*`2|u51 zVsJlt5FI-gkU+TDwC0jP`YZAoWX(LFqi=eEYdb`x4b3k0hkA*Is*y{@PL{NR?k5Yg zO>NM-_NG?8+VP7f)JI^OQci0?1#3^g9<+v!T?k9WcN`_RWKwx?dbwIaX>QP9wXD88 zJG|&q+U%gZ8*yJey1{y%9K`dBH}O+7J$@5^i%m=PdMADhx3ax73L1jmuD;10&t|4B z+fdMMu|BC~u6IqPs;^gR8Hnf2!tCNtEv`fR9hnhS}$T z2T=BNP&M+{M2EN*#?DVa*l=gUk`-9SWf zV-tEH+0H8FMcT!Nc~@OUO#dyt8AlYwOE{&p_!skVTISaPiGJCcQ1hcT zjFXM|IsqA&IAWZ-P;waTbie-golxp~Ibol^>Gtb8bI`utxPhzou50DC^K0TTP9D6o zX=igAlkPr!7$b;s(#BP9eau1Fk1Fh>tt2{h|^@lCW}pGgC7& z^gE$)a%LTg%FclZP}CWo5FS=h&QX5x4rWXFV(NmmQs#izka8pJL7PhK5L5*6!GC18 z`!btkF=1V|t4B*%RNIsABL;A|^5rB~ewU|U*tbdECx`kXL(SLjTHYWqa?Wm=KedLkX094G3E}ce}h!>N-JA< zNqcOW!(;p0`^q`#mK8E?*%YxFU?(|Q%P*mVZmlc%qAp$kDp}a1(e(8&-KnByd@*m? zab+K*YNtY1J9DRw)b+8>YkS0V?C63Nqll@Xc!&!Fl}Ygs*<6^H>}&~FU@ga7S5iCc z$6y4tvK_@3unHU>^%X-85$y+7HqlW6SI#1%&5rLYtZd`(Y~7M-!)D(B`LtpMc)$LN zrx{15>`gic$am%50HyG&2ytg_QtXOvq;V<~1-w{_iMv9siTl=l_>lsa;QO0M84?k%(_I_@~CrFPsWH(td016PFxplp7sw(iFxJaC0MY<(} zG`15OR&>2GxF=V%iys0a^gtF#26QUbQ%JlfkqA#?y3+(H9csK-2q24YgZ(;4Xdd%S z8RNHGxPIUS_rQG4U=ZYy6K42Z={FmO7es$x;N{}(y(}*!A}q)q=l9#WF2$-wi5h(C z%Ao#abI$@deyU@wNy2wwuzVUg%l>mCbHjyH@ZDgd4eG;>1o-al%^I6nAVVsD)o%0(H-QL^C^A>7dWtid%_xY;Lrw|IN@osm6v+|b*~%-h<; z$jQvc%1KpQGE-I6>l&@&fSpD9v;=ZkWjk>3IHlK1bYaR2@&a&-=e~nJeycNP*kf>D zBdBF}7nt8On89J5a)U{q*8ErW2&5XKIYpnD>ODJ9~+qPmPvK~|F}%W!ffM6T@Me)ORwj~YZ# zHDeq4Y{qYN^K8SQeZDkk$zA#jt-5IRa6S$D+22I<4$ZOzSTh70$ZfP8V69PewHfeI zq%=UX#zT{0R|Oy0hu?Ic(>;z=KLao*Zl zE_P3A4TupLoIGKeNU%boMcD7tl9<)?6Lk4)(P>X4kxnwg0&x>Dyi4-g3pFH2weScN)xg6 z3y~P24I(>2KAITFqfN|o_`s&3!__hnixnNDV`9Yf>C6+quGPx1d)X@JV(!tWVO@q4 zj6yVQf7ktPz+LQ`#@vX1Ir+oykA=GD7a&O8P5EKlI_6unj}66R%o~hWyzFtnanG9{ zXm}%#7rYKw4o(AYC8|e;WF!+~V-0tvmIha1Nb}{T6W#bh*=n;|&>BISxbhMX)L;)x+tgEf&7XKA zx=HG_3>ij%(3T*Mw3%s(aZ(m{C6XKsvMmAVH^zmPGwjWSf=4#V3&0DC<5LjEfAB1w>U{IBZhD(oy|hKb@m`7$eF zJq)BGc=Xeq?d@fIw^Xx)?Ms^WYNB!L+Gq9MrsgM5cs%3x-0R~p=3yb|tJ7&VrH(t3 zt{A?Qx1fA~B<6T=(|eekxK~bqG8>YzP-op|$8rnkUhmLj5(p;{xK{_u>{oLdI3pFgiI_E+dk;&oQ|+al_P7#ijx+KESe<^XkghSNf6T!1a^l}s2%3hjugeK6krGR zG7Jsk|Haxnh3DEW(SotHbP@RUb^$Sdl^Jc6NG<6HydekBt*E zZ*525_E%l$%>-kZoa~j!N=OQ)BaJV;CHQc^H~`Ot&Afi_zXD~27?kVk7AGB{8imI# zkN)NmP!3_250mY|iY3|n23Wl4I|+Maz@Xzb+|}SHbV_XOPNALbfR!9FpEz2mGBYk` zZo}2{{^g)|l4Q9{t-9$o9F5OU22Y<`t~NL{k1A#)x1%)r)QT-YTcK}ic#Vg7glxQ( z2D1kCwu)2hyBFN}uTm@Wa1|p&V$z%x#TV7qHr%D)9|(C3QvwB9=ws9tIa}d;r?+;$dFqL#DRUy;0;nU0%-K77UQwk8MmU1iP9C|C~j&- zw$rf5newVFr}6y*#rMO1=L(W=@QZ?In59pRR_6`tD-Z<|o$gPh_3vLS^OwPcj>-x9 z7wDpt9UA!kA);7h?m$f0_dA=o*7JR@2@5|vRAqX`G>#31qs?nm@3%bv zwFRJrHdinwrZwZ=rlSqI;=zGv!xHU!L-MU&sdHx7k=z#*MQA4R*GCAm>(zTb7U=&va=|agxY+?#)nR^buRq7I$MX%-Vv$ z6f>~&>sM4n)UAC+I%Yi!n+_g+_AJ`g-#YAaI%0)r$JIfqNcxUU}+gWczTF?L~6 z4@41I)dK-77}m=M8+gJlvvRRK9KS3tGL`x&jD6WDuuG8*;Y#nSZyCUUJpm|{{PJ*> z{zza;>&^<7$}3`D-@D6yldY?Hdk;##8W|~1-IK36O)2p%me8FKNyjzJ($4AW{FSQ= z?GedlIDVJ35pu%s3uH zVVy!yGXz0!l4(p&SpcP0ttW6w3;K0jMX-Mz^>nNJj1x(=q0BRO$jSFPer&=R&N(pP zl6jg{lnov#)@hC2Olu{2Z@WhDsx0g6F9mE%o z&OvVTS|J23opchHUAh|No_--KwbZ2SE}qpzqQ&2p_>;E;-cO^wnqutnHDpsM*?8y}pTYO`plZ)+d9*;XOM?F{>=*_owmI9ax2+?SKez zS4#$D%DQnWtXm7l{@(6?m@5Y898nH{0swseXe<9;kc#jzf0|Bf{_iu`$e^m zI<6U5H-Tq8#(&XX9$4KL(UTPv4LUSMghgIrF(E12igu@4P(gJkqsjb8y5{V+>DQq%d zO*(jd0LdG4kpTh0$yKAvl#F675W=}TL6rGpZvinRhG_Ji9aDPD`nwJ?et0MvLWO0p zF=e&k(v=fSrnINNi6wOVWs$|h!&|z%^i;c`XDBJC2ifsvSrN)>L_fUzx~xivk0C_nVfE7aafu&LC;3{B z_B~s=?24c@h(n`=y*$5gXyK)swpGMom_y?&dmc_53x<i48TwkM?FEh!oxjHoMh5iMaw)1% zBu9xyT~?YRIdNLaqLDzQ!^O}+9{a+Dar)g0;vlna%SIw}MBD!O{?Tyk|k z7I*9n5(kW_+q3LyAyFMyX@`^QGAC3w4ew9S`x)$fhw^pNNzL>vfCVE$BpV1n`$xRHkfx2Ep>Li01Kw2QC! zB`^Kp^o+t6wnCG##a!k{VQi;P%W-537$13#DFzcNW5w{;2FfhX8gtl|lNLstX<rDF(t=_S(HJ;Ms+Ogm-^bl8ie+BZhrd3W zp(|tsSNS%)cJuOEDRuXz3M)RG>L(<#7hKE#FaWf|$l`Z>N~t_IuNNsb2md9&lA!N> z&Yk-D7kM(&0yJ79Rp%~%Bi6;iy|h%{xMVk z28fHZfu37S%45mv)vfa?=zS~dvHSAaLu#~5n6W19@$OQgn5ivPQQaK`d@L3}VCC)n zY2`~Qw8R2dyG_QLNb3o`okM?@vWZ}{jZU~`EUND?IjcS z@4#aKftDZ2wweS$x5{^kW|E`x0U!EHwDw26{FT&wm$jo=YjU>UQ!kEtT4noTF~qM> zt_W0gm#&ZS+yCo!000ozEmi~gw;%rhp%rbd?__9Z?BGbNtON=GIKIqk@=rR54mto# z@rMtz{^0}vPrg_G>pO=3`k?Or{QD0!$U0tEa)1tHXy<{P=5;>6k`1mL7Y-Z4CXHwK|T^!iW~I@Q52zhlOQiRZ_5(|RFvyr`feqb zE5&d)d{&&IpcSLZdVePms@-Ov)S|X+h5eu6+FX9LzMq);}VJDwXxB2wE zJ`*aEBgdLO_WMSsD~G?1jDQ@m_4;P$YW(xjTGy7RN&?mvP0@0%E)Tu`_)Udj<|%AlvyAI>y(8jC2ffy%ME0ba*jOtmlo2wSVTDRy13E}NIVy?jT?Kh9n* zE6Ntfk`HQSEm#7E4vt@EV*G5s))o(@C-bYoO%o>wh34IkClTIYz&_7*`@KlNuwzJ% zho++0JAP?(^Wx^P=H&Yw%qd_p9je=yDYDfY6?8z~0UKU(;FL}h+Nf^R9bA+&s&!<) zIk;!6OjW$TEE45dPkV)kHxpI|WvqhV(3qd*Xl$C29ma#grVJL$f%Plyk8^^8(y|B{ zP^W_Mdp&iH;HEC}5CRT;>_0R7amKD(346h(HEY^~)oT$uy}fL`Rdkp8n1JD)BkCEfX3(Y3pi)cyzEiqLaBS>Z+JWu-XxA zmH|7mj4TMAya65e6ngTcjjXc5lSCw8uZ=4|OB|qLvn1at_F;iq`EQ$u&n$=iHv94m z{Fk+Cfo%S5*R2ao9NE=G_E(^n@I|FlMa|#L`{Ft(Kt4VZ?$NSALe56Wbu`?NgR?B+ zA|(EuZCMK(nF>CQu^s}Y#Wx2O*A3QL3NmPZVudwew{=F7_2wq5gZ&Q+07wqFO4Ig? ztZ$;w?x^)ym>A#^=ch~#u{ayn)lF(q_i^rYgf?;FscMy*sKhhsX^6Tuu>o)*0`w*>LUGP{5MWpckCq1KDRc89Rce$7rok7;MIOR-q-nAAUS zlM7R2giRKG+ zMV9`p%MU_@?H@=;bRcqkPTl3mRp<>-&86k7_IAsvUyXz^dxhiYDZ3drKJDUd5QyxD z0n1(AIp~bLvh33@*n1kd|lX4q%*%{m~g(HeVA}E79#JS zM#A6hnY!o(%lqM0(l+QiGT=s3KP4IGt-N5s={3RDv^B+}ytEZS_-W&1CQF42_QjhK2X3rd(q;EH1}+ z9X-+!tLM>aUF9DHiH^ClO^^(wRcJGGQ1q8+?S^fP_F&ufvc+CY^S~D7dLf`g8OFYr#-9R#*;u}%!pNR9 z5i(4E=yc4O6->gfGTQ6BG`m)aZ70OSf*`$Cj8->Tt(&^|Qi|khVH5{M0ohrJ1LB+; zydvAR`Cd3$N}g17aRko!Ho(-7dzUcMP5X4_a05RLQSyr(u0Ac+Sg#!hm7I;&W0jqW?@_(C!V4;bhqQG+ORo7tPIK@7nZ%YhN&Q)(ucb;`DRGh8KGAq zrfR#_kv|@sX1BK~1ZA>;fHu1d1S}V9cc4YI+Li!EfmanJf@KesOD}XlrB#A%KHuWr z#Sc>4yy0maJA9qT#7vmdIP_@}KhNk7ou>{+CgDR~8Rqq8ykTH3&Zb!Nyq|`%?|$NE zJ(w*Lzt!?X?LuPESp%PB2@^)mu1RA?Ljn<2>|SP*v>pt6a(Hj+e#tXrHGd@{g%X42 zm<9*Dj&NHdx=vK|3ymC3$&<3)AkGueMo19Mx=eZG>%#?oV)+zR`X1uKNt-P5AR1hORWk6+&E#W zEW^h&@4T_^j(@y-Yh^d?40aoidfWYm!~827kx%Efd`jHs-`3#r`_IW7a4O#?|0|Ytn|Y|T$f#)v z$QOQhQ>ib|KcVt?jyuc1aEY$}kUykg#0w_(|dAI>wK%)v9IP3FqM+3@rd`R6m2eiYonQrNg&9 zyU~`jmdRiaT)lgpZQ@fYBB8gdvlFj4x*a96wM&=~Ae@O4cO`;BPQ$0}N`#aS*0fgh zaE%9^lodG(Q+3Qp{`XxjFcvZOgU=C7C_~IZ5paS~Y#;$iw7e z$-uow)gRf0t5k$hRvSeGG^CZ;mIn_Uv9LV;85>O2w84l~ReSJx~-YV9rjCtzs|NE=73B+gpT_Rf-d?xluhZ=vO2Hk z9o9dSf^5r7SN$g;)PGv)|Gy>0KXAIr4|6Ai;C-ShWr!Cyt0wg>#tCK=5d(P&HYdGN zIu!9+JTgJjz!i0f{_jopk#v$#r%YTb&{5zZvFS9-&vsCIEp#{BfKwPyCfSBy!^*AG+uO|2GRfRRl%w-sr{~D?_P#?v<@8m%!p`meHm4>V;MC z=k1bb>`cTdQQw>u>a0*m2|^X1Wbl=_*DMbE>A?sNU4Py`54LNAUtp18Z;fYLbXj1~ zEV`4&efu;p1TLJpjdtg;zPO--Cs7SSgEz882@Eo=kp0G53g;%zv8(nI^p+u$dMZU( ztJqc%`{zuuVu2F(P1BK%=4{PHX_LkwYYB8Zsp&_$arWtT$~9t59XW*VAsxH)D(eG* zhHE>#*^ANh(4})EGVRL<=XjKp-q?H%3e>lGt2By;tnRsS9;kQBD{6upl@WJYHIP^Y zyYrjqW>|ipsg}PZd+yHh5-#He#Pw>U-9FHgv|h%<5~AMph(jg*6seYr7HkFOu6nV2 zU6A~aUHkE414*<*vZpFsPZ&;|Jzt5H8TkC4 z=b`@XyTNVRnNr99q+Si{+duANv=FvyEx{SuzKMBxz~)mGh21|in+|Ihbl9moeBy0uAG`YE znP(CFqVj8*{5vCE!&)bSR?)~{XwujaEg#E*Hj`-Pqknst$=H6`;3v=bwF3*XM zu^=_9OFhn`ii+=#=!e9(qyrC*Y+S!p#)I^k9agyPJ^%|tf&p9f5`dynIy`fk1QuzL>n-V*6fJhy%f@OlpQSzeB|mnWA#dongB6Ool~{huzb zCpuH4D?6o)<|n}F4*nyUie`Jl;jwi03a4O}AHrlX^QNtCPOvoxVTci*bTK2+yfiQr zeFgopJOvX$H(&~ggY7FZSdl6U_Q*A^hM?iMFncou4X9Sp940s>rBE~2k(SJ!iKQvD ztMnLuC`<6`Mvw|#CUVjt(*a2U2(^&AdqK%aR3Nl~ZIICX3>0C7t;yC;F4a?JM9z5J=$>ty5&bLx50UXwrwX11{D2 z*PrAagTLIZ^H)=s?G>qw?L(OtTA-#iB-pT4HrFZbQcQ7q1N1F|OH|wEwWQb`2mo9z zHa6tZ_KYU~dU$?+41F$+?K^dLp}}unVya>}Ssu^OX0JE0eA$@=%bLn=cq{_Wo+U_u zj^&hw+QBoC;7eT=(vfez1)%)?%A;kYeYoca=AH-&v!fluS-@OAzV{K*1pkJ z9mv2E1}J&R7z?~oP?VMxr2jGg158DqAZ5KT)G%3SZV3)Q$_2{ae61`hM02Q=r>_)n zqBPm<>qz1Xp;ly%8*#tlURt9X@ZjWKWTsBDF{!iQNWRWBh(CAy*IT;u?OxMaR|xN zCsFOW>7G@=oa`u0Zd~DgO=Y?ABO?&IbKji#y*1$77E4E?INF3$SJ?~ogUmZOOG$;4 zPF{@ELRs^ao7k7a4R!+|I-8P7r)2OKtD`UJ`8C*1c*iZ{5JA_HHleS^QC!QVrtUjZ zXu3Q;t(J+n24mrs4@oB+m#%Z?iwtVbOy^EOx-wHlgCErEuuXz?dp)EkPw zI#c$+EmgH{-;HlRv(0*YmFJm|yQGB&Y+@{tEADA-l(s@XPsT0yj-~F2gZajxU9%Y} z%XiegXJTdxq5IivEIgUl`GS)__S4A8f7q_Lj5yX={2IaP<}7inAY&=sGVq}MNA1b?d_R}pP&V@E-a*-in0Or{h7Mkb75X$?uxRg!=e z6pT_vwLQT3i?TT&pZ8Xs`at+!GGO)T9~m%g)zLEkapIaK(}THa9xTKO09$=xV-i`b zK0=c5SuF*#Zl?5X|Gqv~Ssu3venIP*XixKOE@_!q4RHp-@La)7RvlLPV2c<+j!-u3 zXhm-0uSI7sD#K04$uZE|1ukC`sXG|!X;79(|Jugs2GDjAN3d2p&VW=i>K#2!gb?N~ zQ*y`wT)9cLOzrq+_+gCZlJ~gf{2A&Y-P1CN?3C- zKw=amnNFpfp1%GwG}`T|x2mx5t5|#j<|W6I?Zk;{CAfK__FT2EG#x0nob3Y;oiSNi zKtqXbUjg!qOEImtN=nXe9D$}%f&!vaX)2ws?U+6Vsb_!?YOE4TCL4LgVt5swppLC3 zA|tu>PnN*A<2lAhpEU-XMSdO<0y41PxCZ@1QbqAe$HUvE`|?7Tgp~FITDAyj$J6XQ z_MXwBlNH(TSY#?xS#~IRnt=;L1B0u(q_omqU9MNvx#%yr>j5&i`@pe**K3xJ45@;< zYTr*wl&C6hiX&p5hK$|`wp?O}fi}b$>PPsqU6zY7O%8SKTuqfRs3hjd`lVmn9-OQt zNi5ZDrV0XeVf89Sr?3)ZC1w<20|`gF{M????wiay4B>+1NHYU9KY7)ZHC5x107F(# zAk5jg?lWUy;R4h6(PghJ(F_l^JKM<7^A)(h)p$I&(J({;?Pyk1w*u)B*2ZRKoA1Go z?C%cEYqY{renDnBDlKvD-C>|`+L@*{n(3e5`A+AqvXm$ zb+87y?;6Hw;mTSpWYq($!{dRp!xQFGnb^DK5Xc1-c)QbjTS6CTNh+x_{0EB#Gm`F* zlNI&QX!+nvXTAap>h$OK0mOJbc;JcJ(XpMDcr(Y6P{&170H{1atnF4gou$?3NNAqQ z9$y;9hH7#wL$?;``SzUHROZNEPYLawY<=EDe#rBJ5+SxXfN=D)&h)-~Oqq+9Ql~)5 zJ{8Vj&wT#}MksTRK;T#C1GzN?%bX<#_?$dar*^tkE zeaap!3?_#;J-&HGx{)_4mK8Ui88+pahtzB|ZyO{`3r{Z^tj&hSYcPQoNhq*b!{;0L ziWPV#F)`8C6J;?^O0Ol5hl_w@QI$`MNm1kMZDX~=1Hr-zr>aY!&?sI+otwM)dYhCW zP?N_wh09}pE5tntW{ll_G8aL!^Wl#^nfjA_?R|*#C3x}sL$hQ)$-9R02radXSWOcZ zxCh(&L8kj@g%L>0y+u?JOOa2CQJl@{y0q#c+5J*MG3dvqMYw|D*CEsLlgppwzYk%eVJsGDtwiDfsk$eNr`pDPZ*8vHMI_R6g8XchQ>S0>Ls- zxfTP2?niE7LQWum#*C$s^;=-4=lzm)^yfG98fKGOSRYrjBLY&$BMpWl{9>c-LBv^@ z71Gvp*SfiZp+e8f@=&h>E3EHJK`{g?E>Jh)5wDSwK~7mv!+&r~Us7m@f(66rw}{A( z4;^{6Hz;g`L!|JGbBq4JRu}vr5Ez;eP4Xd}F|wrZn8AWCb@ZU0y|}a^I&lfzvQ6orgE@(xDwpkhYSb4A5@oC7(c&& zG`G{oLAjV;7yURXl}bdObdWs0;p{>evjP{B>^sb^+TOefY-t8Mkv6i|aHiqe$A9aZ z5GeevRq;#;D|(%fm;s@0RKc20=_4j3KDo^`;g-(N*l6fll8nnOB)6xF^IMWB=g;@s zvDfcqHTK_pHwg#re7{%c5FeeIvLSpt*}c~CSbv}E+f6+NhQ z-tnHIccSQiCbM8ZX0s{jW5P4Oge~p{*hre~E?oU!@eGmS!|f`AGfT(xWSY>m#xLze zB=$6tBAwGW5HODN#)EDBwYU&GQ#J7SPr%%0d}**=dB)VTzPSYMkOv1~>^Nuc`M%tM zdg=>WPFFrlUL}&>5IAJ*rsczR_SrCgR;Mo1YQ}^=Q}dVUzWU+5mBa3%W&s9b7j(Ia z+2T@Ii^m;uVi@C=M7}TLx$=>m`7%HUi6k1CY6#=ME@m#o$#D^ygC*KF$-B|{k=hd%t6}ew=X=;_;hqxjIN*O zCb?eIt?Z%2u|6&MIu+R2; zP;`h7=GI*6Qs?e@A?a1X@$ak6BmF}1yTJFVoIy{+@n$&3NcQSNh#ptiI&;U1iL4!I zB}44yK0t$mWTQslRX8EsSt$aSf$_z!Tsr*1^~Vt#ZJ#U`6cbm?j{M+7*u83bdrQeC zAG_+$g`P?FSzC`14&I|0W9UquE!*WMj#JUlP(i{c&Z)=_Mo@om>+KDQ>Xtm`)qrT0 zA}gtynpT~47F^3Mu*{e43e(Dz%eE`!;#IEO%ZAC6!0&whmhZdE3fiM5YVVgu=~UtE zL|N-NLDOdC=)qqZ8)vnSxUsAgs7#478;9i)t}L*`2hY@YxXpR#W*-+lmqk58E3axQ zlQQVQA0S@jq(<`vx~GS_W(v|zCD}>e4rQQIU_AcJu4@81!HWe?$i<}q+zL#jpXx@L3C2?sr^gFcv%grYF#dB`9KuOuv*d><{)GAe1@8Pi z)}K0a6{6@Q0P#8b2&nc>+hv2;I|-AOb?s0Q>u*m}YuaP# z_T&E0cVIWulcRJ~Q4KwU=G#_KMEHKjLrZe@(v!ZX?&VX4Qk^kW%L8B!t zYAvwebx4mNoA1hg;SIyHw$qntZpZ!Z#f}wY8!&dV=Z5B$B^9vO#@cZO|Gq6be*%aw4?9fvtC&5gOf61mxZDgpAQx56ZR zmI>xjPNfJ@HBAd-=gt;}@;rh?{A4l~xJuKA9r{3KjZhM@z3eO7BtFXNX^DBSZ_r1S z1X9>4AhS$=OwH{yOjsu*M^CfL05}NwIdw=mDJldbt+_pHgDNzpUHW^!)dv>Y`le3l zM#Jp=kVc&=EAYk@2-U@XUyVg$KYR7)I&KU%s9VGSAb{MOIr{Mwhc;xZ3 zu^}aaRmzf$xx@H?^{PM#hKx%W!))LW2{3P*5!AgN0Lqp(Y*6LBGhROT7@D>{S28^| z44CzsFE8MFC6JjfcA==U8aB(mi18rEJg~9UQ!NztB>4^W>o7**)cIA;NK3KeWusb7 zWwwA0m*YQ4Jd&ndEt&CD*Fx41K#GWDQsp4mR>kwhrEMf93@*<*3qpceN(DUwZ{WRB z4@oFGYlB$yg@AleQ)no)MN37l4zyN8qL%S6!bO_?1!r7a0RrKRf0`g}ze*nVBdSJC zg2(UpQ@y2VlVhj1|GWj9#Scqgo#pqPV7z;W_InftcvR`=qR$UhH`^mv_5ruj`hPsJ z?C?8zINVqGGDCqSp4rQN+7itinRuQjRg%&-asyD)uN1B|hOGrPd3M1+rA6m%S!C*z zt@FyAjYO3U_r(MRQiF<~k*^?YnxjUBO#Kbb7XQ%g>%8ChOz&=$7h+m7yMWX^Q1Y_;|<5|48rghLh?^b%lHlR- zKom>XTINX#I26mQxw4jTEuudlT|0bt?tBg;fP7^Yvw%~&GWRv$$?x z;=PABbY0}%Er0i>({@~4#QH@K_zs!^hPILgROa;S7Md|R>4`pr{*$3;X|xW9|0&)4 zKUT;84MX$4WA*PRRP6 z>ic8rxgb!(!=bm5gzNY7lON|K~Si%P%GF#-c# zgx937#%E4WOe`Fb?&>PNx`{>^B_wmIgp+lxBUmfMSU16vk%1&->o&OLRe%|J&{-eSDN|SFl+TxKEwiM6qi9x(XW^NBOk|P7>l1nGO7##5tEj< zPRtbts1;WuKbSAH5vmd!+}(E3N>6HWcBRetxpsZY&!UQBVvEs<;=A z$tZ=?hEG~Qp`drDcaPx)z8c}@jmS~gLA)RPqWF2FSp3!>c(Ty-_EKQ|Dd$@02JCSy^o1AVIX+h8z5ZM>Yj@o;9j99ms1!UOtvB=ImhS+zOD zz}~pxDasBfIDmG1Y|j41{pXR3d8muE`YDf!KgW*uzaWR~o%L;;%uURHq|g5-kjV+! zKep~DAvX_{aMvRGEgcg!Fn>D`vS2uduO*~nS>zIF*o!ImeRVZ1M6+QgrP;^acODL{ z({2PUrJYoMwTnZLWC`7a6lNh=Q#nQ}nvabt%U}rB7%=fc_N!S+BAhd$ZsJiD@fqJC z^317~qr!CgkDSwQAt1IPcx3*IG4yYi$~NFhryfWbv(|KB6}?`8B#&H7(u^lMv}-ogOS6|E~)PYU6dNdA$p>tng*h^@`VX zIJm1OR7xS2pmyMH*Gksi;7U%{{aUcneTl<)`pL7D*Um?q)l+pVvF6Li!~M+3v%2xZ zrPTV0On=8n0o!*q?QI0NM`IdPbu){S21``322nJB_H~Arm z99UKze*dI7AV|m~PI|f{CnqB;7~Bz)h&4~MebQJPJ|a+te%hrGjT|cBB0kPe$f9(! z4}qY}mLY-Nv?I4dmwbc~;YJR&JZ)I&q%yi7Z z+0sRa2ucPHlqxE;N(Dt>dIiD|?#UwMNFlf=`!P%l^J_TqYKUz+p^J}7VV)*KPf$>I z$xYPuo;<&Ta(ung7?F#sf202SRY4+$DuodhA#oX_kbTN1t;9LMcbU}@;-r;%^EpK{ zJDwL3loeI7hnAYQ7JaE0&oG0|T5CwN4tE_Hbtrmyh|b_G^F+SYjrR($;ShQ3>I z3aj{)aeJo<2lKWooE34AZ&{_Cx+UL`LjRNDOXQuG*)T88-ut?Cs{Iq!8vz%tEZ*NG z+b1;9-~=0uNkg+?m;Nq4aX*FHWLr0eo%_QM*>fieUKw~re=9<3L6l*0Q+c4-!4JK! zJht}JZ=2^0b=(5ODL^-m#UaiZswQ_VX160;eD}?@=}d5)iYL>EKa0lGh&C+SJlCk^ zIV}ti?VP@S>E+j4xs(%=QyOBK?uln!jG2@WG+5MI2PPRTtFbBlZs6&q*R0m=Q@oJh z|AAh))&(u~f8-K7KZlv`zbMZR`ZlJl#SJzTpO;#;q;#2nVjFiR ze@w9kYg4j`goaLAkyX<0l9OSw|Dn&Vz=;n z?N1EN$k)->TWCD*`_=iO)ur#Bwp-q8`01LE!u&?*d9B@J00#U3GFZfS{uF^!=xBwy z(J7t}tvASV_loqAzmF#34x59MQ@G=LG2}e&zfQyl%YY=aK#k^@QnY4{TUwMJ!Y)7| zp;$zd>i|-NgFQ!zT0Gv_TluhL;@wk9d}{G{zDfCSHW=W>+FXqHAx1$H>nmNlM&?dlWL0ISYFfTB4f$ zz!4Rp7}l&5lL752z}(`BSP|hP+IaH##sU>f=w@We7C* zwf}ZWNy&rWDq*H%hD|e$_PNH*DpgPpQJn#|7Xn!ubfQ2^1h81CF_+t~{0K3nTB=99 zOEys$K-}C-ikwDrUPaKYAm=9&2$;Pn^pjFDHCAVqH@SxtWM6Mk7G%kDWgMu@rYNf} zoL3(gox)tNSaj9AH$=lPULvcd_!`8c|9kmM>N44f=(a37Gjb`|jl0%CrKv zvDNHtHqNwkT%+df%Ox!85^+AR>Y;o#`!K05Ud;yzb-FkxGv{$fEipEroKXMAUGct% z{pX!^ozTc_8#Y)ipPwO%X6aEH@w9illlKUx4Z}D17zs!*L==lAopbZWR?vf#4hr-A z9o0j!m@4N>Sd)7NBbI#jZRNpeVZ#tcJckF^cn_(QzVe=2yU_nJLndQgoddK}Il^

#@v}-4EpifPqp3f*6a>&RLL=Yfg4#X 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

Pv~ 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 z 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 z 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%0AkqUvE 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®1koUtN5iMo%5ya_-<)O5%>D?QQZS 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 z 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 FP7_JVf!Y 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

w@MS(NPx0W@rlR^Y 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ð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 Date: Sat, 16 Nov 2024 20:59:41 +0100 Subject: [PATCH 039/102] Suppress some warnings related to old CMake versions support --- CMakeLists.txt | 2 +- scripts/CMakeModules/version_from_git.cmake | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f25b75d8..3a9a05bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # Codac - cmake configuration file # ================================================================== - cmake_minimum_required(VERSION 3.0.2) + cmake_minimum_required(VERSION 3.14...3.25) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/scripts/CMakeModules/) include(version_from_git) diff --git a/scripts/CMakeModules/version_from_git.cmake b/scripts/CMakeModules/version_from_git.cmake index fa5542f1..34b6c491 100644 --- a/scripts/CMakeModules/version_from_git.cmake +++ b/scripts/CMakeModules/version_from_git.cmake @@ -20,7 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required( VERSION 3.0.0 ) +#cmake_minimum_required( VERSION 3.0.0 ) +cmake_minimum_required(VERSION 3.14...3.25) include( CMakeParseArguments ) From 6674442637afc96e2c08d274dd112fca6572ef91 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sun, 17 Nov 2024 16:12:42 +0100 Subject: [PATCH 040/102] Test specific IBEX version --- .github/workflows/dockermatrix.yml | 8 ++++---- .github/workflows/macosmatrix.yml | 2 +- .github/workflows/unixmatrix.yml | 14 +++++++------- .github/workflows/vcmatrix.yml | 6 +++--- packages/temporary/gennewcodacpi_armhf.sh | 4 ++-- scripts/dependencies/install_ibex.sh | 2 +- scripts/docker/build_pybinding.sh | 2 +- scripts/docker/build_pybinding_codac4matlab.sh | 2 +- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/dockermatrix.yml b/.github/workflows/dockermatrix.yml index e311ea61..1b84294a 100644 --- a/.github/workflows/dockermatrix.yml +++ b/.github/workflows/dockermatrix.yml @@ -70,11 +70,11 @@ jobs: if [ ${{ matrix.cfg.deb }} = true ]; then \ sudo sh -c 'echo \"deb [trusted=yes] https://packages.ensta-bretagne.fr/\$(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 dpkg-dev || true && \ - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb --no-check-certificate -nv && \ - sudo dpkg -i libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb && \ - rm -Rf libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb ; \ + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb --no-check-certificate -nv && \ + sudo dpkg -i libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb && \ + rm -Rf libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb ; \ else \ - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv && \ + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv && \ unzip -q ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip && \ rm -Rf ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip && \ sudo cp -Rf ibex/* /usr/ ; \ diff --git a/.github/workflows/macosmatrix.yml b/.github/workflows/macosmatrix.yml index 7a598d6b..4edfa029 100644 --- a/.github/workflows/macosmatrix.yml +++ b/.github/workflows/macosmatrix.yml @@ -60,7 +60,7 @@ jobs: - run: brew install graphviz ; brew install --formula doxygen ; python -m pip install --upgrade pip ; pip install --upgrade wheel setuptools sphinx breathe sphinx_rtd_theme sphinx-tabs sphinx-issues sphinx-reredirects if: runner.os=='macOS' - run: | - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv unzip -q ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip rm -Rf ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip sudo cp -Rf ibex/* /usr/local/ diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index 4e4212d7..5a65a3bc 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -120,23 +120,23 @@ jobs: if: (matrix.cfg.runtime=='mingw13') - run: | choco install -y -r --no-progress eigen --version=3.4.0.20240224 ${{ matrix.cfg.choco_flags }} - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex.2.8.9.20241103.nupkg --no-check-certificate -nv - choco install -y -r --no-progress --ignore-dependencies -s . ibex --version=2.8.9.20241103 ${{ matrix.cfg.choco_flags }} --params "'/url:https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip'" - del /f /q ibex.2.8.9.20241103.nupkg + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex.2.8.9.20241117.nupkg --no-check-certificate -nv + choco install -y -r --no-progress --ignore-dependencies -s . ibex --version=2.8.9.20241117 ${{ matrix.cfg.choco_flags }} --params "'/url:https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip'" + del /f /q ibex.2.8.9.20241117.nupkg if: runner.os=='Windows' - run: | sudo sh -c 'echo "deb [trusted=yes] https://packages.ensta-bretagne.fr/$(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' # Replace this line by the next ones to test a specific binary package of IBEX. #sudo apt-get -q update ; sudo apt-get -y install libibex-dev libeigen3-dev dpkg-dev || true sudo apt-get -q update ; sudo apt-get -y install libeigen3-dev dpkg-dev || true - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb --no-check-certificate -nv - sudo dpkg -i libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb - rm -Rf libibex-dev-2.8.9.20241103-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb --no-check-certificate -nv + sudo dpkg -i libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb + rm -Rf libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb shell: bash if: matrix.cfg.deb==true - run: | brew install eigen - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv unzip -q ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip rm -Rf ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip sudo cp -Rf ibex/* /usr/local/ diff --git a/.github/workflows/vcmatrix.yml b/.github/workflows/vcmatrix.yml index 1fd297b2..648b5977 100644 --- a/.github/workflows/vcmatrix.yml +++ b/.github/workflows/vcmatrix.yml @@ -63,9 +63,9 @@ jobs: - run: choco install -y -r --no-progress graphviz doxygen.install & python -m pip install --upgrade pip & pip install --upgrade wheel setuptools sphinx breathe sphinx-issues sphinx-tabs sphinx_rtd_theme sphinx-reredirects if: runner.os=='Windows' - run: | - wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex.2.8.9.20241103.nupkg --no-check-certificate -nv - choco install -y -r --no-progress --ignore-dependencies -s . ibex --version=2.8.9.20241103 ${{ matrix.cfg.choco_flags }} --params "'/url:https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip'" - del /f /q ibex.2.8.9.20241103.nupkg + wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex.2.8.9.20241117.nupkg --no-check-certificate -nv + choco install -y -r --no-progress --ignore-dependencies -s . ibex --version=2.8.9.20241117 ${{ matrix.cfg.choco_flags }} --params "'/url:https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip'" + del /f /q ibex.2.8.9.20241117.nupkg - run: | mkdir build ; cd build cmake -E env CXXFLAGS=" /wd4267 /wd4244 /wd4305 /wd4996" CFLAGS=" /wd4267 /wd4244 /wd4305 /wd4996" cmake ${{ matrix.cfg.cmake_params }} -D CMAKE_INSTALL_PREFIX="../codac" -D BUILD_TESTS=ON -D WITH_CAPD=OFF -D WITH_PYTHON=ON .. diff --git a/packages/temporary/gennewcodacpi_armhf.sh b/packages/temporary/gennewcodacpi_armhf.sh index e6300d72..eab7df2e 100644 --- a/packages/temporary/gennewcodacpi_armhf.sh +++ b/packages/temporary/gennewcodacpi_armhf.sh @@ -26,8 +26,8 @@ fi && \ sudo apt-get -q update --allow-releaseinfo-change ; sudo apt-get -y install libeigen3-dev python3-dev patchelf || true && \ python3 -m pip install \$PIP_OPTIONS --upgrade patchelf --prefer-binary --extra-index-url https://www.piwheels.org/simple && \ 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.20241103/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.20241103/ibex_armhf_\$(lsb_release -cs).zip --insecure && \ +# wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/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.20241117/ibex_armhf_\$(lsb_release -cs).zip --insecure && \ unzip -q ibex_armhf_\$(lsb_release -cs).zip && \ rm -Rf ibex_armhf_\$(lsb_release -cs).zip && \ sudo cp -Rf ibex/* /usr/local/ && \ diff --git a/scripts/dependencies/install_ibex.sh b/scripts/dependencies/install_ibex.sh index 069399ba..40c682d4 100644 --- a/scripts/dependencies/install_ibex.sh +++ b/scripts/dependencies/install_ibex.sh @@ -4,7 +4,7 @@ cd $HOME echo 'Installing IBEX in ' $HOME '...'; if [ ! -e "ibex-lib/README.md" ]; then #git clone -b master https://github.com/lebarsfa/ibex-lib.git ; - git clone -b ibex-2.8.9.20241103 https://github.com/lebarsfa/ibex-lib.git ; # To test a specific version of IBEX... + git clone -b ibex-2.8.9.20241117 https://github.com/lebarsfa/ibex-lib.git ; # To test a specific version of IBEX... cd ibex-lib ; mkdir build && cd build ; cmake -E env CXXFLAGS="-fPIC" CFLAGS="-fPIC" cmake -DCMAKE_INSTALL_PREFIX=$HOME/ibex-lib/build_install -DCMAKE_BUILD_TYPE=Debug .. ; diff --git a/scripts/docker/build_pybinding.sh b/scripts/docker/build_pybinding.sh index e3e19dc4..f9a50cd5 100755 --- a/scripts/docker/build_pybinding.sh +++ b/scripts/docker/build_pybinding.sh @@ -2,7 +2,7 @@ set -e -x -wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_$(uname -m)_manylinux2014.zip --no-check-certificate -nv +wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex_$(uname -m)_manylinux2014.zip --no-check-certificate -nv unzip -q ibex_$(uname -m)_manylinux2014.zip rm -Rf ibex_$(uname -m)_manylinux2014.zip sudo cp -Rf ibex/* /usr/local/ diff --git a/scripts/docker/build_pybinding_codac4matlab.sh b/scripts/docker/build_pybinding_codac4matlab.sh index aec5e103..d0ea4b3d 100644 --- a/scripts/docker/build_pybinding_codac4matlab.sh +++ b/scripts/docker/build_pybinding_codac4matlab.sh @@ -2,7 +2,7 @@ set -e -x -wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241103/ibex_$(uname -m)_manylinux2014.zip --no-check-certificate -nv +wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex_$(uname -m)_manylinux2014.zip --no-check-certificate -nv unzip -q ibex_$(uname -m)_manylinux2014.zip rm -Rf ibex_$(uname -m)_manylinux2014.zip sudo cp -Rf ibex/* /usr/local/ From 3a367816caf579d090cbbe6738bdaf87718ba926 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 19 Nov 2024 16:21:30 +0100 Subject: [PATCH 041/102] [core] revised matrix types (using EIGEN_MATRIX_PLUGIN) --- src/core/3rd/codac2_eigen.h | 48 -- src/core/3rd/codac2_ibex.cpp | 16 +- src/core/CMakeLists.txt | 29 +- src/core/actions/codac2_OctaSym.cpp | 21 +- src/core/actions/codac2_OctaSym.h | 17 +- src/core/contractors/codac2_CtcEllipse.cpp | 4 +- src/core/contractors/codac2_CtcEllipse.h | 6 +- src/core/contractors/codac2_CtcInverse.h | 2 +- src/core/contractors/codac2_directed_ctc.cpp | 104 +-- src/core/contractors/codac2_directed_ctc.h | 2 +- src/core/contractors/codac2_linear_ctc.cpp | 10 +- src/core/contractors/codac2_linear_ctc.h | 17 +- .../interval/codac2_IntervalMatrix.cpp | 92 --- .../domains/interval/codac2_IntervalMatrix.h | 145 +--- .../interval/codac2_IntervalMatrixBase.h | 517 -------------- .../domains/interval/codac2_IntervalRow.h | 27 + .../interval/codac2_IntervalVector.cpp | 156 ----- .../domains/interval/codac2_IntervalVector.h | 125 +--- .../codac2_IntervalMatrixBase_eigenaddons.h | 642 ++++++++++++++++++ .../eigen/codac2_IntervalMatrix_eigenaddons.h | 25 + .../eigen/codac2_IntervalVector_eigenaddons.h | 183 +++++ .../analytic/codac2_analytic_values.h | 2 + src/core/matrices/codac2_GaussJordan.cpp | 37 +- src/core/matrices/codac2_GaussJordan.h | 1 - src/core/matrices/codac2_Matrix.cpp | 67 -- src/core/matrices/codac2_Matrix.h | 101 +-- src/core/matrices/codac2_MatrixBase.h | 359 ---------- src/core/matrices/codac2_MatrixBaseBlock.h | 89 --- .../{codac2_MatrixBase_fwd.h => codac2_Row.h} | 9 +- src/core/matrices/codac2_Vector.cpp | 72 -- src/core/matrices/codac2_Vector.h | 67 +- src/core/matrices/codac2_VectorBase.h | 120 ---- src/core/matrices/codac2_arithmetic_add.h | 20 +- src/core/matrices/codac2_arithmetic_div.h | 6 +- src/core/matrices/codac2_arithmetic_mul.h | 36 +- src/core/matrices/codac2_arithmetic_sub.h | 12 +- src/core/matrices/codac2_matrices.h | 99 +++ .../matrices/eigen/codac2_Base_eigenaddons.h | 136 ++++ .../eigen/codac2_MatrixBase_eigenaddons.h | 99 +++ .../eigen/codac2_Matrix_eigenaddons.h | 19 + .../eigen/codac2_VectorBase_eigenaddons.h | 115 ++++ .../eigen/codac2_Vector_eigenaddons.h | 72 ++ src/core/matrices/eigen/codac2_eigenaddons.h | 23 + .../matrices/eigen/codac2_eigenaddons_test.h | 25 + src/core/separators/codac2_SepEllipse.cpp | 14 +- src/core/tools/codac2_Approx.h | 12 +- src/core/tools/codac2_template_tools.h | 10 - tests/core/3rd/codac2_tests_ibex.cpp | 8 +- .../contractors/codac2_tests_CtcAction.cpp | 2 +- .../codac2_tests_CtcCtcBoundary.cpp | 7 +- .../contractors/codac2_tests_CtcInverse.cpp | 10 +- .../codac2_tests_CtcInverseNotIn.cpp | 6 +- .../contractors/codac2_tests_CtcPolygon.cpp | 30 +- .../contractors/codac2_tests_CtcSegment.cpp | 20 +- .../interval/codac2_tests_IntervalMatrix.cpp | 114 ++-- .../interval/codac2_tests_IntervalVector.cpp | 16 +- .../interval/codac2_tests_Interval_bwd.cpp | 20 +- .../codac2_tests_AnalyticFunction.cpp | 123 ++-- .../matrices/codac2_tests_arithmetic_add.cpp | 4 +- .../matrices/codac2_tests_arithmetic_div.cpp | 26 +- .../matrices/codac2_tests_arithmetic_mul.cpp | 80 ++- .../matrices/codac2_tests_arithmetic_sub.cpp | 8 +- .../codac2_tests_SepCtcBoundary.cpp | 6 +- .../separators/codac2_tests_SepPolygon.cpp | 30 +- tests/core/tools/codac2_tests_Approx.cpp | 7 +- 65 files changed, 2018 insertions(+), 2309 deletions(-) delete mode 100644 src/core/3rd/codac2_eigen.h delete mode 100644 src/core/domains/interval/codac2_IntervalMatrix.cpp delete mode 100644 src/core/domains/interval/codac2_IntervalMatrixBase.h create mode 100644 src/core/domains/interval/codac2_IntervalRow.h delete mode 100644 src/core/domains/interval/codac2_IntervalVector.cpp create mode 100644 src/core/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h create mode 100644 src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h create mode 100644 src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h delete mode 100644 src/core/matrices/codac2_Matrix.cpp delete mode 100644 src/core/matrices/codac2_MatrixBase.h delete mode 100644 src/core/matrices/codac2_MatrixBaseBlock.h rename src/core/matrices/{codac2_MatrixBase_fwd.h => codac2_Row.h} (59%) delete mode 100644 src/core/matrices/codac2_Vector.cpp delete mode 100644 src/core/matrices/codac2_VectorBase.h create mode 100644 src/core/matrices/codac2_matrices.h create mode 100644 src/core/matrices/eigen/codac2_Base_eigenaddons.h create mode 100644 src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h create mode 100644 src/core/matrices/eigen/codac2_Matrix_eigenaddons.h create mode 100644 src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h create mode 100644 src/core/matrices/eigen/codac2_Vector_eigenaddons.h create mode 100644 src/core/matrices/eigen/codac2_eigenaddons.h create mode 100644 src/core/matrices/eigen/codac2_eigenaddons_test.h diff --git a/src/core/3rd/codac2_eigen.h b/src/core/3rd/codac2_eigen.h deleted file mode 100644 index e0d4fbd8..00000000 --- a/src/core/3rd/codac2_eigen.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef EIGEN_NO_DEBUG -/* Disables Eigen's assertions if defined. - * Not defined by default, unless the NDEBUG macro is defined - * (this is a standard C++ macro which disables all asserts). - * https://eigen.tuxfamily.org/dox/TopicPreprocessorDirectives.html - */ -#define EIGEN_NO_DEBUG -#endif - -#pragma once - -#include -#include -#include "codac2_Interval.h" -#include "codac2_Interval_operations.h" - -namespace Eigen -{ - template<> struct NumTraits - : NumTraits // permits to get the epsilon, dummy_precision, lowest, highest functions - { - typedef codac2::Interval Real; - typedef codac2::Interval NonInteger; - typedef codac2::Interval Nested; - - enum { - IsComplex = 0, - IsInteger = 0, - IsSigned = 1, - RequireInitialization = 1, - ReadCost = 1, - AddCost = 3, - MulCost = 3 - }; - }; -} - -namespace codac2 -{ - using Eigen::Dynamic; - - inline const Interval& conj(const Interval& x) { return x; } - inline const Interval& real(const Interval& x) { return x; } - inline Interval imag(const Interval&) { return 0.; } - //inline Interval abs(const Interval& x) { return codac2::abs(x); } - inline Interval abs2(const Interval& x) { return codac2::sqr(x); } - -} \ No newline at end of file diff --git a/src/core/3rd/codac2_ibex.cpp b/src/core/3rd/codac2_ibex.cpp index e84e6cba..6261f9d4 100644 --- a/src/core/3rd/codac2_ibex.cpp +++ b/src/core/3rd/codac2_ibex.cpp @@ -56,32 +56,32 @@ namespace codac2 cast_vector(codac2::IntervalVector,to_codac); } - #define cast_matrix(OutputType,convert_f,output_ij,input_ij) \ + #define cast_matrix(OutputType,convert_f,output_ij,input_ij,rows_,cols_) \ \ - OutputType x_(x.nb_rows(), x.nb_cols()); \ - for(size_t i = 0 ; i < (size_t)x.nb_rows() ; i++) \ - for(size_t j = 0 ; j < (size_t)x.nb_cols() ; j++) \ + OutputType x_(x.rows_(), x.cols_()); \ + for(size_t i = 0 ; i < (size_t)x.rows_() ; i++) \ + for(size_t j = 0 ; j < (size_t)x.cols_() ; j++) \ output_ij = convert_f(input_ij); \ return x_; \ ibex::Matrix to_ibex(const codac2::Matrix& x) { - cast_matrix(ibex::Matrix,double,x_[i][j],x(i,j)); + cast_matrix(ibex::Matrix,double,x_[i][j],x(i,j),rows,cols); } codac2::Matrix to_codac(const ibex::Matrix& x) { - cast_matrix(codac2::Matrix,double,x_(i,j),x[i][j]); + cast_matrix(codac2::Matrix,double,x_(i,j),x[i][j],nb_rows,nb_cols); } ibex::IntervalMatrix to_ibex(const codac2::IntervalMatrix& x) { - cast_matrix(ibex::IntervalMatrix,to_ibex,x_[i][j],x(i,j)); + cast_matrix(ibex::IntervalMatrix,to_ibex,x_[i][j],x(i,j),rows,cols); } codac2::IntervalMatrix to_codac(const ibex::IntervalMatrix& x) { - cast_matrix(codac2::IntervalMatrix,to_codac,x_(i,j),x[i][j]); + cast_matrix(codac2::IntervalMatrix,to_codac,x_(i,j),x[i][j],nb_rows,nb_cols); } } // namespace codac \ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a3258276..53893d82 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -4,7 +4,6 @@ list(APPEND CODAC_CORE_SRC - ${CMAKE_CURRENT_SOURCE_DIR}/3rd/codac2_eigen.h ${CMAKE_CURRENT_SOURCE_DIR}/3rd/codac2_ibex.cpp ${CMAKE_CURRENT_SOURCE_DIR}/3rd/codac2_ibex.h @@ -55,11 +54,12 @@ ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_Interval.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_Interval_operations.cpp ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_Interval_operations.h - ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_IntervalMatrix.cpp ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_IntervalMatrix.h - ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_IntervalMatrixBase.h - ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_IntervalVector.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_IntervalRow.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_IntervalVector.h + ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h + ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h + ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/paving/codac2_Paving.cpp ${CMAKE_CURRENT_SOURCE_DIR}/domains/paving/codac2_Paving.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/paving/codac2_PavingNode.h @@ -97,14 +97,17 @@ ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_arithmetic_sub.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_GaussJordan.cpp ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_GaussJordan.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Matrix.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_matrices.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Matrix.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_MatrixBase.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_MatrixBase_fwd.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_MatrixBaseBlock.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Vector.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Row.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Vector.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_VectorBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_Base_eigenaddons.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_eigenaddons.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_eigenaddons_test.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_Matrix_eigenaddons.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_MatrixBase_eigenaddons.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_Vector_eigenaddons.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_VectorBase_eigenaddons.h ${CMAKE_CURRENT_SOURCE_DIR}/paver/codac2_pave.cpp ${CMAKE_CURRENT_SOURCE_DIR}/paver/codac2_pave.h @@ -163,6 +166,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/contractors ${CMAKE_CURRENT_SOURCE_DIR}/domains ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval + ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/eigen ${CMAKE_CURRENT_SOURCE_DIR}/domains/paving ${CMAKE_CURRENT_SOURCE_DIR}/functions ${CMAKE_CURRENT_SOURCE_DIR}/functions/analytic @@ -172,6 +176,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/graphics/ipe ${CMAKE_CURRENT_SOURCE_DIR}/graphics/vibes ${CMAKE_CURRENT_SOURCE_DIR}/matrices + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen ${CMAKE_CURRENT_SOURCE_DIR}/paver ${CMAKE_CURRENT_SOURCE_DIR}/proj ${CMAKE_CURRENT_SOURCE_DIR}/separators @@ -209,7 +214,9 @@ file(APPEND ${CODAC_CORE_MAIN_HEADER} "#pragma once\n\n") foreach(header_path ${CODAC_CORE_HDR}) get_filename_component(header_name ${header_path} NAME) - file(APPEND ${CODAC_CORE_MAIN_HEADER} "#include <${header_name}>\n") + if(NOT header_name MATCHES "^.*eigenaddons.*$") + file(APPEND ${CODAC_CORE_MAIN_HEADER} "#include <${header_name}>\n") + endif() endforeach() file(COPY ${CODAC_CORE_MAIN_HEADER} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/../../include) diff --git a/src/core/actions/codac2_OctaSym.cpp b/src/core/actions/codac2_OctaSym.cpp index e5e3f909..b37ab370 100644 --- a/src/core/actions/codac2_OctaSym.cpp +++ b/src/core/actions/codac2_OctaSym.cpp @@ -15,16 +15,6 @@ using namespace std; using namespace codac2; -Interval sign(int a) -{ - return (a > 0) ? 1 : ((a < 0) ? -1 : 0); -} - -int isign(int a) -{ - return (a > 0) ? 1 : ((a < 0) ? -1 : 0); -} - OctaSym::OctaSym(const vector& s) : std::vector(s) { @@ -51,15 +41,6 @@ OctaSym OctaSym::operator*(const OctaSym& s) const assert_release(size() == s.size()); OctaSym a(*this); for(size_t i = 0 ; i < a.size() ; i++) - a[i] = isign(s[i])*(*this)[std::abs((int)s[i])-1]; + a[i] = _sign(s[i])*(*this)[std::abs((int)s[i])-1]; return a; -} - -IntervalVector OctaSym::operator()(const IntervalVector& x) const -{ - assert_release((size_t)x.size() == size()); - IntervalVector x_(size()); - for(size_t i = 0 ; i < size() ; i++) - x_[i] = sign((*this)[i])*x[std::abs((*this)[i])-1]; - return x_; } \ No newline at end of file diff --git a/src/core/actions/codac2_OctaSym.h b/src/core/actions/codac2_OctaSym.h index da695b88..da2618be 100644 --- a/src/core/actions/codac2_OctaSym.h +++ b/src/core/actions/codac2_OctaSym.h @@ -10,7 +10,7 @@ #pragma once #include -#include "codac2_Vector.h" +#include "codac2_matrices.h" #include "codac2_IntervalVector.h" #include "codac2_CtcWrapper.h" #include "codac2_template_tools.h" @@ -42,7 +42,20 @@ namespace codac2 OctaSym operator*(const OctaSym& s) const; - IntervalVector operator()(const IntervalVector& x) const; + int _sign(int a) const + { + return (a > 0) ? 1 : ((a < 0) ? -1 : 0); + } + + template + Mat operator()(const Mat& x) const + { + assert_release((size_t)x.size() == size()); + Mat x_(size()); + for(size_t i = 0 ; i < size() ; i++) + x_[i] = _sign((*this)[i])*x[std::abs((*this)[i])-1]; + return x_; + } template requires IsCtcBaseOrPtr diff --git a/src/core/contractors/codac2_CtcEllipse.cpp b/src/core/contractors/codac2_CtcEllipse.cpp index 195de192..15993843 100644 --- a/src/core/contractors/codac2_CtcEllipse.cpp +++ b/src/core/contractors/codac2_CtcEllipse.cpp @@ -62,7 +62,7 @@ void CtcEllipse0::contract(IntervalVector& x) const } } -CtcEllipse::CtcEllipse(const Vector& q) +CtcEllipse::CtcEllipse(const IntervalVector& q) : Ctc(2), _q(q) { assert_release(q.size() == 6); @@ -76,7 +76,7 @@ void CtcEllipse::contract(IntervalVector& x) const | contract_ith({1,-2}, x) | contract_ith({-1, 2}, x); } -const Vector& CtcEllipse::q() const +const IntervalVector& CtcEllipse::q() const { return _q; } diff --git a/src/core/contractors/codac2_CtcEllipse.h b/src/core/contractors/codac2_CtcEllipse.h index 0e35b7ec..149cdb2f 100644 --- a/src/core/contractors/codac2_CtcEllipse.h +++ b/src/core/contractors/codac2_CtcEllipse.h @@ -30,14 +30,14 @@ namespace codac2 { public: - CtcEllipse(const Vector& q); + CtcEllipse(const IntervalVector& q); void contract(IntervalVector& x) const; - const Vector& q() const; + const IntervalVector& q() const; protected: IntervalVector contract_ith(const OctaSym& i, const IntervalVector& x) const; - const Vector _q; + const IntervalVector _q; }; } \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcInverse.h b/src/core/contractors/codac2_CtcInverse.h index 91dde651..a987520a 100644 --- a/src/core/contractors/codac2_CtcInverse.h +++ b/src/core/contractors/codac2_CtcInverse.h @@ -92,7 +92,7 @@ namespace codac2 X0 x_mid = X0(x_.mid()); assert(val_expr.a.size() == val_expr.m.size()); - IntervalVector fm({val_expr.a - val_expr.m}); + IntervalVector fm { val_expr.a - val_expr.m }; if constexpr(std::is_same_v) { diff --git a/src/core/contractors/codac2_directed_ctc.cpp b/src/core/contractors/codac2_directed_ctc.cpp index b4132bc1..e65af924 100644 --- a/src/core/contractors/codac2_directed_ctc.cpp +++ b/src/core/contractors/codac2_directed_ctc.cpp @@ -9,7 +9,6 @@ #include #include "codac2_directed_ctc.h" -#include "codac2_MatrixBase.h" #include "codac2_IntervalVector.h" #include "codac2_IntervalMatrix.h" @@ -108,7 +107,7 @@ using namespace codac2; VectorOpValue AddOp::fwd(const VectorOpValue& x1, const VectorOpValue& x2) { - assert(x1.da.nb_rows() == x2.da.nb_rows() && x1.da.nb_cols() == x2.da.nb_cols()); + assert(x1.da.rows() == x2.da.rows() && x1.da.cols() == x2.da.cols()); return { fwd(x1.m, x2.m), fwd(x1.a, x2.a), @@ -144,7 +143,7 @@ using namespace codac2; { assert(y.size() == x1.size() && y.size() == x2.size()); for(size_t i = 0 ; i < y.size() ; i++) - AddOp::bwd(*(y._e.data()+i), *(x1._e.data()+i), *(x2._e.data()+i)); + AddOp::bwd(*(y.data()+i), *(x1.data()+i), *(x2.data()+i)); } @@ -212,7 +211,7 @@ using namespace codac2; { assert(y.size() == x1.size()); for(size_t i = 0 ; i < y.size() ; i++) - SubOp::bwd(*(y._e.data()+i), *(x1._e.data()+i)); + SubOp::bwd(*(y.data()+i), *(x1.data()+i)); } @@ -225,7 +224,7 @@ using namespace codac2; ScalarOpValue SubOp::fwd(const ScalarOpValue& x1, const ScalarOpValue& x2) { - assert(x1.da.nb_rows() == x2.da.nb_rows() && x1.da.nb_cols() == x2.da.nb_cols()); + assert(x1.da.rows() == x2.da.rows() && x1.da.cols() == x2.da.cols()); return { fwd(x1.m, x2.m), fwd(x1.a, x2.a), @@ -247,7 +246,7 @@ using namespace codac2; VectorOpValue SubOp::fwd(const VectorOpValue& x1, const VectorOpValue& x2) { - assert(x1.da.nb_rows() == x2.da.nb_rows() && x1.da.nb_cols() == x2.da.nb_cols()); + assert(x1.da.rows() == x2.da.rows() && x1.da.cols() == x2.da.cols()); return { fwd(x1.m, x2.m), fwd(x1.a, x2.a), @@ -271,7 +270,7 @@ using namespace codac2; MatrixOpValue SubOp::fwd(const MatrixOpValue& x1, const MatrixOpValue& x2) { - assert(x1.a.nb_cols() == x2.a.nb_cols() && x1.a.nb_rows() == x2.a.nb_rows()); + assert(x1.a.cols() == x2.a.cols() && x1.a.rows() == x2.a.rows()); return { fwd(x1.m, x2.m), fwd(x1.a, x2.a), @@ -284,7 +283,7 @@ using namespace codac2; { assert(y.size() == x1.size() && y.size() == x2.size()); for(size_t i = 0 ; i < y.size() ; i++) - SubOp::bwd(*(y._e.data()+i), *(x1._e.data()+i), *(x2._e.data()+i)); + SubOp::bwd(*(y.data()+i), *(x1.data()+i), *(x2.data()+i)); } @@ -297,10 +296,10 @@ using namespace codac2; ScalarOpValue MulOp::fwd(const ScalarOpValue& x1, const ScalarOpValue& x2) { - assert(x1.da.nb_rows() == 1); - assert(x1.da.nb_rows() == x2.da.nb_rows() && x1.da.nb_cols() == x2.da.nb_cols()); + assert(x1.da.rows() == 1); + assert(x1.da.rows() == x2.da.rows() && x1.da.cols() == x2.da.cols()); - IntervalMatrix d(1,x1.da.nb_cols()); + IntervalMatrix d(1,x1.da.cols()); for(size_t i = 0 ; i < d.size() ; i++) d(0,i) = x1.da(0,i)*x2.a + x1.a*x2.da(0,i); @@ -324,13 +323,13 @@ using namespace codac2; VectorOpValue MulOp::fwd(const ScalarOpValue& x1, const VectorOpValue& x2) { - assert(x1.da.nb_rows() == 1); - assert(x1.da.nb_cols() == x2.da.nb_cols()); - assert(x2.a.size() == x2.da.nb_rows()); + assert(x1.da.rows() == 1); + assert(x1.da.cols() == x2.da.cols()); + assert(x2.a.size() == x2.da.rows()); - IntervalMatrix d(x2.da.nb_rows(),x2.da.nb_cols()); - for(size_t i = 0 ; i < d.nb_rows() ; i++) - for(size_t j = 0 ; j < d.nb_cols() ; j++) + IntervalMatrix d(x2.da.rows(),x2.da.cols()); + for(size_t i = 0 ; i < d.rows() ; i++) + for(size_t j = 0 ; j < d.cols() ; j++) d(i,j) = x1.da(0,j)*x2.a[i]+x1.a*x2.da(i,j); return { @@ -365,7 +364,7 @@ using namespace codac2; IntervalVector MulOp::fwd(const IntervalMatrix& x1, const IntervalVector& x2) { - assert(x1.nb_cols() == x2.size()); + assert(x1.cols() == x2.size()); return x1 * x2; } @@ -374,7 +373,7 @@ using namespace codac2; return { fwd(x1.a, /* <<----- x1.m */ x2.m), fwd(x1.a, x2.a), - IntervalMatrix::zeros(x1.a.nb_rows(),x1.a.nb_cols()), // todo + IntervalMatrix::zeros(x1.a.rows(),x1.a.cols()), // todo x1.def_domain && x2.def_domain }; } @@ -384,8 +383,8 @@ using namespace codac2; void MulOp::bwd(const IntervalVector& y, IntervalMatrix& x1, IntervalVector& x2) { - assert(x1.nb_rows() == y.size()); - assert(x1.nb_cols() == x2.size()); + assert(x1.rows() == y.size()); + assert(x1.cols() == x2.size()); /*if(x1.is_squared()) // not working for any x1 { @@ -516,9 +515,9 @@ using namespace codac2; ScalarOpValue SqrOp::fwd(const ScalarOpValue& x1) { - assert(x1.da.nb_rows() == 1); + assert(x1.da.rows() == 1); - IntervalMatrix d(1,x1.da.nb_cols()); + IntervalMatrix d(1,x1.da.cols()); for(size_t i = 0 ; i < d.size() ; i++) d(0,i) = 2.*x1.a*x1.da(0,i); @@ -796,10 +795,10 @@ using namespace codac2; ScalarOpValue Atan2Op::fwd(const ScalarOpValue& x1, const ScalarOpValue& x2) { - assert(x1.da.nb_rows() == 1); - assert(x1.da.nb_rows() == x2.da.nb_rows() && x1.da.nb_cols() == x2.da.nb_cols()); + assert(x1.da.rows() == 1); + assert(x1.da.rows() == x2.da.rows() && x1.da.cols() == x2.da.cols()); - IntervalMatrix d(1,x1.da.nb_cols()); + IntervalMatrix d(1,x1.da.cols()); for(size_t i = 0 ; i < d.size() ; i++) d(0,i) = (-x1.a*x2.da(0,i)/(sqr(x2.a)+sqr(x1.a)))+(x2.a*x1.da(0,i)/(sqr(x2.a)+sqr(x1.a))); @@ -936,7 +935,7 @@ using namespace codac2; ScalarOpValue ComponentOp::fwd(const VectorOpValue& x1, size_t i) { - assert(i >= 0 && i < x1.a.nb_rows()); + assert(i >= 0 && i < x1.a.rows()); return { fwd(x1.m,i), fwd(x1.a,i), @@ -962,11 +961,11 @@ using namespace codac2; VectorOpValue SubvectorOp::fwd(const VectorOpValue& x1, size_t i, size_t j) { - assert(i >= 0 && i < x1.a.nb_rows() && j >= i && j < x1.a.nb_rows()); + assert(i >= 0 && i < x1.a.rows() && j >= i && j < x1.a.rows()); return { fwd(x1.m,i,j), fwd(x1.a,i,j), - x1.da.block(i,0,j-i+1,x1.da.nb_cols()), + x1.da.block(i,0,j-i+1,x1.da.cols()), x1.def_domain }; } @@ -984,8 +983,8 @@ using namespace codac2; void MatrixOp::fwd_i(IntervalMatrix& m, const IntervalVector& x, size_t i) { - assert(i >= 0 && i < m.nb_cols()); - m.resize(x.size(),m.nb_cols()); + assert(i >= 0 && i < m.cols()); + m.resize(x.size(),m.cols()); m.col(i) = x; } @@ -997,12 +996,12 @@ using namespace codac2; Interval DetOp::fwd(const IntervalMatrix& x) { assert_release(x.is_squared() && "can only compute determinants for a square matrix"); - assert_release((x.nb_rows() == 1 || x.nb_rows() == 2) && "determinant not yet computable for n×n matrices, n>2"); + assert_release((x.rows() == 1 || x.rows() == 2) && "determinant not yet computable for n×n matrices, n>2"); - if(x.nb_rows() == 1) // 1×1 matrix + if(x.rows() == 1) // 1×1 matrix return x(0,0); - else if(x.nb_rows() == 2) // 2×2 matrix + else if(x.rows() == 2) // 2×2 matrix return x(0,0)*x(1,1)-x(0,1)*x(1,0); else @@ -1022,12 +1021,12 @@ using namespace codac2; void DetOp::bwd(const Interval& y, IntervalMatrix& x) { assert_release(x.is_squared() && "can only compute determinants for a square matrix"); - assert_release((x.nb_rows() == 1 || x.nb_rows() == 2) && "determinant not yet computable for n×n matrices, n>2"); + assert_release((x.rows() == 1 || x.rows() == 2) && "determinant not yet computable for n×n matrices, n>2"); - if(x.nb_rows() == 1) // 1×1 matrix + if(x.rows() == 1) // 1×1 matrix x(0,0) &= y; - else if(x.nb_rows() == 2) // 2×2 matrix + else if(x.rows() == 2) // 2×2 matrix { Interval z1 = x(0,0)*x(1,1), z2 = x(1,0)*x(0,1); SubOp::bwd(y, z1, z2); @@ -1046,14 +1045,21 @@ using namespace codac2; Interval DetOp::fwd(const IntervalVector& x1, const IntervalVector& x2) { assert_release(x1.size() == 2 && x2.size() == 2 && "determinant only computable for pairs of 2d vectors"); - return DetOp::fwd(IntervalMatrix(x1,x2)); + IntervalMatrix m(2,2); + m.col(0) = x1; m.col(1) = x2; + return DetOp::fwd(m); } ScalarOpValue DetOp::fwd(const VectorOpValue& x1, const VectorOpValue& x2) { + IntervalMatrix m(2,2); + m.col(0) = x1.m; m.col(1) = x2.m; + IntervalMatrix a(2,2); + a.col(0) = x1.a; a.col(1) = x2.a; + return { - fwd(IntervalMatrix(x1.m,x2.m)), - fwd(IntervalMatrix(x1.a,x2.a)), + fwd(m), + fwd(a), IntervalMatrix(0,0), // not supported yet for auto diff x1.def_domain && x2.def_domain }; @@ -1074,14 +1080,21 @@ using namespace codac2; Interval DetOp::fwd(const IntervalVector& x1, const IntervalVector& x2, const IntervalVector& x3) { assert_release(x1.size() == 3 && x2.size() == 3 && x3.size() == 3 && "determinant only computable for triplet of 3d vectors"); - return DetOp::fwd(IntervalMatrix(x1,x2,x3)); + IntervalMatrix m(3,3); + m.col(0) = x1; m.col(1) = x2; m.col(2) = x3; + return DetOp::fwd(m); } ScalarOpValue DetOp::fwd(const VectorOpValue& x1, const VectorOpValue& x2, const VectorOpValue& x3) { + IntervalMatrix m(3,3); + m.col(0) = x1.m; m.col(1) = x2.m; m.col(2) = x3.m; + IntervalMatrix a(3,3); + a.col(0) = x1.a; a.col(1) = x2.a; a.col(2) = x3.a; + return { - fwd(IntervalMatrix(x1.m,x2.m,x3.m)), - fwd(IntervalMatrix(x1.a,x2.a,x3.a)), + fwd(m), + fwd(a), IntervalMatrix(0,0), // not supported yet for auto diff x1.def_domain && x2.def_domain && x3.def_domain }; @@ -1090,7 +1103,10 @@ using namespace codac2; void DetOp::bwd(const Interval& y, IntervalVector& x1, IntervalVector& x2, IntervalVector& x3) { assert_release(x1.size() == 3 && x2.size() == 3 && x3.size() == 3 && "determinant only computable for triplet of 3d vectors"); - IntervalMatrix m(x1,x2,x3); + + IntervalMatrix m(3,3); + m.col(0) = x1; m.col(1) = x2; m.col(2) = x3; + DetOp::bwd(y,m); x1 &= m.col(0); x2 &= m.col(1); diff --git a/src/core/contractors/codac2_directed_ctc.h b/src/core/contractors/codac2_directed_ctc.h index 4dc4f0c9..69bdb963 100644 --- a/src/core/contractors/codac2_directed_ctc.h +++ b/src/core/contractors/codac2_directed_ctc.h @@ -243,7 +243,7 @@ namespace codac2 requires (std::is_base_of_v && ...) static VectorOpValue fwd(const X&... x) { - IntervalMatrix d(sizeof...(X),std::get<0>(std::tie(x...)).da.nb_cols()); + IntervalMatrix d(sizeof...(X),std::get<0>(std::tie(x...)).da.cols()); size_t i = 0; ((d.row(i++) = x.da), ...); diff --git a/src/core/contractors/codac2_linear_ctc.cpp b/src/core/contractors/codac2_linear_ctc.cpp index 69842be5..fee447d9 100644 --- a/src/core/contractors/codac2_linear_ctc.cpp +++ b/src/core/contractors/codac2_linear_ctc.cpp @@ -15,12 +15,12 @@ using namespace codac2; void CtcGaussElim::contract(IntervalMatrix& A, IntervalVector& x, IntervalVector& b) const { - assert_release(A.is_squared() && A.nb_rows() == x.size() && A.nb_rows() == b.size()); + assert_release(A.is_squared() && A.rows() == x.size() && A.rows() == b.size()); IntervalMatrix A_ = A; IntervalVector b_ = b; - size_t n = A_.nb_rows(); + size_t n = A_.rows(); for(size_t i = 0 ; i < n ; i++) if(A_(i,i).contains(0.)) return; @@ -45,10 +45,10 @@ void CtcGaussElim::contract(IntervalMatrix& A, IntervalVector& x, IntervalVector void CtcGaussSeidel::contract(IntervalMatrix& A, IntervalVector& x, IntervalVector& b) const { - assert_release(A.is_squared() && A.nb_rows() == x.size() && A.nb_rows() == b.size()); + assert_release(A.is_squared() && A.rows() == x.size() && A.rows() == b.size()); auto ext_diag = A; - for(size_t i = 0 ; i < A.nb_rows() ; i++) + for(size_t i = 0 ; i < A.rows() ; i++) ext_diag(i,i) = 0.; - x &= IntervalVector(A._e.diagonal().asDiagonal().inverse()*(b._e-ext_diag._e*x._e)); + x &= IntervalVector(A.diagonal().asDiagonal().inverse()*(b-ext_diag*x)); } \ No newline at end of file diff --git a/src/core/contractors/codac2_linear_ctc.h b/src/core/contractors/codac2_linear_ctc.h index f1c96f36..81c9f608 100644 --- a/src/core/contractors/codac2_linear_ctc.h +++ b/src/core/contractors/codac2_linear_ctc.h @@ -14,6 +14,9 @@ #include "codac2_arithmetic.h" #include "codac2_Collection.h" #include "codac2_template_tools.h" +#include "codac2_Matrix.h" +#include "codac2_IntervalVector.h" +#include "codac2_IntervalMatrix.h" namespace codac2 { @@ -177,17 +180,17 @@ namespace codac2 */ void contract(IntervalMatrix& A, IntervalVector& x, IntervalVector& b) const { - assert_release(A.is_squared() && A.nb_rows() == x.size() && A.nb_rows() == b.size()); + assert_release(A.is_squared() && A.rows() == x.size() && A.rows() == b.size()); - auto A0 = A.mid(); - auto A0_inv = A0._e.inverse(); - IntervalMatrix Ap(A0_inv.template cast()*A._e); - IntervalVector bp(A0_inv.template cast()*b._e); + IntervalMatrix A0 = A.mid(); + IntervalMatrix A0_inv = A.mid().inverse().template cast(); + IntervalMatrix Ap = A0_inv*A; + IntervalVector bp = A0_inv*b; _ctc_no_precond.front().contract(Ap,x,bp); - b &= IntervalVector(A0._e.template cast()*bp._e); - A &= IntervalMatrix(A0._e.template cast()*Ap._e); + b &= A0*bp; + A &= A0*Ap; } virtual std::shared_ptr copy() const diff --git a/src/core/domains/interval/codac2_IntervalMatrix.cpp b/src/core/domains/interval/codac2_IntervalMatrix.cpp deleted file mode 100644 index 368e08ea..00000000 --- a/src/core/domains/interval/codac2_IntervalMatrix.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/** - * codac2_IntervalMatrix.cpp - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#include "codac2_IntervalMatrix.h" -#include "codac2_IntervalVector.h" - -using namespace std; -using namespace codac2; - -namespace codac2 -{ - IntervalMatrix::IntervalMatrix(size_t r, size_t c) - : IntervalMatrix(r,c,Interval()) - { - assert_release(r >= 0 && c >= 0); - } - - IntervalMatrix::IntervalMatrix(size_t r, size_t c, const Interval& x) - : MatrixBase(r,c,x), - IntervalMatrixBase(r,c,x) - { - assert_release(r >= 0 && c >= 0); - } - - IntervalMatrix::IntervalMatrix(const Matrix& x) - : MatrixBase(x._e.template cast()), - IntervalMatrixBase(x._e.template cast()) - { } - - IntervalMatrix::IntervalMatrix(const Matrix& lb, const Matrix& ub) - : MatrixBase(lb._e.template cast()), - IntervalMatrixBase(lb._e.template cast()) - { - assert_release(lb.size() == ub.size()); - *this |= ub; - } - - IntervalMatrix::IntervalMatrix(size_t r, size_t c, const double bounds[][2]) - : MatrixBase(r,c), - IntervalMatrixBase(r,c,bounds) - { - assert_release(r >= 0 && c >= 0); - } - - IntervalMatrix::IntervalMatrix(std::initializer_list> l) - : MatrixBase(l), - IntervalMatrixBase(l) - { - assert_release(!std::empty(l)); - } - - IntervalMatrix::IntervalMatrix(const MatrixBase& x) - : IntervalMatrix(x._e.template cast()) - { } - - IntervalMatrix::IntervalMatrix(const MatrixBase& x) - : MatrixBase(x._e), - IntervalMatrixBase(x._e) - { } - - IntervalMatrix::IntervalMatrix(const IntervalVector& x) - : IntervalMatrix(x._e) - { } - - IntervalMatrix IntervalMatrix::transpose() const - { - return this->_e.transpose(); - } - - IntervalMatrix IntervalMatrix::diag_matrix() const - { - return _e.diagonal().asDiagonal().toDenseMatrix(); - } - - bool operator==(const IntervalMatrix& x1, const IntervalMatrix& x2) - { - // ^ This overload allows automatic cast for Matrix == IntervalMatrix comparisons - return (IntervalMatrixBase)x1 == (IntervalMatrixBase)x2; - } - - IntervalMatrix IntervalMatrix::empty(size_t r, size_t c) - { - assert_release(r >= 0 && c >= 0); - return IntervalMatrix(r,c,Interval::empty()); - } -} \ No newline at end of file diff --git a/src/core/domains/interval/codac2_IntervalMatrix.h b/src/core/domains/interval/codac2_IntervalMatrix.h index 0f10c61c..90af210c 100644 --- a/src/core/domains/interval/codac2_IntervalMatrix.h +++ b/src/core/domains/interval/codac2_IntervalMatrix.h @@ -1,140 +1,20 @@ /** * \file codac2_IntervalMatrix.h - * - * This class reuses some of the functions developed for ibex::IntervalMatrix. - * The original IBEX code is revised in modern C++ and adapted to the template - * structure proposed in Codac, based on the Eigen library. - * See ibex::IntervalMatrix (IBEX lib, author: Gilles Chabert) - * * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou, Gilles Chabert + * \author Simon Rohou * \copyright Copyright 2023 Codac Team * \license GNU Lesser General Public License (LGPL) */ #pragma once -#include "codac2_assert.h" -#include "codac2_Matrix.h" -#include "codac2_IntervalMatrixBase.h" -#include "codac2_IntervalVector.h" +#include "codac2_matrices.h" +#include "codac2_Vector.h" namespace codac2 { - class IntervalVector; - - class IntervalMatrix : public IntervalMatrixBase - { - public: - - explicit IntervalMatrix(size_t r, size_t c); - - explicit IntervalMatrix(size_t r, size_t c, const Interval& x); - - IntervalMatrix(const Matrix& x); - - explicit IntervalMatrix(const Matrix& lb, const Matrix& ub); - - explicit IntervalMatrix(size_t r, size_t c, const double bounds[][2]); - - IntervalMatrix(std::initializer_list> l); - - template - requires (std::is_same_v && ...) - IntervalMatrix(const IV&... x) - : MatrixBase(sizeof...(IV), std::get<0>(std::tie(x...)).size()), - IntervalMatrixBase(sizeof...(IV), std::get<0>(std::tie(x...)).size()) - { - size_t i = 0; - ((this->row(i++) = x), ...); - assert(i == nb_rows()); - } - - IntervalMatrix(const MatrixBase& x); - - IntervalMatrix(const MatrixBase& x); - - IntervalMatrix(const IntervalVector& x); - - template - IntervalMatrix(const MatrixBaseBlock& x) - : IntervalMatrix(x.eval()) - { } - - template - IntervalMatrix(const Eigen::MatrixBase& x) - : MatrixBase(x.template cast()), - IntervalMatrixBase(x.template cast()) - { } - - IntervalMatrix transpose() const; - - IntervalMatrix diag_matrix() const; - - friend bool operator==(const IntervalMatrix& x1, const IntervalMatrix& x2); - - static IntervalMatrix empty(size_t r, size_t c); - - // Operators - - IntervalMatrix& operator+=(const IntervalMatrix& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e += x._e; - return *this; - } - - template - IntervalMatrix& operator+=(const MatrixBaseBlock& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e += eigen(x).template cast(); - return *this; - } - - IntervalMatrix& operator-=(const IntervalMatrix& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e -= x._e; - return *this; - } - - template - IntervalMatrix& operator-=(const MatrixBaseBlock& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e -= eigen(x).template cast(); - return *this; - } - - IntervalMatrix& operator*=(const Interval& x) - { - this->_e *= x; - return *this; - } - - IntervalMatrix& operator*=(const IntervalMatrix& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e *= x._e; - return *this; - } - - template - IntervalMatrix& operator*=(const MatrixBaseBlock& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e *= eigen(x).template cast(); - return *this; - } - - IntervalMatrix& operator/=(const Interval& x) - { - this->_e /= x; - return *this; - } - }; + using IntervalMatrix = Eigen::Matrix; inline std::ostream& operator<<(std::ostream& os, const IntervalMatrix& x) { @@ -142,6 +22,21 @@ namespace codac2 return os << "( empty matrix )"; else - return os << (const MatrixBase&)x; + return operator<<(os, + static_cast&>(x)); + + #if 0 // IBEX style + os << "("; + for(size_t i = 0 ; i < x.rows() ; i++) + { + os << (i!=0 ? " " : "") << "("; + for(size_t j = 0 ; j < x.cols() ; j++) + os << x(i,j) << (j - class IntervalMatrixBase : virtual public MatrixBase, public DomainInterface - { - public: - - explicit IntervalMatrixBase(size_t r, size_t c) - : MatrixBase(r,c) - { } - - explicit IntervalMatrixBase(size_t r, size_t c, const Interval& x) - : MatrixBase(r,c,x) - { } - - explicit IntervalMatrixBase(size_t r, size_t c, const double bounds[][2]) - : MatrixBase(r,c) - { - size_t k = 0; - for(size_t i = 0 ; i < this->nb_rows() ; i++) - for(size_t j = 0 ; j < this->nb_cols() ; j++) - { - (*this)(i,j) = Interval(bounds[k][0],bounds[k][1]); - k++; - } - assert(k == this->size()); - } - - IntervalMatrixBase(std::initializer_list> l) - : MatrixBase(l) - { } - - template - IntervalMatrixBase(const Eigen::MatrixBase& x) - : MatrixBase(x) - { } - - double volume() const - { - if(is_empty()) - return 0.; - - double v = 0.; - for(size_t i = 0 ; i < this->size() ; i++) - { - if((this->_e.data()+i)->is_unbounded()) return oo; - if((this->_e.data()+i)->is_degenerated()) return 0.; - v += std::log((this->_e.data()+i)->diam()); - } - return std::exp(v); - } - - bool is_empty() const - { - for(size_t i = 0 ; i < this->size() ; i++) - if((this->_e.data()+i)->is_empty()) - return true; - return false; - } - - void set_empty() - { - this->init(Interval::empty()); - } - - #define degenerate_mat(op) \ - V op(this->nb_rows(),this->nb_cols()); \ - \ - if(is_empty()) \ - op.init(std::numeric_limits::quiet_NaN()); \ - \ - else \ - { \ - for(size_t i = 0 ; i < this->size() ; i++) \ - *(op._e.data()+i) = (this->_e.data()+i)->op(); \ - } \ - \ - return op; \ - - V lb() const - { - degenerate_mat(lb); - } - - V ub() const - { - degenerate_mat(ub); - } - - V mid() const - { - degenerate_mat(mid); - } - - V mag() const - { - degenerate_mat(mag); - } - - V mig() const - { - degenerate_mat(mig); - } - - V rand() const - { - srand(time(NULL)); - degenerate_mat(rand); - } - - V rad() const - { - degenerate_mat(rad); - } - - V diam() const - { - degenerate_mat(diam); - } - - double min_diam() const - { - return (this->_e.data()+extr_diam_index(true))->diam(); - } - - double max_diam() const - { - return (this->_e.data()+extr_diam_index(false))->diam(); - } - - size_t min_diam_index() const - { - return extr_diam_index(true); - } - - size_t max_diam_index() const - { - return extr_diam_index(false); - } - - size_t extr_diam_index(bool min) const - { - // This code originates from the ibex-lib - // See: ibex_TemplateVector.h - // Author: Gilles Chabert - - double d = min ? oo : -1; // -1 to be sure that even a 0-diameter interval can be selected - int selected_index = -1; - bool unbounded = false; - assert_release(!is_empty() && "Diameter of an empty IntervalVector is undefined"); - - size_t i; - - for(i = 0 ; i < this->size() ; i++) - { - if((this->_e.data()+i)->is_unbounded()) - { - unbounded = true; - if(!min) break; - } - else - { - double w = (this->_e.data()+i)->diam(); - if(min ? wd) - { - selected_index = i; - d = w; - } - } - } - - if(min && selected_index == -1) - { - assert(unbounded); - // the selected interval is the first one. - i = 0; - } - - // The unbounded intervals are not considered if we look for the minimal diameter - // and some bounded intervals have been found (selected_index!=-1) - if(unbounded && (!min || selected_index == -1)) - { - double pt = min ? -oo : oo; // keep the point less/most distant from +oo (we normalize if the lower bound is -oo) - selected_index = i; - - for(; i < this->size() ; i++) - { - if((this->_e.data()+i)->lb() == -oo) - { - if((this->_e.data()+i)->ub() == oo) - if(!min) - { - selected_index = i; - break; - } - - if((min && (-(this->_e.data()+i)->ub() > pt)) || (!min && (-(this->_e.data()+i)->ub() < pt))) - { - selected_index = i; - pt = -(this->_e.data()+i)->ub(); - } - } - - else if((this->_e.data()+i)->ub() == oo) - if((min && ((this->_e.data()+i)->lb() > pt)) || (!min && ((this->_e.data()+i)->lb() < pt))) - { - selected_index = i; - pt = (this->_e.data()+i)->lb(); - } - } - } - - return selected_index; - } - - bool contains(const V& x) const - { - assert_release(x.size() == this->size()); - - if(is_empty()) - return false; - - for(size_t i = 0 ; i < this->size() ; i++) - if(!(this->_e.data()+i)->contains(*(x._e.data()+i))) - return false; - - return true; - } - - bool interior_contains(const V& x) const - { - assert_release(x.size() == this->size()); - - if(is_empty()) - return false; - - for(size_t i = 0 ; i < this->size() ; i++) - if(!(this->_e.data()+i)->interior_contains(*(x._e.data()+i))) - return false; - - return true; - } - - bool is_unbounded() const - { - if(is_empty()) return false; - for(size_t i = 0 ; i < this->size() ; i++) - if((this->_e.data()+i)->is_unbounded()) - return true; - return false; - } - - bool is_degenerated() const - { - for(size_t i = 0 ; i < this->size() ; i++) - if(!(this->_e.data()+i)->is_degenerated()) - return false; - return true; - } - - bool is_flat() const - { - if(is_empty()) return true; - for(size_t i = 0 ; i < this->size() ; i++) - if((this->_e.data()+i)->is_degenerated()) // don't use diam() because of roundoff - return true; - return false; - } - - bool intersects(const S& x) const - { - assert_release(this->size() == x.size()); - - if(is_empty()) - return false; - - for(size_t i = 0 ; i < this->size() ; i++) - if(!(this->_e.data()+i)->intersects(*(x._e.data()+i))) - return false; - - return true; - } - - bool is_disjoint(const S& x) const - { - assert_release(this->size() == x.size()); - - if(is_empty()) - return true; - - for(size_t i = 0 ; i < this->size() ; i++) - if((this->_e.data()+i)->is_disjoint(*(x._e.data()+i))) - return true; - - return false; - } - - bool overlaps(const S& x) const - { - assert_release(this->size() == x.size()); - - if(is_empty()) - return false; - - for(size_t i = 0 ; i < this->size() ; i++) - if(!(this->_e.data()+i)->overlaps(*(x._e.data()+i))) - return false; - - return true; - } - - bool is_subset(const S& x) const - { - assert_release(this->size() == x.size()); - - if(is_empty()) - return true; - - for(size_t i = 0 ; i < this->size() ; i++) - if(!(this->_e.data()+i)->is_subset(*(x._e.data()+i))) - return false; - - return true; - } - - bool is_strict_subset(const S& x) const - { - assert_release(this->size() == x.size()); - - if(is_empty()) - return true; - - if(!is_subset(x)) - return false; - - for(size_t i = 0 ; i < this->size() ; i++) - if((this->_e.data()+i)->is_strict_subset(*(x._e.data()+i))) - return true; - - return false; - } - - bool is_interior_subset(const S& x) const - { - assert_release(this->size() == x.size()); - - if(is_empty()) - return true; - - for(size_t i = 0 ; i < this->size() ; i++) - if(!(this->_e.data()+i)->is_interior_subset(*(x._e.data()+i))) - return false; - - return true; - } - - bool is_strict_interior_subset(const S& x) const - { - assert_release(this->size() == x.size()); - - if(is_empty()) - return true; - - for(size_t i = 0 ; i < this->size() ; i++) - if(!(this->_e.data()+i)->is_strict_interior_subset(*(x._e.data()+i))) - return false; - - return true; - } - - bool is_superset(const S& x) const - { - assert_release(this->size() == x.size()); - - if(is_empty()) - return false; - - for(size_t i = 0 ; i < this->size() ; i++) - if(!(x._e.data()+i)->is_subset(*(this->_e.data()+i))) - return false; - - return true; - } - - bool is_strict_superset(const S& x) const - { - assert_release(this->size() == x.size()); - - if(is_empty()) - return false; - - if(!is_superset(x)) - return false; - - for(size_t i = 0 ; i < this->size() ; i++) - if((x._e.data()+i)->is_strict_subset(*(this->_e.data()+i))) - return true; - - return false; - } - - bool is_bisectable() const - { - for(size_t i = 0 ; i < this->size() ; i++) - if((this->_e.data()+i)->is_bisectable()) - return true; - return false; - } - - S& inflate(double r) - { - assert_release(r >= 0.); - - for(size_t i = 0 ; i < this->size() ; i++) - (this->_e.data()+i)->inflate(r); - return static_cast(*this); - } - - S& inflate(const V& r) - { - assert_release(this->size() == r.size()); - assert_release(r.min_coeff() >= 0.); - - for(size_t i = 0 ; i < this->size() ; i++) - (this->_e.data()+i)->inflate(*(r._e.data()+i)); - return static_cast(*this); - } - - S& operator&=(const S& x) - { - assert_release(this->size() == x.size()); - - if(x.is_empty()) - { - set_empty(); - return static_cast(*this); - } - - for(size_t i = 0 ; i < this->size() ; i++) - *(this->_e.data()+i) &= *(x._e.data()+i); - return static_cast(*this); - } - - S& operator|=(const S& x) - { - assert_release(this->size() == x.size()); - - if(x.is_empty()) - return static_cast(*this); - - for(size_t i = 0 ; i < this->size() ; i++) - *(this->_e.data()+i) |= *(x._e.data()+i); - return static_cast(*this); - } - - S operator&(const S& x) const - { - auto y = *this; - return y &= x; - } - - S operator|(const S& x) const - { - auto y = *this; - return y |= x; - } - - friend bool operator==(const IntervalMatrixBase& x1, const IntervalMatrixBase& x2) - { - if(x1.is_empty() || x2.is_empty()) - return x1.is_empty() && x2.is_empty() && x1.size() == x2.size(); - - return (MatrixBase)x1 == (MatrixBase)x2; - } - - std::pair bisect(size_t i, float ratio = 0.49) const - { - assert_release(i >= 0 && i < this->size()); - assert_release((this->_e.data()+i)->is_bisectable()); - assert_release(Interval(0,1).interior_contains(ratio)); - - auto p = std::make_pair(*this,*this); - auto pi = (this->_e.data()+i)->bisect(ratio); - *(p.first._e.data()+i) = pi.first; - *(p.second._e.data()+i) = pi.second; - return p; - } - - std::pair bisect_largest(float ratio = 0.49) const - { - return bisect(max_diam_index(), ratio); - } - }; -} diff --git a/src/core/domains/interval/codac2_IntervalRow.h b/src/core/domains/interval/codac2_IntervalRow.h new file mode 100644 index 00000000..82b69d49 --- /dev/null +++ b/src/core/domains/interval/codac2_IntervalRow.h @@ -0,0 +1,27 @@ +/** + * \file codac2_IntervalRow.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include "codac2_matrices.h" + +namespace codac2 +{ + using IntervalRow = Eigen::Matrix; + + inline std::ostream& operator<<(std::ostream& os, const IntervalRow& x) + { + if(x.is_empty()) + return os << "( empty row )"; + + else + return operator<<(os, + static_cast&>(x)); + } +} \ No newline at end of file diff --git a/src/core/domains/interval/codac2_IntervalVector.cpp b/src/core/domains/interval/codac2_IntervalVector.cpp deleted file mode 100644 index 589d20c8..00000000 --- a/src/core/domains/interval/codac2_IntervalVector.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/** - * codac2_IntervalVector.cpp - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#include "codac2_IntervalVector.h" - -using namespace std; -using namespace codac2; - -namespace codac2 -{ - IntervalVector::IntervalVector(size_t n) - : IntervalVector(n,Interval()) - { - assert_release(n >= 0); - } - - IntervalVector::IntervalVector(size_t n, const Interval& x) - : MatrixBase(n,1,x), - IntervalMatrixBase(n,1), - VectorBase(n) - { - assert_release(n >= 0); - } - - IntervalVector::IntervalVector(size_t n, const double bounds[][2]) - : MatrixBase(n,1), - IntervalMatrixBase(n,1,bounds), - VectorBase(n) - { - assert_release(n >= 0); - } - - IntervalVector::IntervalVector(const Vector& x) - : MatrixBase(x._e.template cast()), - IntervalMatrixBase(x.size(),1), - VectorBase(x.size()) - { } - - IntervalVector::IntervalVector(const Vector& lb, const Vector& ub) - : MatrixBase(lb._e.template cast()), - IntervalMatrixBase(lb.size(),1), - VectorBase(lb.size()) - { - assert_release(lb.size() == ub.size()); - *this |= ub; - } - - IntervalVector::IntervalVector(initializer_list l) - : MatrixBase(l.size(),1), - IntervalMatrixBase(l.size(),1), - VectorBase(l) - { - assert_release(!std::empty(l)); - } - - IntervalVector::IntervalVector(const MatrixBase& x) - : IntervalVector(x._e.template cast()) - { } - - IntervalVector::IntervalVector(const MatrixBase& x) - : IntervalVector(x._e) - { } - - bool operator==(const IntervalVector& x1, const IntervalVector& x2) - { - // ^ This overload allows automatic cast for Vector == IntervalVector comparisons - return (IntervalMatrixBase)x1 == (IntervalMatrixBase)x2; - } - - list IntervalVector::complementary() const - { - return IntervalVector(this->size()).diff(*this); - } - - list IntervalVector::diff(const IntervalVector& y, bool compactness) const - { - // This code originates from the ibex-lib - // See: ibex_TemplateVector.h - // Author: Gilles Chabert - // It has been revised with modern C++ and templated types - - const size_t n = this->size(); - assert_release(y.size() == n); - - if(y == *this) - return { }; - - IntervalVector x = *this; - IntervalVector z = x & y; - - if(z.is_empty()) - { - if(x.is_empty()) return { }; - else return { x }; - } - - else - { - // Check if in one dimension y is flat and x not, - // in which case the diff returns also x directly - if(compactness) - for(size_t i = 0 ; i < n ; i++) - if(z[i].is_degenerated() && !x[i].is_degenerated()) - { - if(x.is_empty()) return { }; - else return { x }; - } - } - - list l; - - for(size_t var = 0 ; var < n ; var++) - { - Interval c1, c2; - - for(const auto& ci : x[var].diff(y[var], compactness)) - { - assert(!ci.is_empty()); - - IntervalVector v(n); - for(size_t i = 0 ; i < var ; i++) - v[i] = x[i]; - v[var] = ci; - for(size_t i = var+1 ; i < n ; i++) - v[i] = x[i]; - if(!v.is_empty()) - l.push_back(v); - } - - x[var] = z[var]; - } - - return l; - } - - IntervalVector IntervalVector::empty(size_t n) - { - assert_release(n >= 0); - return IntervalVector(n,Interval::empty()); - } - - ostream& operator<<(ostream& os, const IntervalVector& x) - { - if(x.is_empty()) - return os << "( empty vector )"; - - else - return os << (const VectorBase&)x; - } -} \ No newline at end of file diff --git a/src/core/domains/interval/codac2_IntervalVector.h b/src/core/domains/interval/codac2_IntervalVector.h index 376331ad..feefe003 100644 --- a/src/core/domains/interval/codac2_IntervalVector.h +++ b/src/core/domains/interval/codac2_IntervalVector.h @@ -1,110 +1,26 @@ /** * \file codac2_IntervalVector.h - * - * This class reuses some of the functions developed for ibex::IntervalVector. - * The original IBEX code is revised in modern C++ and adapted to the template - * structure proposed in Codac, based on the Eigen library. - * See ibex::IntervalVector (IBEX lib, author: Gilles Chabert) - * * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou, Gilles Chabert + * \author Simon Rohou * \copyright Copyright 2023 Codac Team * \license GNU Lesser General Public License (LGPL) */ #pragma once -#include "codac2_assert.h" +#include "codac2_matrices.h" #include "codac2_Vector.h" -#include "codac2_IntervalMatrixBase.h" -#include "codac2_VectorBase.h" -#include "codac2_IntervalMatrix.h" namespace codac2 { - class IntervalVector : public IntervalMatrixBase, public VectorBase - { - public: - - explicit IntervalVector(size_t n); - - explicit IntervalVector(size_t n, const Interval& x); - - explicit IntervalVector(size_t n, const double bounds[][2]); - - IntervalVector(const Vector& x); - - explicit IntervalVector(const Vector& lb, const Vector& ub); - - IntervalVector(std::initializer_list l); - - IntervalVector(const MatrixBase& x); - - IntervalVector(const MatrixBase& x); - - template - IntervalVector(const Eigen::MatrixBase& x) - : MatrixBase(x.template cast()), - IntervalMatrixBase(x.template cast()), - VectorBase(x.template cast()) - { - assert_release(x.cols() == 1); - } - - template - IntervalVector(const MatrixBaseBlock& x) - : IntervalVector(x.eval()) - { - assert_release(x._q == 1); // column block only - } - - Interval& operator()(size_t i, size_t j) = delete; - const Interval& operator()(size_t i, size_t j) const = delete; - - friend bool operator==(const IntervalVector& x1, const IntervalVector& x2); - - std::list complementary() const; - - std::list diff(const IntervalVector& y, bool compactness = true) const; - - static IntervalVector empty(size_t n); - - // Operators - - IntervalVector& operator+=(const IntervalVector& x) - { - assert_release(this->size() == x.size()); - this->_e += x._e; - return *this; - } - - IntervalVector& operator-=(const IntervalVector& x) - { - assert_release(this->size() == x.size()); - this->_e -= x._e; - return *this; - } - - IntervalVector& operator*=(const Interval& x) - { - this->_e *= x; - return *this; - } - - IntervalVector& operator/=(const Interval& x) - { - this->_e /= x; - return *this; - } - }; - - std::ostream& operator<<(std::ostream& os, const IntervalVector& x); - + using IntervalVector = Eigen::Matrix; inline IntervalVector to_IntervalVector(const Interval& x) { - return IntervalVector(1,x); + IntervalVector a(1); + a[0] = x; + return a; } inline IntervalVector to_IntervalVector(const IntervalVector& x) @@ -112,8 +28,14 @@ namespace codac2 return x; } + inline IntervalVector to_IntervalVector(const Vector& x) + { + return x.template cast(); + } + template - requires ((std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) && ...) + requires ((std::is_same_v || std::is_same_v || std::is_same_v + || std::is_same_v || std::is_same_v) && ...) inline IntervalVector cart_prod(const X&... x) { std::vector v_x; @@ -133,12 +55,21 @@ namespace codac2 return x_; } - inline IntervalVector hull(const std::list& l) + inline std::ostream& operator<<(std::ostream& os, const IntervalVector& x) { - assert_release(!l.empty()); - IntervalVector h(l.front()); - for(const auto& li : l) - h |= li; - return h; + if(x.is_empty()) + return os << "( empty vector )"; + + else + return operator<<(os, + static_cast&>(x)); + + #if 0 // IBEX style + os << "("; + for(size_t i = 0 ; i < x.size() ; i++) + os << x[i] << (i + requires IsIntervalDomain +Matrix(const Matrix& x) + : Matrix(x.template cast()) +{ } + +template + requires IsIntervalDomain +Matrix(const Matrix& lb, const Matrix& ub) + : Matrix(lb) +{ + assert_release(lb.size() == ub.size()); + + for(size_t i = 0 ; i < this->size() ; i++) + { + auto& lbi = *(this->data()+i); + const auto& ubi = *(ub.data()+i); + + if(lbi.lb() > ubi) + { + set_empty(); + break; + } + + else + lbi |= ubi; + } +} + +template + requires IsIntervalDomain +Matrix(int r, int c, const double bounds[][2]) + : Matrix(r,c) +{ + assert_release(r > 0 && c > 0); + + size_t k = 0; + for(size_t i = 0 ; i < this->rows() ; i++) + for(size_t j = 0 ; j < this->cols() ; j++) + { + (*this)(i,j) = codac2::Interval(bounds[k][0],bounds[k][1]); + k++; + } + assert_release(k == this->size() && "incorrect array size"); +} + +template + requires IsIntervalDomain +Matrix(const MatrixBase& x) + : Matrix(x.eval().template cast()) +{ } + +template + requires IsIntervalDomain +inline bool operator==(const MatrixBase& x) const +{ + return operator==(x.eval().template cast()); +} + +template + requires IsIntervalDomain +inline double volume() const +{ + if(this->is_empty()) + return 0.; + + double v = 0.; + for(size_t i = 0 ; i < this->size() ; i++) + { + if((this->data()+i)->is_unbounded()) return codac2::oo; + if((this->data()+i)->is_degenerated()) return 0.; + v += std::log((this->data()+i)->diam()); + } + return std::exp(v); +} + +#define degenerate_mat(op) \ + Matrix op(this->rows(),this->cols()); \ + \ + if(this->is_empty()) \ + op.init(std::numeric_limits::quiet_NaN()); \ + \ + else \ + { \ + for(size_t i = 0 ; i < this->size() ; i++) \ + *(op.data()+i) = (this->data()+i)->op(); \ + } \ + \ + return op; \ + +template + requires IsIntervalDomain +inline auto lb() const +{ + degenerate_mat(lb); +} + +template + requires IsIntervalDomain +inline auto ub() const +{ + degenerate_mat(ub); +} + +template + requires IsIntervalDomain +inline auto mid() const +{ + degenerate_mat(mid); +} + +template + requires IsIntervalDomain +inline auto mag() const +{ + degenerate_mat(mag); +} + +template + requires IsIntervalDomain +inline auto mig() const +{ + degenerate_mat(mig); +} + +template + requires IsIntervalDomain +inline auto rand() const +{ + srand(time(NULL)); + degenerate_mat(rand); +} + +template + requires IsIntervalDomain +inline auto rad() const +{ + degenerate_mat(rad); +} + +template + requires IsIntervalDomain +inline auto diam() const +{ + degenerate_mat(diam); +} + +template + requires IsIntervalDomain +inline double min_diam() const +{ + return (this->data()+extr_diam_index(true))->diam(); +} + +template + requires IsIntervalDomain +inline double max_diam() const +{ + return (this->data()+extr_diam_index(false))->diam(); +} + +template + requires IsIntervalDomain +inline size_t min_diam_index() const +{ + return extr_diam_index(true); +} + +template + requires IsIntervalDomain +inline size_t max_diam_index() const +{ + return extr_diam_index(false); +} + +template + requires IsIntervalDomain +inline size_t extr_diam_index(bool min) const +{ + // This code originates from the ibex-lib + // See: ibex_TemplateVector.h + // Author: Gilles Chabert + + double d = min ? codac2::oo : -1; // -1 to be sure that even a 0-diameter interval can be selected + int selected_index = -1; + bool unbounded = false; + assert_release(!this->is_empty() && "Diameter of an empty IntervalVector is undefined"); + + size_t i; + + for(i = 0 ; i < this->size() ; i++) + { + if((this->data()+i)->is_unbounded()) + { + unbounded = true; + if(!min) break; + } + else + { + double w = (this->data()+i)->diam(); + if(min ? wd) + { + selected_index = i; + d = w; + } + } + } + + if(min && selected_index == -1) + { + assert(unbounded); + // the selected interval is the first one. + i = 0; + } + + // The unbounded intervals are not considered if we look for the minimal diameter + // and some bounded intervals have been found (selected_index!=-1) + if(unbounded && (!min || selected_index == -1)) + { + double pt = min ? -codac2::oo : codac2::oo; // keep the point less/most distant from +oo (we normalize if the lower bound is -oo) + selected_index = i; + + for(; i < this->size() ; i++) + { + if((this->data()+i)->lb() == -codac2::oo) + { + if((this->data()+i)->ub() == codac2::oo) + if(!min) + { + selected_index = i; + break; + } + + if((min && (-(this->data()+i)->ub() > pt)) || (!min && (-(this->data()+i)->ub() < pt))) + { + selected_index = i; + pt = -(this->data()+i)->ub(); + } + } + + else if((this->data()+i)->ub() == codac2::oo) + if((min && ((this->data()+i)->lb() > pt)) || (!min && ((this->data()+i)->lb() < pt))) + { + selected_index = i; + pt = (this->data()+i)->lb(); + } + } + } + + return selected_index; +} + +// to MatrixBase template +// to MatrixBase requires IsIntervalDomain +// to MatrixBase inline bool is_empty() const +// to MatrixBase { +// to MatrixBase for(size_t i = 0 ; i < this->size() ; i++) +// to MatrixBase if((this->data()+i)->is_empty()) +// to MatrixBase return true; +// to MatrixBase return false; +// to MatrixBase } + +template + requires IsIntervalDomain +inline void set_empty() +{ + this->init(codac2::Interval::empty()); +} + +template + requires IsIntervalDomain +inline bool contains(const Matrix& x) const +{ + assert_release(x.size() == this->size()); + + if(this->is_empty()) + return false; + + for(size_t i = 0 ; i < this->size() ; i++) + if(!(this->data()+i)->contains(*(x.data()+i))) + return false; + + return true; +} + +template + requires IsIntervalDomain +inline bool interior_contains(const Matrix& x) const +{ + assert_release(x.size() == this->size()); + + if(this->is_empty()) + return false; + + for(size_t i = 0 ; i < this->size() ; i++) + if(!(this->data()+i)->interior_contains(*(x.data()+i))) + return false; + + return true; +} + +template + requires IsIntervalDomain +inline bool is_unbounded() const +{ + if(this->is_empty()) return false; + for(size_t i = 0 ; i < this->size() ; i++) + if((this->data()+i)->is_unbounded()) + return true; + return false; +} + +template + requires IsIntervalDomain +inline bool is_degenerated() const +{ + for(size_t i = 0 ; i < this->size() ; i++) + if(!(this->data()+i)->is_degenerated()) + return false; + return true; +} + +template + requires IsIntervalDomain +inline bool is_flat() const +{ + if(this->is_empty()) return true; + for(size_t i = 0 ; i < this->size() ; i++) + if((this->data()+i)->is_degenerated()) // don't use diam() because of roundoff + return true; + return false; +} + +template + requires IsIntervalDomain +inline bool intersects(const Matrix& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return false; + + for(size_t i = 0 ; i < this->size() ; i++) + if(!(this->data()+i)->intersects(*(x.data()+i))) + return false; + + return true; +} + +template + requires IsIntervalDomain +inline bool is_disjoint(const Matrix& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + for(size_t i = 0 ; i < this->size() ; i++) + if((this->data()+i)->is_disjoint(*(x.data()+i))) + return true; + + return false; +} + +template + requires IsIntervalDomain +inline bool overlaps(const Matrix& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return false; + + for(size_t i = 0 ; i < this->size() ; i++) + if(!(this->data()+i)->overlaps(*(x.data()+i))) + return false; + + return true; +} + +template + requires IsIntervalDomain +inline bool is_subset(const Matrix& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + for(size_t i = 0 ; i < this->size() ; i++) + if(!(this->data()+i)->is_subset(*(x.data()+i))) + return false; + + return true; +} + +template + requires IsIntervalDomain +inline bool is_strict_subset(const Matrix& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + if(!is_subset(x)) + return false; + + for(size_t i = 0 ; i < this->size() ; i++) + if((this->data()+i)->is_strict_subset(*(x.data()+i))) + return true; + + return false; +} + +template + requires IsIntervalDomain +inline bool is_interior_subset(const Matrix& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + for(size_t i = 0 ; i < this->size() ; i++) + if(!(this->data()+i)->is_interior_subset(*(x.data()+i))) + return false; + + return true; +} + +template + requires IsIntervalDomain +inline bool is_strict_interior_subset(const Matrix& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + for(size_t i = 0 ; i < this->size() ; i++) + if(!(this->data()+i)->is_strict_interior_subset(*(x.data()+i))) + return false; + + return true; +} + +template + requires IsIntervalDomain +inline bool is_superset(const Matrix& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return false; + + for(size_t i = 0 ; i < this->size() ; i++) + if(!(x.data()+i)->is_subset(*(this->data()+i))) + return false; + + return true; +} + +template + requires IsIntervalDomain +inline bool is_strict_superset(const Matrix& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return false; + + if(!is_superset(x)) + return false; + + for(size_t i = 0 ; i < this->size() ; i++) + if((x.data()+i)->is_strict_subset(*(this->data()+i))) + return true; + + return false; +} + +template + requires IsIntervalDomain +inline bool is_bisectable() const +{ + for(size_t i = 0 ; i < this->size() ; i++) + if((this->data()+i)->is_bisectable()) + return true; + return false; +} + +template + requires IsIntervalDomain +inline auto& inflate(double r) +{ + assert_release(r >= 0.); + + for(size_t i = 0 ; i < this->size() ; i++) + (this->data()+i)->inflate(r); + return *this; +} + +template + requires IsIntervalDomain +inline auto& inflate(const Matrix& r) +{ + assert_release(this->size() == r.size()); + assert_release(r.min_coeff() >= 0.); + + for(size_t i = 0 ; i < this->size() ; i++) + (this->data()+i)->inflate(*(r.data()+i)); + return *this; +} + +template + requires IsIntervalDomain +inline auto& operator&=(const Matrix& x) +{ + assert_release(this->size() == x.size()); + + if constexpr(std::is_same_v) + { + if(x.is_empty()) + { + set_empty(); + return *this; + } + } + + for(size_t i = 0 ; i < this->size() ; i++) + *(this->data()+i) &= *(x.data()+i); + return *this; +} + +template + requires IsIntervalDomain +inline auto& operator&=(const MatrixBase& x) +{ + assert_release(this->size() == x.size()); + + for(size_t i = 0 ; i < this->rows() ; i++) + for(size_t j = 0 ; j < this->cols() ; j++) + (*this)(i,j) &= x(i,j); + return *this; +} + +template + requires IsIntervalDomain +inline auto& operator|=(const Matrix& x) +{ + assert_release(this->size() == x.size()); + + if constexpr(std::is_same_v) + { + if(x.is_empty()) + return *this; + } + + for(size_t i = 0 ; i < this->size() ; i++) + *(this->data()+i) |= *(x.data()+i); + return *this; +} + +template + requires IsIntervalDomain +inline auto operator&(const Matrix& x) const +{ + auto y = *this; + return y &= x; +} + +template + requires IsIntervalDomain +inline auto operator|(const Matrix& x) const +{ + auto y = *this; + return y |= x; +} + +template + requires IsIntervalDomain +inline auto diam() const +{ + const Eigen::Matrix& e = *this; + Eigen::Matrix d(this->rows(),this->cols()); + for(size_t i = 0 ; i < this->size() ; i++) + *(d.data()+i) = (e.data()+i)->diam(); + return d; +} + +template + requires IsIntervalDomain +inline static auto empty(size_t r, size_t c) +{ + assert_release(r >= 0 && c >= 0); + Matrix e(r,c); + return e.init(codac2::Interval::empty()); +} + +template + requires IsIntervalDomain +inline auto bisect(size_t i, float ratio = 0.49) const +{ + assert_release(i >= 0 && i < this->size()); + assert_release((this->data()+i)->is_bisectable()); + assert_release(codac2::Interval(0,1).interior_contains(ratio)); + + auto p = std::make_pair(*this,*this); + auto pi = (this->data()+i)->bisect(ratio); + *(p.first.data()+i) = pi.first; + *(p.second.data()+i) = pi.second; + return p; +} + +template + requires IsIntervalDomain +inline auto bisect_largest(float ratio = 0.49) const +{ + return bisect(max_diam_index(), ratio); +} \ No newline at end of file diff --git a/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h b/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h new file mode 100644 index 00000000..5007c523 --- /dev/null +++ b/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h @@ -0,0 +1,25 @@ +/** + * \file codac2_IntervalMatrix_eigenaddons.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +//template +// requires (IsIntervalDomain && (!IsVectorOrRow) +// && (std::is_same_v,IV> && ...)) +//Matrix(const IV&... x) +// : Matrix(sizeof...(IV), std::get<0>(std::tie(x...)).size()) +//{ +// size_t i = 0; +// ((this->row(i++) = x), ...); +// assert_release(i == rows() && "invalid input size"); +//} \ No newline at end of file diff --git a/src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h b/src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h new file mode 100644 index 00000000..0a18ff6d --- /dev/null +++ b/src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h @@ -0,0 +1,183 @@ +/** + * \file codac2_IntervalVector_eigenaddons.h + * + * This class reuses some of the functions developed for ibex::IntervalVector. + * The original IBEX code is revised in modern C++ and adapted to the template + * structure proposed in Codac, based on the Eigen library. + * See ibex::IntervalVector (IBEX lib, author: Gilles Chabert) + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Gilles Chabert + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +template + requires IsIntervalDomain && IsVectorOrRow +Matrix(const std::initializer_list& l) + : Matrix( + [&]() -> int { if(R == 1) return 1; else return l.size(); }(), + [&]() -> int { if(C == 1) return 1; else return l.size(); }() + ) +{ + assert_release(!std::empty(l)); + size_t i = 0; + for(const auto& li : l) + (*this)[i++] = codac2::Interval(li); +} + +template + requires IsIntervalDomain && IsVectorOrRow +Matrix(const std::initializer_list>& l) + : Matrix( + [&]() -> int { if(R == 1) return 1; else return l.size(); }(), + [&]() -> int { if(C == 1) return 1; else return l.size(); }() + ) +{ + assert_release(!std::empty(l)); + size_t i = 0; + for(const auto& li : l) + (*this)[i++] = codac2::Interval(li); +} + +template + requires IsIntervalDomain && IsVectorOrRow +Matrix(const std::initializer_list& l) + : Matrix( + [&]() -> int { if(R == 1) return 1; else return l.size(); }(), + [&]() -> int { if(C == 1) return 1; else return l.size(); }() + ) +{ + assert_release(!std::empty(l)); + size_t i = 0; + for(const auto& li : l) + (*this)[i++] = li; +} + +template + requires IsIntervalDomain && IsVectorOrRow +explicit Matrix(int n) + : Matrix( + [&]() -> int { if(R == 1) return 1; else return n; }(), + [&]() -> int { if(C == 1) return 1; else return n; }() + ) +{ + assert_release(n >= 0); + this->init(codac2::Interval()); +} + +template + requires IsIntervalDomain && IsVectorOrRow +Matrix(int n, const double bounds[][2]) + : Matrix( + [&]() -> int { if(R == 1) return 1; else return n; }(), + [&]() -> int { if(C == 1) return 1; else return n; }(), + bounds + ) +{ + assert_release(n > 0); +} + +//template +// requires IsIntervalDomain && IsVectorOrRow +//explicit Matrix(std::initializer_list> l) +// : Matrix( +// [&]() -> int { if constexpr(R == 1) return 1; else return l.size(); }(), +// [&]() -> int { if constexpr(C == 1) return 1; else return l.size(); }() +// ) +//{ +// assert_release(!std::empty(l)); +// size_t i = 0; +// for(const auto& li : l) +// { +// assert_release(!std::empty(li)); +// (*this)[i++] = codac2::Interval(li); +// } +//} + +template + requires IsIntervalDomain && IsVectorOrRow +inline static auto empty(size_t n) +{ + assert_release(n >= 0); + if constexpr(R == 1) + return Matrix((int)n,codac2::Interval::empty()); + else + return Matrix((int)n,codac2::Interval::empty()); +} + +template + requires IsIntervalDomain && IsVectorOrRow +inline auto complementary() const +{ + return Matrix((int)this->size()).diff(*this); +} + +template + requires IsIntervalDomain && IsVectorOrRow +inline std::list> diff(const Matrix& y, bool compactness = true) const +{ + // This code originates from the ibex-lib + // See: ibex_TemplateVector.h + // Author: Gilles Chabert + // It has been revised with modern C++ and templated types + + const size_t n = this->size(); + assert_release(y.size() == n); + + if(y == *this) + return { }; + + Matrix x = *this; + Matrix z = x & y; + + if(z.is_empty()) + { + if(x.is_empty()) return { }; + else return { x }; + } + + else + { + // Check if in one dimension y is flat and x not, + // in which case the diff returns also x directly + if(compactness) + for(size_t i = 0 ; i < n ; i++) + if(z[i].is_degenerated() && !x[i].is_degenerated()) + { + if(x.is_empty()) return { }; + else return { x }; + } + } + + std::list> l; + + for(size_t var = 0 ; var < n ; var++) + { + codac2::Interval c1, c2; + + for(const auto& ci : x[var].diff(y[var], compactness)) + { + assert(!ci.is_empty()); + + Matrix v(n); + for(size_t i = 0 ; i < var ; i++) + v[i] = x[i]; + v[var] = ci; + for(size_t i = var+1 ; i < n ; i++) + v[i] = x[i]; + if(!v.is_empty()) + l.push_back(v); + } + + x[var] = z[var]; + } + + return l; +} \ No newline at end of file diff --git a/src/core/functions/analytic/codac2_analytic_values.h b/src/core/functions/analytic/codac2_analytic_values.h index d0021c0e..899252eb 100644 --- a/src/core/functions/analytic/codac2_analytic_values.h +++ b/src/core/functions/analytic/codac2_analytic_values.h @@ -10,6 +10,8 @@ #pragma once #include +#include +#include #include #include diff --git a/src/core/matrices/codac2_GaussJordan.cpp b/src/core/matrices/codac2_GaussJordan.cpp index f40ec787..75329fdd 100644 --- a/src/core/matrices/codac2_GaussJordan.cpp +++ b/src/core/matrices/codac2_GaussJordan.cpp @@ -13,17 +13,15 @@ using namespace std; namespace codac2 { - typedef Eigen::Matrix Mat; - - Mat rising(const Mat& R_, const Mat& U_, const Mat& A) + Matrix rising(const Matrix& R_, const Matrix& U_, const Matrix& A) { - Mat R = R_, U = U_; + Matrix R = R_, U = U_; size_t n = A.rows(), m = A.cols(); size_t p = m-n; for(int i = n-1 ; i > 0 ; i--) { - Mat K = U(i,i+p)*Mat::Identity(n,n); + Matrix K = U(i,i+p)*Matrix::Identity(n,n); K.block(0,i,i,1) = -U.block(0,i+p,i,1); R = K*R; U = R*A; @@ -32,28 +30,29 @@ namespace codac2 return R; } - Mat precond(const Mat& P, const Mat& L, const Mat& U) + Matrix precond(const Matrix& P, const Matrix& L, const Matrix& U) { - Mat A = P.inverse()*L*U; - Mat R = (P.inverse()*L).inverse(); + Matrix A = P.inverse()*(L*U); + Matrix R = (P.inverse().eval()*L).inverse().eval(); return rising(R,U,A); } Matrix gauss_jordan(const Matrix& A) { - size_t n = A.nb_rows(), m = A.nb_cols(); - Eigen::FullPivLU lu(A._e); + size_t n = A.rows(), m = A.cols(); + Eigen::FullPivLU lu(A); - Mat L = Mat::Identity(n,n); - if(std::pow(L.determinant(),2) < 1e-5) - { - cout << "[Matrix gauss_jordan(const Matrix& A)] -> eye matrix" << endl; - return Matrix::eye(n,n); - } - L.block(0,0,n,m).triangularView() = lu.matrixLU(); + Matrix L = Matrix::Identity(n,n); + //if(std::pow(L.determinant(),2) < 1e-5) + //{ + // cout << "[Matrix gauss_jordan(const Matrix& A)] -> eye Matrix" << endl; + // return Matrix::eye(n,n); + //} + + L.block(0,0,n,n).triangularView() = lu.matrixLU(); - Mat P = lu.permutationP(); - Mat U = lu.matrixLU().triangularView(); + Matrix P = lu.permutationP(); + Matrix U = lu.matrixLU().triangularView(); return precond(P,L,U); } diff --git a/src/core/matrices/codac2_GaussJordan.h b/src/core/matrices/codac2_GaussJordan.h index 3b5ced65..78b6a14b 100644 --- a/src/core/matrices/codac2_GaussJordan.h +++ b/src/core/matrices/codac2_GaussJordan.h @@ -10,7 +10,6 @@ #pragma once #include -#include "codac2_eigen.h" #include "codac2_Matrix.h" namespace codac2 diff --git a/src/core/matrices/codac2_Matrix.cpp b/src/core/matrices/codac2_Matrix.cpp deleted file mode 100644 index 5a82c244..00000000 --- a/src/core/matrices/codac2_Matrix.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/** - * codac2_Matrix.cpp - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#include "codac2_Vector.h" -#include "codac2_Matrix.h" -#include "codac2_IntervalVector.h" -#include "codac2_IntervalMatrix.h" - -using namespace std; -using namespace codac2; - -namespace codac2 -{ - Matrix::Matrix(size_t r, size_t c) - : Matrix(r,c,0.) - { - assert_release(r >= 0 && c >= 0); - } - - Matrix::Matrix(size_t r, size_t c, double x) - : MatrixBase(r,c,x) - { - assert_release(r >= 0 && c >= 0); - } - - Matrix::Matrix(size_t r, size_t c, const double values[]) - : MatrixBase(r,c,values) - { - assert_release(r >= 0 && c >= 0); - } - - Matrix::Matrix(std::initializer_list> l) - : MatrixBase(l) - { - assert_release(!std::empty(l)); - } - - Matrix::Matrix(const MatrixBase& x) - : Matrix(x._e) - { } - - Matrix::Matrix(const Vector& x) - : Matrix(x._e) - { } - - - Matrix Matrix::transpose() const - { - return this->_e.transpose(); - } - - Matrix Matrix::diag_matrix() const - { - return this->_e.diagonal().asDiagonal().toDenseMatrix(); - } - - Matrix Matrix::inverse() const - { - return this->_e.inverse(); - } -} \ No newline at end of file diff --git a/src/core/matrices/codac2_Matrix.h b/src/core/matrices/codac2_Matrix.h index 87d82e22..d48488f7 100644 --- a/src/core/matrices/codac2_Matrix.h +++ b/src/core/matrices/codac2_Matrix.h @@ -2,111 +2,16 @@ * \file codac2_Matrix.h * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou, Gilles Chabert + * \author Simon Rohou * \copyright Copyright 2023 Codac Team * \license GNU Lesser General Public License (LGPL) */ #pragma once -#include "codac2_assert.h" -#include "codac2_MatrixBase.h" +#include "codac2_matrices.h" namespace codac2 { - class Vector; - class IntervalVector; - class IntervalMatrix; - - class Matrix : public MatrixBase - { - public: - - explicit Matrix(size_t r, size_t c); - - explicit Matrix(size_t r, size_t c, double x); - - explicit Matrix(size_t r, size_t c, const double values[]); - - Matrix(std::initializer_list> l); - - Matrix(const MatrixBase& x); - - Matrix(const Vector& x); - - template - Matrix(const MatrixBaseBlock& x) - : Matrix(x.eval()) - { } - - template - Matrix(const Eigen::MatrixBase& x) - : MatrixBase(x) - { } - - Matrix transpose() const; - - Matrix diag_matrix() const; - - Matrix inverse() const; - - // Operators - - Matrix& operator+=(const Matrix& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e += x._e; - return *this; - } - - template - Matrix& operator+=(const MatrixBaseBlock& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e += eigen(x); - return *this; - } - - Matrix& operator-=(const Matrix& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e -= x._e; - return *this; - } - - template - Matrix& operator-=(const MatrixBaseBlock& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e -= eigen(x); - return *this; - } - - Matrix& operator*=(double x) - { - this->_e *= x; - return *this; - } - - Matrix& operator*=(const Matrix& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e *= x._e; - return *this; - } - - template - Matrix& operator*=(const MatrixBaseBlock& x) - { - assert_release(this->nb_rows() == x.nb_rows() && this->nb_cols() == x.nb_cols()); - this->_e *= eigen(x); - return *this; - } - - Matrix& operator/=(double x) - { - this->_e /= x; - return *this; - } - }; + using Matrix = Eigen::Matrix; } \ No newline at end of file diff --git a/src/core/matrices/codac2_MatrixBase.h b/src/core/matrices/codac2_MatrixBase.h deleted file mode 100644 index 5b4931a3..00000000 --- a/src/core/matrices/codac2_MatrixBase.h +++ /dev/null @@ -1,359 +0,0 @@ -/** - * \file codac2_MatrixBase.h - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#pragma once - -#include -#include "codac2_eigen.h" -#include "codac2_assert.h" -#include "codac2_MatrixBase_fwd.h" -#include "codac2_MatrixBaseBlock.h" - -namespace codac2 -{ - template - class VectorBase; - - template - struct MatrixBaseBlock; - - template - class MatrixBase - { - public: - - using EigenType = Eigen::Matrix; - - explicit MatrixBase(size_t r, size_t c) - : _e(EigenType(r,c)) - { - assert((Rows == (int)r || Rows == -1) && (Cols == (int)c || Cols == -1)); - assert(r >= 0 && c >= 0); - } - - explicit MatrixBase(size_t r, size_t c, const T& x) - : MatrixBase(r,c) - { - assert((Rows == (int)r || Rows == -1) && (Cols == (int)c || Cols == -1)); - init(x); - } - - explicit MatrixBase(size_t r, size_t c, const T values[]) - : MatrixBase(r,c) - { - assert((Rows == (int)r || Rows == -1) && (Cols == (int)c || Cols == -1)); - - if(values == 0) - init(T(0.)); // in case the user called MatrixBase(r,c,0) and 0 is interpreted as NULL! - - else - { - size_t k = 0; - for(size_t i = 0 ; i < nb_rows() ; i++) - for(size_t j = 0 ; j < nb_cols() ; j++) - (*this)(i,j) = values[k++]; - assert(k == size()); - } - } - - explicit MatrixBase(const std::vector& x) - : MatrixBase(x.size(),1,&x[0]) - { - assert(Rows == -1 && Cols == -1); - assert(!x.empty()); - } - - MatrixBase(std::initializer_list> l) - : MatrixBase(0,0 /* will be resized thereafter */) - { - assert(Rows == -1 && Cols == -1); - assert(!std::empty(l)); - - int cols = -1; - for(const auto& ri : l) { - assert_release((cols == -1 || cols == (int)ri.size()) && "ill-formed matrix"); - cols = (int)ri.size(); - } - - resize(l.size(),cols); - size_t i = 0; - for(const auto& ri : l) - { - size_t j = 0; - for(const auto& ci : ri) - (*this)(i,j++) = ci; - i++; - } - // todo: use this instead (faster?) ? std::copy(l.begin(), l.end(), vec); - } - - MatrixBase(const std::vector>& l) - : MatrixBase(0,0 /* will be resized thereafter */) - { - assert(Rows == -1 && Cols == -1); - assert(!std::empty(l)); - - int cols = -1; - for(const auto& ri : l) { - assert_release((cols == -1 || cols == (int)ri.size()) && "ill-formed matrix"); - cols = (int)ri.size(); - } - - resize(l.size(),cols); - size_t i = 0; - for(const auto& ri : l) - { - size_t j = 0; - for(const auto& ci : ri) - (*this)(i,j++) = ci; - i++; - } - // todo: use this instead (faster?) ? std::copy(l.begin(), l.end(), vec); - } - - template - MatrixBase(const Eigen::MatrixBase& x) - : _e(x) - { } - - virtual ~MatrixBase() - { } - - MatrixBase& operator=(const MatrixBase&) = default; - - size_t size() const - { - return _e.size(); - } - - size_t nb_rows() const - { - return _e.rows(); - } - - size_t nb_cols() const - { - return _e.cols(); - } - - bool is_squared() const - { - return nb_rows() == nb_cols(); - } - - #define minmax_item(op) \ - T m = *_e.data(); /* first element */ \ - for(size_t i = 1 ; i < size() ; i++) \ - { \ - if constexpr(std::is_same_v) \ - m = codac2::op(m,*(_e.data()+i)); \ - else \ - m = std::op(m,*(_e.data()+i)); \ - } \ - return m; \ - - T min_coeff() const - { - minmax_item(min); - } - - T max_coeff() const - { - minmax_item(max); - } - - friend bool operator==(const MatrixBase& x1, const MatrixBase& x2) - { - if(x1.nb_rows() != x2.nb_rows() || x1.nb_cols() != x2.nb_cols()) - return false; - - for(size_t i = 0 ; i < x1.nb_rows() ; i++) - for(size_t j = 0 ; j < x1.nb_cols() ; j++) - if(x1(i,j) != x2(i,j)) - return false; - - return true; - } - - T& operator()(size_t i, size_t j) - { - return const_cast(const_cast*>(this)->operator()(i,j)); - } - - const T& operator()(size_t i, size_t j) const - { - assert_release(i >= 0 && i < nb_rows() && j >= 0 && j < nb_cols()); - return this->_e(i,j); - } - - void init(const T& x) - { - for(size_t i = 0 ; i < size() ; i++) - *(_e.data()+i) = x; - } - - void init(const S& x) - { - *this = x; - } - - void resize(size_t nb_rows, size_t nb_cols) - { - assert_release(nb_rows >= 0 && nb_cols >= 0); - - // With resize() of Eigen, the data is reallocated and all previous values are lost. - auto copy = _e; - _e.resize(nb_rows, nb_cols); - for(size_t i = 0 ; i < std::min((size_t)copy.rows(),nb_rows) ; i++) - for(size_t j = 0 ; j < std::min((size_t)copy.cols(),nb_cols) ; j++) - _e(i,j) = copy(i,j); - } - - MatrixBaseBlock block(size_t i, size_t j, size_t p, size_t q) - { - assert_release(i >= 0 && p > 0 && i+p <= nb_rows()); - assert_release(j >= 0 && q > 0 && j+q <= nb_cols()); - return { _e,i,j,p,q }; - } - - MatrixBaseBlock block(size_t i, size_t j, size_t p, size_t q) const - { - assert_release(i >= 0 && p > 0 && i+p <= nb_rows()); - assert_release(j >= 0 && q > 0 && j+q <= nb_cols()); - return { _e,i,j,p,q }; - } - - MatrixBaseBlock col(size_t i) - { - return block(0,i,nb_rows(),1); - } - - MatrixBaseBlock col(size_t i) const - { - return block(0,i,nb_rows(),1); - } - - MatrixBaseBlock row(size_t i) - { - return block(i,0,1,nb_cols()); - } - - MatrixBaseBlock row(size_t i) const - { - return block(i,0,1,nb_cols()); - } - - const auto& operator+() const - { - return _e; - } - - S operator-() const - { - return -_e; - } - - static S zeros(size_t r, size_t c) - { - assert_release(r >= 0 && c >= 0); - return EigenType::Zero(r,c); - } - - static S ones(size_t r, size_t c) - { - assert_release(r >= 0 && c >= 0); - return EigenType::Ones(r,c); - } - - static S eye(size_t r, size_t c) - { - assert_release(r >= 0 && c >= 0); - return EigenType::Identity(r,c); - } - - template - friend std::ostream& operator<<(std::ostream& os, const MatrixBase& x); - - template - friend S_ abs(const MatrixBase& x); - - operator EigenType() - { - return const_cast(const_cast*>(this)->operator EigenType()); - } - - operator EigenType() const - { - return _e; - } - - using iterator = typename EigenType::iterator; - using const_iterator = typename EigenType::const_iterator; - - iterator begin() - { - return _e.begin(); - } - - const_iterator begin() const - { - return _e.cbegin(); - } - - const_iterator end() const - { - return _e.cend(); - } - - iterator end() - { - return _e.end(); - } - - EigenType _e; - }; - - template - S abs(const MatrixBase& x) - { - S a(x); - - for(size_t i = 0 ; i < x.size() ; i++) - { - if constexpr(std::is_same_v) - *(a._e.data()+i) = fabs(*(x._e.data()+i)); - else - *(a._e.data()+i) = abs(*(x._e.data()+i)); - } - - return a; - } - - template - std::ostream& operator<<(std::ostream& os, const MatrixBase& x) - { - os << "("; - for(size_t i = 0 ; i < x.nb_rows() ; i++) - { - os << (i!=0 ? " " : "") << "("; - for(size_t j = 0 ; j < x.nb_cols() ; j++) - os << x(i,j) << (j - const auto& eigen(const MatrixBase& x) - { - return x._e; - } -} \ No newline at end of file diff --git a/src/core/matrices/codac2_MatrixBaseBlock.h b/src/core/matrices/codac2_MatrixBaseBlock.h deleted file mode 100644 index ad8ada14..00000000 --- a/src/core/matrices/codac2_MatrixBaseBlock.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * \file codac2_MatrixBaseBlock.h - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#pragma once - -#include -#include "codac2_eigen.h" -#include "codac2_assert.h" -#include "codac2_MatrixBase_fwd.h" -#include "codac2_MatrixBase.h" - -namespace codac2 -{ - template - struct MatrixBaseBlock - { - Q _m; - size_t _i,_j,_p,_q; - - MatrixBaseBlock(Q m, size_t i, size_t j, size_t p, size_t q) - : _m(m), _i(i), _j(j), _p(p), _q(q) - { - assert(i >= 0 && p > 0 && i+p <= (size_t)m.rows()); - assert(j >= 0 && q > 0 && j+q <= (size_t)m.cols()); - } - - size_t nb_rows() const - { - return _p; - } - - size_t nb_cols() const - { - return _q; - } - - template - void operator=(const MatrixBase& x) - { - assert_release(x.nb_rows() == _p && x.nb_cols() == _q); - _m.block(_i,_j,_p,_q) = x._e; - } - - template - void operator=(const Eigen::MatrixBase& x) - { - assert_release(x.rows() == _p && x.cols() == _q); - _m.block(_i,_j,_p,_q) = x; - } - - // The following replaces operator=, that does not work in Python - // (assignment on function output Matrix::block()) - template - void init(const S_& x) - { - _m.block(_i,_j,_p,_q) = x; - } - - auto eval() const - { - return _m.block(_i,_j,_p,_q).eval(); - } - - template - bool operator==(const M& x) const - { - return this->eval() == x; - } - }; - - template - std::ostream& operator<<(std::ostream& os, const MatrixBaseBlock& x) - { - os << x.eval(); - return os; - } - - template - auto eigen(const MatrixBaseBlock& x) - { - return x._m.block(x._i,x._j,x._p,x._q); - } -} \ No newline at end of file diff --git a/src/core/matrices/codac2_MatrixBase_fwd.h b/src/core/matrices/codac2_Row.h similarity index 59% rename from src/core/matrices/codac2_MatrixBase_fwd.h rename to src/core/matrices/codac2_Row.h index 44fe5ee0..79429ee4 100644 --- a/src/core/matrices/codac2_MatrixBase_fwd.h +++ b/src/core/matrices/codac2_Row.h @@ -1,16 +1,17 @@ /** - * \file codac2_MatrixBase_fwd.h + * \file codac2_Row.h * ---------------------------------------------------------------------------- * \date 2024 * \author Simon Rohou - * \copyright Copyright 2024 Codac Team + * \copyright Copyright 2023 Codac Team * \license GNU Lesser General Public License (LGPL) */ #pragma once +#include "codac2_matrices.h" + namespace codac2 { - template - class MatrixBase; + using Row = Eigen::Matrix; } \ No newline at end of file diff --git a/src/core/matrices/codac2_Vector.cpp b/src/core/matrices/codac2_Vector.cpp deleted file mode 100644 index 24768680..00000000 --- a/src/core/matrices/codac2_Vector.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/** - * codac2_Vector.cpp - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#include "codac2_Vector.h" - -using namespace std; -using namespace codac2; - -namespace codac2 -{ - Vector::Vector(size_t n) - : Vector(n,0.) - { - assert_release(n >= 0); - } - - Vector::Vector(size_t n, double x) - : MatrixBase(n,1,x), - VectorBase(n) - { - assert_release(n >= 0); - } - - Vector::Vector(std::initializer_list l) - : MatrixBase(l.size(),1), - VectorBase(l) - { - assert_release(!std::empty(l)); - } - - Vector::Vector(const std::vector& l) - : MatrixBase(l.size(),1), - VectorBase(l) - { - assert_release(!std::empty(l)); - } - - Vector::Vector(const MatrixBase& x) - : Vector(x._e) - { } - - size_t Vector::min_coeff_index() const - { - size_t r,c; - this->_e.minCoeff(&r,&c); - assert(c == 0); - return r; - } - - size_t Vector::max_coeff_index() const - { - size_t r,c; - this->_e.maxCoeff(&r,&c); - assert(c == 0); - return r; - } - - std::ostream& operator<<(std::ostream& os, const Vector& x) - { - os << "("; - for(size_t i = 0 ; i < x.size() ; i++) - os << x[i] << (i - { - public: - - explicit Vector(size_t n); - - explicit Vector(size_t n, double x); - - Vector(std::initializer_list l); - - Vector(const std::vector& l); - - Vector(const MatrixBase& x); - - template - Vector(const Eigen::MatrixBase& x) - : MatrixBase(x), - VectorBase(x) - { } - - double& operator()(size_t i, size_t j) = delete; - const double& operator()(size_t i, size_t j) const = delete; - - size_t min_coeff_index() const; - - size_t max_coeff_index() const; - - // Operators - - Vector& operator+=(const Vector& x) - { - assert_release(this->size() == x.size()); - this->_e += x._e; - return *this; - } - - Vector& operator-=(const Vector& x) - { - assert_release(this->size() == x.size()); - this->_e -= x._e; - return *this; - } - - Vector& operator*=(double x) - { - this->_e *= x; - return *this; - } - - Vector& operator/=(double x) - { - this->_e /= x; - return *this; - } - - }; - - std::ostream& operator<<(std::ostream& os, const Vector& x); + using Vector = Eigen::Matrix; } \ No newline at end of file diff --git a/src/core/matrices/codac2_VectorBase.h b/src/core/matrices/codac2_VectorBase.h deleted file mode 100644 index 2ee4bcff..00000000 --- a/src/core/matrices/codac2_VectorBase.h +++ /dev/null @@ -1,120 +0,0 @@ -/** - * \file codac2_VectorBase.h - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#pragma once - -#include "codac2_MatrixBase.h" - -namespace codac2 -{ - template - class VectorBase : virtual public MatrixBase - { - public: - - explicit VectorBase(size_t n) - : MatrixBase(n,1) - { - assert_release(n >= 0); - } - - VectorBase(std::initializer_list l) - : MatrixBase(l.size(),1) - { - assert(!std::empty(l)); - size_t i = 0; - for(const auto& li : l) - (*this)[i++] = li; - } - - VectorBase(const std::vector& l) - : MatrixBase(l.size(),1) - { - assert(!std::empty(l)); - size_t i = 0; - for(const auto& li : l) - (*this)[i++] = li; - } - - template - VectorBase(const Eigen::MatrixBase& x) - : MatrixBase(x) - { } - - bool is_squared() const = delete; - - T& operator[](size_t i) - { - return const_cast(const_cast*>(this)->operator[](i)); - } - - const T& operator[](size_t i) const - { - assert_release(i >= 0 && i < this->size()); - return this->_e(i); - } - - S subvector(size_t start_id, size_t end_id) const - { - assert_release(end_id >= 0 && start_id >= 0); - assert_release(end_id < this->size() && start_id <= end_id); - return this->_e.block(start_id, 0, end_id-start_id+1, 1); - } - - void resize(size_t n) - { - assert_release(n >= 0); - MatrixBase::resize(n,1); - } - - void put(size_t start_id, const S& x) - { - assert_release(start_id >= 0 && start_id < this->size()); - assert_release(start_id+x.size() <= this->size()); - this->_e.block(start_id,0,x.size(),1) << x._e; - } - - M transpose() const - { - return this->_e.transpose(); - } - - M diag_matrix() const - { - M diag(this->size(),this->size(),0.); - for(size_t i = 0 ; i < this->size() ; i++) - diag(i,i) = (*this)[i]; - return diag; - } - - static S zeros(size_t n) - { - assert_release(n >= 0); - return S::EigenType::Zero(n,1); - } - - static S ones(size_t n) - { - assert_release(n >= 0); - return S::EigenType::Ones(n,1); - } - - }; - - template - std::ostream& operator<<(std::ostream& os, const VectorBase& x) - { - os << "("; - for(size_t i = 0 ; i < x.size() ; i++) - os << x[i] << (i() + eigen(x2); + return x1.template cast() + eigen(x2); } // ====== First operand: matrix @@ -36,7 +36,7 @@ namespace codac2 requires IsMatrix && IsMatrix Matrix operator+(const M& x1, const M_& x2) { - assert_release(x1.nb_rows() == x2.nb_rows() && x1.nb_cols() == x2.nb_cols()); + assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); return eigen(x1) + eigen(x2); } @@ -44,7 +44,7 @@ namespace codac2 requires IsMatrix && IsIntervalMatrix IntervalMatrix operator+(const M& x1, const IM& x2) { - assert_release(x1.nb_rows() == x2.nb_rows() && x1.nb_cols() == x2.nb_cols()); + assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); return eigen(x1).template cast() + eigen(x2); } @@ -68,7 +68,7 @@ namespace codac2 requires IsIntervalMatrix && IsMatrix IntervalMatrix operator+(const IM& x1, const M& x2) { - assert_release(x1.nb_rows() == x2.nb_rows() && x1.nb_cols() == x2.nb_cols()); + assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); return eigen(x1) + eigen(x2).template cast(); } @@ -76,7 +76,7 @@ namespace codac2 requires IsIntervalMatrix && IsIntervalMatrix IntervalMatrix operator+(const IM& x1, const IM_& x2) { - assert_release(x1.nb_rows() == x2.nb_rows() && x1.nb_cols() == x2.nb_cols()); + assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); return eigen(x1) + eigen(x2); - } + }*/ } \ No newline at end of file diff --git a/src/core/matrices/codac2_arithmetic_div.h b/src/core/matrices/codac2_arithmetic_div.h index cba21e35..5a45d56c 100644 --- a/src/core/matrices/codac2_arithmetic_div.h +++ b/src/core/matrices/codac2_arithmetic_div.h @@ -12,12 +12,12 @@ #include "codac2_template_tools.h" #include "codac2_IntervalMatrix.h" #include "codac2_IntervalVector.h" -#include "codac2_MatrixBaseBlock.h" +//#include "codac2_MatrixBaseBlock.h" namespace codac2 { // ====== First operand: vector - +/* inline Vector operator/(const Vector& x1, double x2) { return eigen(x1) / x2; @@ -70,5 +70,5 @@ namespace codac2 IntervalMatrix operator/(const IM& x1, const Interval& x2) { return eigen(x1) / x2; - } + }*/ } \ No newline at end of file diff --git a/src/core/matrices/codac2_arithmetic_mul.h b/src/core/matrices/codac2_arithmetic_mul.h index 0506e334..88b7f849 100644 --- a/src/core/matrices/codac2_arithmetic_mul.h +++ b/src/core/matrices/codac2_arithmetic_mul.h @@ -12,12 +12,12 @@ #include "codac2_template_tools.h" #include "codac2_IntervalMatrix.h" #include "codac2_IntervalVector.h" -#include "codac2_MatrixBaseBlock.h" +//#include "codac2_MatrixBaseBlock.h" namespace codac2 { // ====== First operand: double - +/* inline Vector operator*(double x1, const Vector& x2) { return x1 * eigen(x2); @@ -100,7 +100,7 @@ namespace codac2 requires IsMatrix Vector operator*(const M& x1, const Vector& x2) { - assert_release(x1.nb_cols() == x2.size()); + assert_release(x1.cols() == x2.size()); return eigen(x1) * eigen(x2); } @@ -108,7 +108,7 @@ namespace codac2 requires IsMatrix && IsMatrix Matrix operator*(const M& x1, const M_& x2) { - assert_release(x1.nb_cols() == x2.nb_rows()); + assert_release(x1.cols() == x2.rows()); return eigen(x1) * eigen(x2); } @@ -116,18 +116,24 @@ namespace codac2 requires IsMatrix IntervalVector operator*(const M& x1, const IntervalVector& x2) { - assert_release(x1.nb_cols() == x2.size()); + assert_release(x1.cols() == x2.size()); return eigen(x1).template cast() * eigen(x2); } template - requires IsMatrix && IsIntervalMatrix - IntervalMatrix operator*(const M& x1, const IM& x2) + requires IsMatrix && IsIntervalMatrix*/ + + /*auto operator*(const Matrix& x1, const IntervalMatrix& x2) { - assert_release(x1.nb_cols() == x2.nb_rows()); - return eigen(x1).template cast() * eigen(x2); - } + assert_release(x1.cols() == x2.rows()); + //return Eigen::operator*(x1.template cast(), x2); + + //const Eigen::Product Eigen::MatrixBase::operator*(const Eigen::MatrixBase&) const [with OtherDerived = Eigen::Matrix; Derived = Eigen::CwiseUnaryOp, const Eigen::Matrix >] + + return x1.template cast() * x2; + }*/ +/* // ====== First operand: interval vector inline IntervalVector operator*(const IntervalVector& x1, double x2) @@ -160,7 +166,7 @@ namespace codac2 requires IsIntervalMatrix IntervalVector operator*(const IM& x1, const Vector& x2) { - assert_release(x1.nb_cols() == x2.size()); + assert_release(x1.cols() == x2.size()); return eigen(x1) * eigen(x2).template cast(); } @@ -168,7 +174,7 @@ namespace codac2 requires IsIntervalMatrix && IsMatrix IntervalMatrix operator*(const IM& x1, const M& x2) { - assert_release(x1.nb_cols() == x2.nb_rows()); + assert_release(x1.cols() == x2.rows()); return eigen(x1) * eigen(x2).template cast(); } @@ -176,7 +182,7 @@ namespace codac2 requires IsIntervalMatrix IntervalVector operator*(const IM& x1, const IntervalVector& x2) { - assert_release(x1.nb_cols() == x2.size()); + assert_release(x1.cols() == x2.size()); return eigen(x1) * eigen(x2); } @@ -184,7 +190,7 @@ namespace codac2 requires IsIntervalMatrix && IsIntervalMatrix IntervalMatrix operator*(const IM& x1, const IM_& x2) { - assert_release(x1.nb_cols() == x2.nb_rows()); + assert_release(x1.cols() == x2.rows()); return eigen(x1) * eigen(x2); - } + }*/ } \ No newline at end of file diff --git a/src/core/matrices/codac2_arithmetic_sub.h b/src/core/matrices/codac2_arithmetic_sub.h index a5ce04b8..21fefbc2 100644 --- a/src/core/matrices/codac2_arithmetic_sub.h +++ b/src/core/matrices/codac2_arithmetic_sub.h @@ -14,7 +14,7 @@ namespace codac2 { // ====== First operand: vector - +/* inline Vector operator-(const Vector& x1, const Vector& x2) { assert_release(x1.size() == x2.size()); @@ -33,7 +33,7 @@ namespace codac2 requires IsMatrix && IsMatrix Matrix operator-(const M& x1, const M_& x2) { - assert_release(x1.nb_rows() == x2.nb_rows() && x1.nb_cols() == x2.nb_cols()); + assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); return eigen(x1) - eigen(x2); } @@ -41,7 +41,7 @@ namespace codac2 requires IsMatrix && IsIntervalMatrix IntervalMatrix operator-(const M& x1, const IM& x2) { - assert_release(x1.nb_rows() == x2.nb_rows() && x1.nb_cols() == x2.nb_cols()); + assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); return eigen(x1).template cast() - eigen(x2); } @@ -65,7 +65,7 @@ namespace codac2 requires IsIntervalMatrix && IsMatrix IntervalMatrix operator-(const IM& x1, const M& x2) { - assert_release(x1.nb_rows() == x2.nb_rows() && x1.nb_cols() == x2.nb_cols()); + assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); return eigen(x1) - eigen(x2).template cast(); } @@ -73,7 +73,7 @@ namespace codac2 requires IsIntervalMatrix && IsIntervalMatrix IntervalMatrix operator-(const IM& x1, const IM_& x2) { - assert_release(x1.nb_rows() == x2.nb_rows() && x1.nb_cols() == x2.nb_cols()); + assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); return eigen(x1) - eigen(x2); - } + }*/ } \ No newline at end of file diff --git a/src/core/matrices/codac2_matrices.h b/src/core/matrices/codac2_matrices.h new file mode 100644 index 00000000..d552d195 --- /dev/null +++ b/src/core/matrices/codac2_matrices.h @@ -0,0 +1,99 @@ +/** + * \file codac2_matrices.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include "codac2_Interval.h" +#include "codac2_Interval_operations.h" +#include "codac2_assert.h" + +namespace Eigen +{ + template + concept IsVectorOrRow = (C == 1 || R == 1); + + template + concept IsIntervalDomain = std::is_same_v; +} + +#define EIGEN_MATRIX_PLUGIN "codac2_eigenaddons.h" +#define EIGEN_MATRIXBASE_PLUGIN "codac2_eigenaddons_test.h" + +#ifndef EIGEN_NO_DEBUG +/* Disables Eigen's assertions if defined. + * Not defined by default, unless the NDEBUG macro is defined + * (this is a standard C++ macro which disables all asserts). + * https://eigen.tuxfamily.org/dox/TopicPreprocessorDirectives.html + */ +#define EIGEN_NO_DEBUG +#endif + +#include +#include + +namespace Eigen +{ + template<> struct NumTraits + : NumTraits // permits to get the epsilon, dummy_precision, lowest, highest functions + { + typedef codac2::Interval Real; + typedef codac2::Interval NonInteger; + typedef codac2::Interval Nested; + typedef codac2::Interval Scalar; + typedef double RealScalar; + + enum { + IsComplex = 0, + IsInteger = 0, + IsSigned = 1, + RequireInitialization = 1, + ReadCost = 1, + AddCost = 3, + MulCost = 3 + }; + }; + + template + struct ScalarBinaryOpTraits + { typedef codac2::Interval ReturnType; }; + + template + struct ScalarBinaryOpTraits + { typedef codac2::Interval ReturnType; }; + + /*inline bool operator==(const codac2::Interval& x1, double x2) + { return x1 == codac2::Interval(x2); } // todo: keep this? + + inline bool operator==(double x2, const codac2::Interval& x1) + { return codac2::Interval(x1) == x2; } // todo: keep this?*/ +} + +namespace codac2 +{ + using Eigen::Dynamic; + + inline const Interval& conj(const Interval& x) { return x; } + inline const Interval& real(const Interval& x) { return x; } + inline Interval imag(const Interval&) { return 0.; } + //inline Interval abs(const Interval& x) { return codac2::abs(x); } + inline Interval abs2(const Interval& x) { return codac2::sqr(x); } + + template + using Mat = Eigen::Matrix; +} \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_Base_eigenaddons.h b/src/core/matrices/eigen/codac2_Base_eigenaddons.h new file mode 100644 index 00000000..12698227 --- /dev/null +++ b/src/core/matrices/eigen/codac2_Base_eigenaddons.h @@ -0,0 +1,136 @@ +/** + * \file codac2_Base_eigenaddons.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +inline size_t size() const +{ + return Eigen::PlainObjectBase>::size(); +} + +inline size_t rows() const +{ + return Eigen::PlainObjectBase>::rows(); +} + +inline size_t cols() const +{ + return Eigen::PlainObjectBase>::cols(); +} + +template +inline Scalar& operator()(size_t i, size_t j) +{ + return const_cast(const_cast*>(this)->operator()(i,j)); +} + +template +inline const Scalar& operator()(size_t i, size_t j) const +{ + assert_release(i >= 0 && i < this->rows() && j >= 0 && j < this->cols()); + + if constexpr(!IsVectorOrRow) + return this->PlainObjectBase>::operator()(i,j); + + else + { + if constexpr(R == 1) + return (*this)[j]; + return (*this)[i]; + } +} + +inline auto& init(const Scalar& x) +{ + for(size_t i = 0 ; i < this->size() ; i++) + *(this->data()+i) = x; + return *this; +} + +inline auto& init(const Matrix& x) // todo: keep this? +{ + *this = x; + return *this; +} + +inline bool is_squared() const +{ + return this->rows() == this->cols(); +} + +#define minmax_item(op) \ + Scalar m = *(this->data()); /* first element */ \ + for(size_t i = 1 ; i < this->size() ; i++) \ + { \ + if constexpr(std::is_same_v) \ + m = codac2::op(m,*(this->data()+i)); \ + else \ + m = std::op(m,*(this->data()+i)); \ + } \ + return m; \ + +inline Scalar min_coeff() const +{ + minmax_item(min); +} + +inline Scalar max_coeff() const +{ + minmax_item(max); +} + +inline friend auto abs(const Matrix& x) +{ + Matrix a(x); + + for(size_t i = 0 ; i < x.size() ; i++) + { + if constexpr(std::is_same_v) + *(a.data()+i) = fabs(*(x.data()+i)); + else + *(a.data()+i) = abs(*(x.data()+i)); + } + + return a; +} + +inline friend auto hull(const std::list>& l) +{ + assert_release(!l.empty()); + Matrix h(l.front()); + for(const auto& li : l) + h |= li; + return h; +} + +template +inline bool operator==(const Matrix& x) const +{ + if(this->size() != x.size()) + return false; + + if constexpr(std::is_same_v && std::is_same_v) + { + if(this->is_empty() || x.is_empty()) + return this->is_empty() && x.is_empty(); + } + + if(this->rows() != x.rows() || this->cols() != x.cols()) + return false; + + for(size_t i = 0 ; i < this->size() ; i++) + if(*(this->data()+i) != *(x.data()+i)) + return false; + + return true; +} \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h b/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h new file mode 100644 index 00000000..12bdb8cd --- /dev/null +++ b/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h @@ -0,0 +1,99 @@ +/** + * \file codac2_MatrixBase_eigenaddons.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +template + requires (!IsVectorOrRow) +explicit Matrix(int r, int c, const Scalar& x) + : Matrix(r,c) +{ + assert((R==(int)r || R==-1) && (C==(int)c || C==-1)); + assert(r >= 0 && c >= 0); + init(x); +} + +template + requires (!IsVectorOrRow) +explicit Matrix(int r, int c, const Scalar values[]) + : Matrix(r,c) +{ + assert((R==(int)r || R==-1) && (C==(int)c || C==-1)); + assert(r >= 0 && c >= 0); + + if(values == 0) + init(Scalar(0.)); // in case the user called Matrix(r,c,0) and 0 is interpreted as NULL! + + else + { + size_t k = 0; + for(size_t i = 0 ; i < this->rows() ; i++) + for(size_t j = 0 ; j < this->cols() ; j++) + (*this)(i,j) = values[k++]; + assert(k == this->size()); + } +} + +template + requires (!IsVectorOrRow) +inline auto block(size_t i, size_t j, size_t p, size_t q) +{ + assert_release(i >= 0 && p > 0 && i+p <= this->rows()); + assert_release(j >= 0 && q > 0 && j+q <= this->cols()); + return this->PlainObjectBase>::block(i,j,p,q); +} + +template + requires (!IsVectorOrRow) +inline auto block(size_t i, size_t j, size_t p, size_t q) const +{ + assert_release(i >= 0 && p > 0 && i+p <= this->rows()); + assert_release(j >= 0 && q > 0 && j+q <= this->cols()); + return this->PlainObjectBase>::block(i,j,p,q); +} + +template + requires (!IsVectorOrRow) +inline static Matrix zeros(size_t r, size_t c) +{ + assert_release(r >= 0 && c >= 0); + return Matrix::Zero(r,c); +} + +template + requires (!IsVectorOrRow) +inline static Matrix ones(size_t r, size_t c) +{ + assert_release(r >= 0 && c >= 0); + return Matrix::Ones(r,c); +} + +template + requires (!IsVectorOrRow) +inline static Matrix eye(size_t r, size_t c) +{ + assert_release(r >= 0 && c >= 0); + return Matrix::Identity(r,c); +} + +template + requires (!IsVectorOrRow) +inline void resize_save_values(size_t r, size_t c) +{ + // With resize() of Eigen, the data is reallocated and all previous values are lost. + auto copy = *this; + this->resize(r,c); + for(size_t i = 0 ; i < std::min((size_t)copy.rows(),r) ; i++) + for(size_t j = 0 ; j < std::min((size_t)copy.cols(),c) ; j++) + (*this)(i,j) = copy(i,j); +} \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_Matrix_eigenaddons.h b/src/core/matrices/eigen/codac2_Matrix_eigenaddons.h new file mode 100644 index 00000000..90c6ec54 --- /dev/null +++ b/src/core/matrices/eigen/codac2_Matrix_eigenaddons.h @@ -0,0 +1,19 @@ +/** + * \file codac2_Matrix_eigenaddons.h + * + * This class reuses some of the functions developed for ibex::Matrix. + * The original IBEX code is revised in modern C++ and adapted to the template + * structure proposed in Codac, based on the Eigen library. + * See ibex::Matrix (IBEX lib, author: Gilles Chabert) + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Gilles Chabert + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ diff --git a/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h b/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h new file mode 100644 index 00000000..1fc14273 --- /dev/null +++ b/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h @@ -0,0 +1,115 @@ +/** + * \file codac2_VectorBase_eigenaddons.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +template + requires IsVectorOrRow +explicit Matrix(int n, const Scalar& x) + : Matrix( + [&]() -> int { if(R == 1) return 1; else return n; }(), + [&]() -> int { if(C == 1) return 1; else return n; }() + ) +{ + assert_release(n > 0); + init(x); +} + +template + requires IsVectorOrRow +inline auto diag_matrix() const +{ + return this->asDiagonal().toDenseMatrix(); +} + +template + requires IsVectorOrRow +inline Scalar& operator()(size_t i) +{ + return const_cast(const_cast*>(this)->operator()(i)); +} + +template + requires IsVectorOrRow +inline const Scalar& operator()(size_t i) const +{ + assert_release(i >= 0 && i < this->size()); + return this->PlainObjectBase>::operator()(i); +} + +template + requires IsVectorOrRow +inline Scalar& operator[](size_t i) +{ + return const_cast(const_cast*>(this)->operator[](i)); +} + +template + requires IsVectorOrRow +inline const Scalar& operator[](size_t i) const +{ + assert_release(i >= 0 && i < this->size()); + return this->PlainObjectBase>::operator[](i); +} + +template + requires IsVectorOrRow +inline static Matrix zeros(size_t n) +{ + assert_release(n >= 0); + if constexpr(R == 1) + return Matrix::Zero(1,n); + else + return Matrix::Zero(n,1); +} + +template + requires IsVectorOrRow +inline static Matrix ones(size_t n) +{ + assert_release(n >= 0); + if constexpr(R == 1) + return Matrix::Ones(1,n); + else + return Matrix::Ones(n,1); +} + +template + requires IsVectorOrRow +inline auto subvector(size_t start_id, size_t end_id) const +{ + assert_release(end_id >= 0 && start_id >= 0); + assert_release(end_id < this->size() && start_id <= end_id); + return this->segment(start_id,end_id-start_id+1); +} + +template + requires IsVectorOrRow +inline void put(size_t start_id, const Matrix& x) +{ + assert_release(start_id >= 0 && start_id < this->size()); + assert_release(start_id+x.size() <= this->size()); + + this->segment(start_id,x.size()) << x; +} + +template + requires IsVectorOrRow +inline void resize_save_values(size_t n) +{ + // With resize() of Eigen, the data is reallocated and all previous values are lost. + auto copy = *this; + this->resize(n); + for(size_t i = 0 ; i < std::min((size_t)copy.size(),n) ; i++) + (*this)[i] = copy[i]; +} diff --git a/src/core/matrices/eigen/codac2_Vector_eigenaddons.h b/src/core/matrices/eigen/codac2_Vector_eigenaddons.h new file mode 100644 index 00000000..f105c108 --- /dev/null +++ b/src/core/matrices/eigen/codac2_Vector_eigenaddons.h @@ -0,0 +1,72 @@ +/** + * \file codac2_Vector_eigenaddons.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +template + requires (!IsIntervalDomain) && (IsVectorOrRow) +Matrix(std::initializer_list l) + : Matrix( + [&]() -> int { if(R == 1) return 1; else return l.size(); }(), + [&]() -> int { if(C == 1) return 1; else return l.size(); }() + ) +{ + assert_release(!std::empty(l)); + size_t i = 0; + for(const auto& li : l) + (*this)[i++] = li; +} + +template + requires (!IsIntervalDomain) && (IsVectorOrRow) +explicit Matrix(int n) + : Matrix( + [&]() -> int { if(R == 1) return 1; else return n; }(), + [&]() -> int { if(C == 1) return 1; else return n; }() + ) +{ + assert_release(n >= 0); + this->init(0.); +} + +template + requires (!IsIntervalDomain) && (IsVectorOrRow) +explicit Matrix(int n, double values[]) + : Matrix( + [&]() -> int { if(R == 1) return 1; else return n; }(), + [&]() -> int { if(C == 1) return 1; else return n; }(), + values + ) +{ + assert_release(n > 0); +} + +template + requires (!IsIntervalDomain) && (IsVectorOrRow) +inline size_t min_coeff_index() const +{ + size_t r,c; + this->minCoeff(&r,&c); + assert(c == 0); + return r; +} + +template + requires (!IsIntervalDomain) && (IsVectorOrRow) +inline size_t max_coeff_index() const +{ + size_t r,c; + this->maxCoeff(&r,&c); + assert(c == 0); + return r; +} \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_eigenaddons.h b/src/core/matrices/eigen/codac2_eigenaddons.h new file mode 100644 index 00000000..b2bec7db --- /dev/null +++ b/src/core/matrices/eigen/codac2_eigenaddons.h @@ -0,0 +1,23 @@ +/** + * \file codac2_eigenaddons.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_Base_eigenaddons.h" +#include "codac2_MatrixBase_eigenaddons.h" +#include "codac2_Matrix_eigenaddons.h" +#include "codac2_VectorBase_eigenaddons.h" +#include "codac2_Vector_eigenaddons.h" +#include "codac2_IntervalMatrixBase_eigenaddons.h" +#include "codac2_IntervalMatrix_eigenaddons.h" +#include "codac2_IntervalVector_eigenaddons.h" \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_eigenaddons_test.h b/src/core/matrices/eigen/codac2_eigenaddons_test.h new file mode 100644 index 00000000..fd2faa4a --- /dev/null +++ b/src/core/matrices/eigen/codac2_eigenaddons_test.h @@ -0,0 +1,25 @@ +/** + * \file codac2_eigenaddons.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + + + +inline bool is_empty() const +{ + for(size_t i = 0 ; i < rows() ; i++) + for(size_t j = 0 ; j < cols() ; j++) + if((*this)(i,j).is_empty()) + return true; + return false; +} \ No newline at end of file diff --git a/src/core/separators/codac2_SepEllipse.cpp b/src/core/separators/codac2_SepEllipse.cpp index 5a296f5f..b3c658d8 100644 --- a/src/core/separators/codac2_SepEllipse.cpp +++ b/src/core/separators/codac2_SepEllipse.cpp @@ -19,15 +19,15 @@ SepEllipse::SepEllipse(const Vector& q) assert_release(q.size() == 6); } -bool test_ellipse(const Vector& x, const Vector& q) +bool test_ellipse(const IntervalVector& x, const IntervalVector& q) { // todo: Interval evaluation: - return q[0] - + q[1]*x[0] - + q[2]*x[1] - + q[3]*pow(x[0],2) - + q[4]*x[0]*x[1] - + q[5]*pow(x[1],2) < 0.; + return (q[0] + + q[1]*x[0] + + q[2]*x[1] + + q[3]*pow(x[0],2) + + q[4]*x[0]*x[1] + + q[5]*pow(x[1],2)).ub() < 0.; } BoxPair SepEllipse::separate(const IntervalVector& x) const diff --git a/src/core/tools/codac2_Approx.h b/src/core/tools/codac2_Approx.h index 4584f742..f40c398d 100644 --- a/src/core/tools/codac2_Approx.h +++ b/src/core/tools/codac2_Approx.h @@ -11,6 +11,7 @@ #include #include "codac2_IntervalVector.h" +#include "codac2_matrices.h" namespace codac2 { @@ -26,7 +27,12 @@ namespace codac2 public: explicit Approx(const T& x, double eps = std::numeric_limits::epsilon()*10) - : _x(x ), _eps(eps) + : _x(x), _eps(eps) + { } + + template + explicit Approx(const Eigen::MatrixBase& x, double eps = std::numeric_limits::epsilon()*10) + : _x(x.eval()), _eps(eps) { } friend bool operator==(const T& x1, const Approx& x2) @@ -56,8 +62,8 @@ namespace codac2 else { - for(size_t i = 0 ; i < x1.nb_rows() ; i++) - for(size_t j = 0 ; j < x1.nb_cols() ; j++) + for(size_t i = 0 ; i < x1.rows() ; i++) + for(size_t j = 0 ; j < x1.cols() ; j++) if(!(((std::fabs(_lb(x1(i,j))-_lb(x2._x(i,j))) < x2._eps) && _ub(x1(i,j)) == _ub(x2._x(i,j))) || ((std::fabs(_ub(x1(i,j))-_ub(x2._x(i,j))) < x2._eps) && _lb(x1(i,j)) == _lb(x2._x(i,j))) || ((std::fabs(_lb(x1(i,j))-_lb(x2._x(i,j))) < x2._eps) && std::fabs(_ub(x1(i,j))-_ub(x2._x(i,j))) < x2._eps))) diff --git a/src/core/tools/codac2_template_tools.h b/src/core/tools/codac2_template_tools.h index 489dc5b6..000099ef 100644 --- a/src/core/tools/codac2_template_tools.h +++ b/src/core/tools/codac2_template_tools.h @@ -15,16 +15,6 @@ namespace codac2 { - template - concept IsMatrix = (std::is_same_v - || std::is_same_v,T> - || std::is_same_v,T>); - - template - concept IsIntervalMatrix = (std::is_same_v - || std::is_same_v,T> - || std::is_same_v,T>); - template concept IsCtcBaseOrPtr = (std::is_base_of_v,C> || std::is_same_v>,C>); diff --git a/tests/core/3rd/codac2_tests_ibex.cpp b/tests/core/3rd/codac2_tests_ibex.cpp index c2f86962..86b94fba 100644 --- a/tests/core/3rd/codac2_tests_ibex.cpp +++ b/tests/core/3rd/codac2_tests_ibex.cpp @@ -38,13 +38,13 @@ TEST_CASE("IBEX") // [Vector] Codac -> IBEX { - CHECK(codac2::to_ibex(codac2::Vector(2)) == ibex::Vector(2)); + CHECK(codac2::to_ibex(codac2::Vector::zeros(2)) == ibex::Vector(2)); CHECK(codac2::to_ibex(codac2::Vector({1,2,3})) == ibex::Vector({1,2,3})); } // [Vector] IBEX -> Codac { - CHECK(codac2::to_codac(ibex::Vector(2)) == codac2::Vector(2)); + CHECK(codac2::to_codac(ibex::Vector::zeros(2)) == codac2::Vector::zeros(2)); CHECK(codac2::to_codac(ibex::Vector({1,2,3})) == codac2::Vector({1,2,3})); } @@ -64,14 +64,14 @@ TEST_CASE("IBEX") // [Matrix] Codac -> IBEX { - CHECK(codac2::to_ibex(codac2::Matrix(2,3)) == ibex::Matrix(2,3)); + CHECK(codac2::to_ibex(codac2::Matrix::zeros(2,3)) == ibex::Matrix(2,3)); CHECK(codac2::to_ibex(codac2::Matrix({{1,2,3},{4,5,6}})) == ibex::Matrix({{1,2,3},{4,5,6}})); } // [Matrix] IBEX -> Codac { - CHECK(codac2::to_codac(ibex::Matrix(2,3)) == codac2::Matrix(2,3)); + CHECK(codac2::to_codac(ibex::Matrix(2,3)) == codac2::Matrix::zeros(2,3)); CHECK(codac2::to_codac(ibex::Matrix({{1,2,3},{4,5,6}})) == codac2::Matrix({{1,2,3},{4,5,6}})); } diff --git a/tests/core/contractors/codac2_tests_CtcAction.cpp b/tests/core/contractors/codac2_tests_CtcAction.cpp index fb74f9c5..cc62b968 100644 --- a/tests/core/contractors/codac2_tests_CtcAction.cpp +++ b/tests/core/contractors/codac2_tests_CtcAction.cpp @@ -18,7 +18,7 @@ TEST_CASE("CtcAction") { { VectorVar x(2); - CtcInverse_ c1(AnalyticFunction({x}, x-IntervalVector({{1,5},{8,6}})), IntervalVector({{0},{0}})); + CtcInverse_ c1(AnalyticFunction({x}, x-IntervalVector({{1,5},{8,6}})), IntervalVector({0.,0.})); IntervalVector b(2); c1.contract(b); diff --git a/tests/core/contractors/codac2_tests_CtcCtcBoundary.cpp b/tests/core/contractors/codac2_tests_CtcCtcBoundary.cpp index d9e95480..4dd9107c 100644 --- a/tests/core/contractors/codac2_tests_CtcCtcBoundary.cpp +++ b/tests/core/contractors/codac2_tests_CtcCtcBoundary.cpp @@ -13,6 +13,7 @@ #include #include #include +#include using namespace std; using namespace codac2; @@ -29,8 +30,8 @@ BoolInterval test_inside_diamond(const Vector& x) TEST_CASE("CtcCtcBoundary") { - auto ctc_bound_diamond = CtcSegment({{-1},{0}}, {{0},{-1}}) | CtcSegment({{0},{-1}}, {{1},{0}}) - | CtcSegment({{1},{0}}, {{0},{1}}) | CtcSegment({{0},{1}}, {{-1},{0}}); + auto ctc_bound_diamond = CtcSegment({-1,0}, {0,-1}) | CtcSegment({0,-1}, {1,0}) + | CtcSegment({1,0}, {0,1}) | CtcSegment({0,1}, {-1,0}); CtcCtcBoundary ctc_diamond(ctc_bound_diamond,test_inside_diamond); @@ -54,5 +55,5 @@ TEST_CASE("CtcCtcBoundary") x = IntervalVector({{0.5,10},{0.5,10}}); ctc_diamond.contract(x); //DefaultView::draw_box(x,Color::blue()); - CHECK(x == IntervalVector({{0.5},{0.5}})); + CHECK(x == IntervalVector({0.5,0.5})); } \ No newline at end of file diff --git a/tests/core/contractors/codac2_tests_CtcInverse.cpp b/tests/core/contractors/codac2_tests_CtcInverse.cpp index 9aa85c12..666c0084 100644 --- a/tests/core/contractors/codac2_tests_CtcInverse.cpp +++ b/tests/core/contractors/codac2_tests_CtcInverse.cpp @@ -81,9 +81,9 @@ TEST_CASE("CtcInverse") c.contract(b); CHECK(b == IntervalVector({{1,oo},{1,oo}})); - b = IntervalVector({{10},{10}}); + b = IntervalVector({10,10}); c.contract(b); - CHECK(b == IntervalVector({{10},{10}})); + CHECK(b == IntervalVector({10,10})); b = IntervalVector({{1,5},{8,9}}); c.contract(b); @@ -93,7 +93,7 @@ TEST_CASE("CtcInverse") { VectorVar x(2); AnalyticFunction f { {x}, vec(x[0]-x[1]) }; - CtcInverse_ c(f, {{0}}); + CtcInverse_ c(f, {0}); //pave(IntervalVector({{-10,10},{-10,10}}), c, 0.1); @@ -110,9 +110,9 @@ TEST_CASE("CtcInverse") c.contract(b); CHECK(b == IntervalVector({{1,oo},{1,oo}})); - b = IntervalVector({{10},{10}}); + b = IntervalVector({10,10}); c.contract(b); - CHECK(b == IntervalVector({{10},{10}})); + CHECK(b == IntervalVector({10,10})); b = IntervalVector({{1,5},{8,9}}); c.contract(b); diff --git a/tests/core/contractors/codac2_tests_CtcInverseNotIn.cpp b/tests/core/contractors/codac2_tests_CtcInverseNotIn.cpp index 65883a36..d66035a2 100644 --- a/tests/core/contractors/codac2_tests_CtcInverseNotIn.cpp +++ b/tests/core/contractors/codac2_tests_CtcInverseNotIn.cpp @@ -28,7 +28,7 @@ TEST_CASE("CtcInverseNotIn") VectorVar x(2); AnalyticFunction f { {x}, vec(x[0]-x[1]) }; - CtcInverseNotIn c(f, {{0}}); + CtcInverseNotIn c(f, {0}); //pave(IntervalVector({{-10,10},{-10,10}}), c, 0.1); @@ -45,9 +45,9 @@ TEST_CASE("CtcInverseNotIn") c.contract(b); CHECK(b == IntervalVector({{1,oo},{1,oo}})); - b = IntervalVector({{10},{10}}); + b = IntervalVector({10,10}); c.contract(b); - CHECK(b == IntervalVector({{10},{10}})); + CHECK(b == IntervalVector({10,10})); b = IntervalVector({{1,5},{8,9}}); c.contract(b); diff --git a/tests/core/contractors/codac2_tests_CtcPolygon.cpp b/tests/core/contractors/codac2_tests_CtcPolygon.cpp index ee23daa8..49a16e95 100644 --- a/tests/core/contractors/codac2_tests_CtcPolygon.cpp +++ b/tests/core/contractors/codac2_tests_CtcPolygon.cpp @@ -33,24 +33,24 @@ TEST_CASE("CtcPolygon - tests from Codac1") { CtcPolygon c({ // external border - {{6,-6},{7,9}}, - {{7,9},{0,5}}, - {{0,5},{-9,8}}, - {{-9,8},{-8,-9}}, - {{-8,-9},{6,-6}}, + Edge({{6,-6},{7,9}}), + Edge({{7,9},{0,5}}), + Edge({{0,5},{-9,8}}), + Edge({{-9,8},{-8,-9}}), + Edge({{-8,-9},{6,-6}}), // hole - {{-2,3},{3.5,2}}, - {{3.5,2},{1.5,0.5}}, - {{1.5,0.5},{3,-4}}, - {{3,-4},{-3,-3}}, - {{-3,-3},{-2,3}} + Edge({{-2,3},{3.5,2}}), + Edge({{3.5,2},{1.5,0.5}}), + Edge({{1.5,0.5},{3,-4}}), + Edge({{3,-4},{-3,-3}}), + Edge({{-3,-3},{-2,3}}) }); //draw_while_paving(IntervalVector({{-10,10},{-10,10}}), c, 0.1); // Check a box inside the hole { - IntervalVector x = IntervalVector({{0},{0}}).inflate(0.5); + IntervalVector x = IntervalVector({0,0}).inflate(0.5); //DefaultView::draw_box(x,Color::purple()); c.contract(x); CHECK(x.is_empty()); @@ -58,7 +58,7 @@ TEST_CASE("CtcPolygon - tests from Codac1") // Check a box inside the polygon { - IntervalVector x = IntervalVector({{5},{-5}}).inflate(0.5), _x(x); + IntervalVector x = IntervalVector({5,-5}).inflate(0.5), _x(x); //DefaultView::draw_box(x,Color::purple()); c.contract(x); CHECK(x == _x); @@ -66,7 +66,7 @@ TEST_CASE("CtcPolygon - tests from Codac1") // Check a box outside the polygon { - IntervalVector x = IntervalVector({{-1},{8}}).inflate(0.5); + IntervalVector x = IntervalVector({-1,8}).inflate(0.5); //DefaultView::draw_box(x,Color::purple()); c.contract(x); CHECK(x.is_empty()); @@ -78,14 +78,14 @@ TEST_CASE("CtcPolygon - tests from Codac1") // Check a box inside the polygon { - IntervalVector x = IntervalVector({{5},{-5}}).inflate(0.5), _x(x); + IntervalVector x = IntervalVector({5,-5}).inflate(0.5), _x(x); c.contract(x); CHECK(x == _x); } // Check a box outside the polygon { - IntervalVector x = IntervalVector({{-1},{8}}).inflate(0.5); + IntervalVector x = IntervalVector({-1,8}).inflate(0.5); c.contract(x); CHECK(x.is_empty()); } diff --git a/tests/core/contractors/codac2_tests_CtcSegment.cpp b/tests/core/contractors/codac2_tests_CtcSegment.cpp index 3e600a61..9b49ed34 100644 --- a/tests/core/contractors/codac2_tests_CtcSegment.cpp +++ b/tests/core/contractors/codac2_tests_CtcSegment.cpp @@ -17,7 +17,7 @@ TEST_CASE("CtcSegment") { { IntervalVector x(2); - CtcSegment c({{3},{-1}},{{3},{4}}); + CtcSegment c({3,-1},{3,4}); x = IntervalVector(2); c.contract(x); @@ -34,7 +34,7 @@ TEST_CASE("CtcSegment") { IntervalVector x(2); - CtcSegment c({{-1},{-1}},{{1},{1}}); + CtcSegment c({-1,-1},{1,1}); x = IntervalVector(2); c.contract(x); @@ -42,7 +42,7 @@ TEST_CASE("CtcSegment") x = IntervalVector({{-oo,oo},{0}}); c.contract(x); - CHECK(x == IntervalVector({{0},{0}})); + CHECK(x == IntervalVector({0,0})); x = IntervalVector({{0,oo},{0,oo}}); c.contract(x); @@ -58,7 +58,7 @@ TEST_CASE("CtcSegment - tests from Codac1") { // Test_CtcSegment01 { - CtcSegment c({{0},{0}}, {{10},{20}}); + CtcSegment c({0,0}, {10,20}); IntervalVector x({{-5,50},{-5, 50}}); c.contract(x); CHECK(x == IntervalVector({{0,10},{0,20}})); @@ -66,7 +66,7 @@ TEST_CASE("CtcSegment - tests from Codac1") // Test_CtcSegment02 { - CtcSegment c({{0},{0}}, {{10},{20}}); + CtcSegment c({0,0}, {10,20}); IntervalVector x({{10,50},{20,50}}); c.contract(x); CHECK(x == IntervalVector({{10,10},{20,20}})); @@ -74,7 +74,7 @@ TEST_CASE("CtcSegment - tests from Codac1") // Test_contract_degenerate { - CtcSegment c({{5},{5}}, {{5},{5}}); + CtcSegment c({5,5}, {5,5}); IntervalVector x({{-5,50},{-5,50}}); c.contract(x); CHECK(x == IntervalVector({{5,5},{5,5}})); @@ -82,7 +82,7 @@ TEST_CASE("CtcSegment - tests from Codac1") // Test_contract_degenerate_x { - CtcSegment c({{5},{5}}, {{10},{5}}); + CtcSegment c({5,5}, {10,5}); IntervalVector x({{-50,50},{-50,50}}); c.contract(x); CHECK(x == IntervalVector({{5,10},{5,5}})); @@ -90,7 +90,7 @@ TEST_CASE("CtcSegment - tests from Codac1") // Test_contract_degenerate_y { - CtcSegment c({{-5},{-5}}, {{-5},{15}}); + CtcSegment c({-5,-5}, {-5,15}); IntervalVector x({Interval(-50, 50), Interval(-50, 50)}); c.contract(x); CHECK(x == IntervalVector({{-5,-5},{-5,15}})); @@ -98,7 +98,7 @@ TEST_CASE("CtcSegment - tests from Codac1") // Test_contract_empty { - CtcSegment c({{0},{0}}, {{10},{20}}); + CtcSegment c({0,0}, {10,20}); IntervalVector x({{-5,-2},{-5,50}}); c.contract(x); CHECK(x.is_empty()); @@ -106,7 +106,7 @@ TEST_CASE("CtcSegment - tests from Codac1") // Test_call_with_empty_x { - CtcSegment c({{0},{0}}, {{10},{20}}); + CtcSegment c({0,0}, {10,20}); IntervalVector x(2); c.contract(x); CHECK(x == IntervalVector({{0,10},{0,20}})); diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp index 402932ac..2f23b0dc 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -66,10 +67,10 @@ TEST_CASE("IntervalMatrix") IntervalMatrix m1(2,3); IntervalMatrix m2(2,3); - CHECK(m1.nb_rows() == 2); - CHECK(m1.nb_cols() == 3); - CHECK(m2.nb_rows() == 2); - CHECK(m2.nb_cols() == 3); + CHECK(m1.rows() == 2); + CHECK(m1.cols() == 3); + CHECK(m2.rows() == 2); + CHECK(m2.cols() == 3); m1(0,0) = 1.; m1(0,1) = 2.; @@ -107,8 +108,8 @@ TEST_CASE("IntervalMatrix") { IntervalMatrix m(2,3); - CHECK(m.nb_rows() == 2); - CHECK(m.nb_cols() == 3); + CHECK(m.rows() == 2); + CHECK(m.cols() == 3); CHECK(m(0,0) == Interval(-oo,oo)); CHECK(m(0,1) == Interval(-oo,oo)); CHECK(m(0,2) == Interval(-oo,oo)); @@ -122,33 +123,27 @@ TEST_CASE("IntervalMatrix") { IntervalMatrix m1(2,3, 0.); - double _r1[][2] = {{0,1},{0,2},{0,3}}; - double _r2[][2] = {{-1,0},{-2,0},{-3,0}}; - auto r1_0 = IntervalVector(3,_r1); - CHECK(r1_0.nb_cols() == 1); - CHECK(r1_0.nb_rows() == 3); - auto r1 = IntervalVector(3,_r1).transpose(); - CHECK(r1.nb_cols() == 3); - CHECK(r1.nb_rows() == 1); - auto r2 = IntervalVector(3,_r2).transpose(); - CHECK(r2.nb_cols() == 3); - CHECK(r2.nb_rows() == 1); + auto r1_0 = IntervalVector({{0,1},{0,2},{0,3}}); + CHECK(r1_0.cols() == 1); + CHECK(r1_0.rows() == 3); + auto r1 = IntervalVector({{0,1},{0,2},{0,3}}).transpose().eval(); + CHECK(r1.cols() == 3); + CHECK(r1.rows() == 1); + auto r2 = IntervalVector({{-1,0},{-2,0},{-3,0}}).transpose().eval(); + CHECK(r2.cols() == 3); + CHECK(r2.rows() == 1); CHECK(r1 == IntervalMatrix({ { {0,1}, {0,2}, {0,3} } })); m1.row(0) = r1; m1.row(1) = r2; - double _c1[][2] = {{0,1},{-1,0}}; - double _c2[][2] = {{0,2},{-2,0}}; - double _c3[][2] = {{0,3},{-3,0}}; + IntervalVector c1({{0,1},{-1,0}}); + IntervalVector c2({{0,2},{-2,0}}); + IntervalVector c3({{0,3},{-3,0}}); - IntervalVector c1(2,_c1); - IntervalVector c2(2,_c2); - IntervalVector c3(2,_c3); - - CHECK(m1.nb_rows() == 2); - CHECK(m1.nb_cols() == 3); + CHECK(m1.rows() == 2); + CHECK(m1.cols() == 3); CHECK((m1.row(0) == r1)); CHECK((m1.row(1) == r2)); CHECK((m1.row(0) == r1)); @@ -172,8 +167,8 @@ TEST_CASE("IntervalMatrix") Interval x(-1,2); IntervalMatrix m(2,3,x); - CHECK(m.nb_rows() == 2); - CHECK(m.nb_cols() == 3); + CHECK(m.rows() == 2); + CHECK(m.cols() == 3); for(size_t i = 0 ; i < 2 ; i++) for(size_t j = 0 ; j < 3 ; j++) CHECK(m(i,j) == x); @@ -212,8 +207,8 @@ TEST_CASE("IntervalMatrix") } { - CHECK(IntervalMatrix::empty(2,3).nb_rows() == 2); - CHECK(IntervalMatrix::empty(2,3).nb_cols() == 3); + CHECK(IntervalMatrix::empty(2,3).rows() == 2); + CHECK(IntervalMatrix::empty(2,3).cols() == 3); CHECK(IntervalMatrix(IntervalMatrix::empty(2,3)) == IntervalMatrix::empty(2,3)); CHECK((IntervalMatrix(2,3)=IntervalMatrix::empty(2,3)) == IntervalMatrix::empty(2,3)); @@ -306,13 +301,11 @@ TEST_CASE("IntervalMatrix") { IntervalMatrix m1(2,2); - double _r1[][2] = {{0,1},{0,2}}; - double _r2[][2] = {{-1,0},{-2,0}}; - IntervalVector r1(2,_r1); - IntervalVector r2(2,_r2); - m1.row(0) = r1.transpose(); - m1.row(1) = r2.transpose(); - m1.resize(2,3); + IntervalVector r1({{0,1},{0,2}}); + IntervalVector r2({{-1,0},{-2,0}}); + m1.row(0) = r1.transpose().eval(); + m1.row(1) = r2.transpose().eval(); + m1.resize_save_values(2,3); m1(0,2) = Interval(0,3); m1(1,2) = Interval(-3,0); @@ -321,10 +314,9 @@ TEST_CASE("IntervalMatrix") { IntervalMatrix m1(1,3); - double _r1[][2] = {{0,1},{0,2},{0,3}}; - IntervalVector r1(3,_r1); - m1.row(0) = r1.transpose(); - m1.resize(2,3); + IntervalVector r1({{0,1},{0,2},{0,3}}); + m1.row(0) = r1.transpose().eval(); + m1.resize_save_values(2,3); m1(1,0) = Interval(-1,0); m1(1,1) = Interval(-2,0); m1(1,2) = Interval(-3,0); @@ -334,7 +326,7 @@ TEST_CASE("IntervalMatrix") { IntervalMatrix e(IntervalMatrix::empty(1,1)); - e.resize(2,3); + e.resize_save_values(2,3); CHECK(e.is_empty()); } @@ -393,8 +385,8 @@ TEST_CASE("IntervalMatrix") IntervalMatrix m1(M1()); IntervalMatrix m2(M2()); IntervalMatrix m3(m1*m2); - CHECK(m3.nb_rows() == 2); - CHECK(m3.nb_cols() == 2); + CHECK(m3.rows() == 2); + CHECK(m3.cols() == 2); for(size_t i = 0 ; i < 2 ; i++) for(size_t j = 0 ; j < 2 ; j++) @@ -451,7 +443,7 @@ TEST_CASE("IntervalMatrix") IntervalMatrix res(4,4); res.block(0,0,3,3) = M1; res.block(0,3,3,1) = V1; - res.block(3,0,1,3) = IntervalVector::ones(3).transpose(); + res.block(3,0,1,3) = IntervalVector::ones(3).transpose().eval(); res(3,3) = 6; double _expected[16] = { 2,0,0,3, @@ -510,7 +502,7 @@ TEST_CASE("IntervalMatrix") } } -TEST_CASE("IntervalMatrix - mixing types") +TEST_CASE("IntervalMatrix - mixing type") { { Matrix m1 { @@ -531,10 +523,13 @@ TEST_CASE("IntervalMatrix - mixing types") }); IntervalVector v1({ - {-1}, - {-2} + -1, + -2 }); + CHECK(v1[0] == -1); + CHECK(v1[1] == -2); + IntervalVector iv1({ {-1,1}, {-1,1} @@ -614,6 +609,29 @@ TEST_CASE("IntervalMatrix - mixing types") // Row of IntervalMatrix - col of IntervalMatrix CHECK((im1.row(1) * im1.col(0)) == IntervalMatrix({{{-15,15}}})); } + + { + Matrix m1 { + { {1},{2} }, + { {3},{4} } + }; + + Matrix m2 { + { {2},{3} }, + { {4},{5} } + }; + + IntervalMatrix im(m1,m2); + CHECK(im == IntervalMatrix{ + { {1,2},{2,3} }, + { {3,4},{4,5} } + }); + + m2(0,1) = 1.; + + IntervalMatrix im_empty(m1,m2); + CHECK(im_empty == IntervalMatrix::empty(2,2)); + } } #if 0 diff --git a/tests/core/domains/interval/codac2_tests_IntervalVector.cpp b/tests/core/domains/interval/codac2_tests_IntervalVector.cpp index 12cbfe24..92681bfc 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalVector.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalVector.cpp @@ -33,7 +33,7 @@ void CHECK_diff(const IntervalVector& x, const IntervalVector& y, bool compactne for(const auto& ci : c) { bool found = false; - for(size_t i = 0 ; i < result.nb_rows() ; i++) + for(size_t i = 0 ; i < result.rows() ; i++) if(ci == IntervalMatrix(result.row(i)).transpose().col(0)) { found = true; @@ -58,7 +58,7 @@ TEST_CASE("IntervalVector") IntervalVector x(2); x[0] = Interval(0,1); x[1] = Interval(0,1); - CHECK(x == IntervalVector(2,Interval(0,1))); + CHECK(x == IntervalVector({{0,1},{0,1}})); CHECK(x == IntervalVector(x)); CHECK(x == (IntervalVector(2)=x)); } @@ -112,7 +112,7 @@ TEST_CASE("IntervalVector") { IntervalVector x(1); x[0] = Interval(1,2); - x.resize(3); + x.resize_save_values(3); CHECK(x.size() == 3); CHECK(x[0] == Interval(1,2)); CHECK(x[1] == Interval(-oo,oo)); @@ -122,7 +122,7 @@ TEST_CASE("IntervalVector") { IntervalVector x(1); x[0] = Interval(1,2); - x.resize(1); + x.resize_save_values(1); CHECK(x.size() == 1); CHECK(x[0] == Interval(1,2)); } @@ -131,7 +131,7 @@ TEST_CASE("IntervalVector") IntervalVector x(2); x[0] = Interval(1,2); x.set_empty(); - x.resize(3); + x.resize_save_values(3); CHECK(x.size() == 3); CHECK(x.is_empty()); CHECK(x[2] == Interval(-oo,oo)); @@ -141,7 +141,7 @@ TEST_CASE("IntervalVector") IntervalVector x(5); x[0] = Interval(1,2); x[1] = Interval(3,4); - x.resize(2); + x.resize_save_values(2); CHECK(x.size() == 2); CHECK(x[0] == Interval(1,2)); CHECK(x[1] == Interval(3,4)); @@ -239,8 +239,8 @@ TEST_CASE("IntervalVector") CHECK(!IntervalVector({{0,1},{2,3},{4,5}}).is_flat()); CHECK(IntervalVector::empty(3).is_flat()); - CHECK(IntervalVector(1,Interval(0,0)).is_flat()); - CHECK(!IntervalVector(1,Interval(0,1)).is_flat()); + CHECK(IntervalVector({{0,0}}).is_flat()); + CHECK(!IntervalVector({{0,1}}).is_flat()); CHECK(IntervalVector({{0,1},{2,2},{3,4}}).is_flat()); CHECK(IntervalVector({{0,1},{2,3},{4,4}}).is_flat()); CHECK(!IntervalVector::empty(3).is_unbounded()); diff --git a/tests/core/domains/interval/codac2_tests_Interval_bwd.cpp b/tests/core/domains/interval/codac2_tests_Interval_bwd.cpp index 92453556..be6ce2c4 100644 --- a/tests/core/domains/interval/codac2_tests_Interval_bwd.cpp +++ b/tests/core/domains/interval/codac2_tests_Interval_bwd.cpp @@ -365,9 +365,9 @@ TEST_CASE("bwd mul operations") A(1,0) = deltaM; A(1,1) = 1+deltaM; - Vector b(2,1.0); + Vector b({1,1}); - IntervalVector x(2,Interval(-10,10)); + IntervalVector x({{-10,10},{-10,10}}); double _M[16]={1+delta, 0, 0, delta, 0, 1-delta, 0, -delta, @@ -376,13 +376,13 @@ TEST_CASE("bwd mul operations") Matrix M(4,4,_M); Matrix invM = M.inverse(); - Vector b2(4,1.0); + Vector b2 = Vector::ones(4); Vector bounds = invM * b2; - double _x2[2][2]={ {bounds[0],bounds[1]}, {bounds[2],bounds[3]} }; - IntervalVector x2(2,_x2); - - MulOp::bwd(b,A,x); - - cout << x << endl; - cout << x2 << endl; + //double _x2[][2]={ {bounds[0],bounds[1]}, {bounds[2],bounds[3]} }; + //IntervalVector x2(_x2,(size_t)2); + // + //MulOp::bwd(b,A,x); + // + //cout << x << endl; + //cout << x2 << endl; } \ No newline at end of file diff --git a/tests/core/functions/analytic/codac2_tests_AnalyticFunction.cpp b/tests/core/functions/analytic/codac2_tests_AnalyticFunction.cpp index 45b4b82a..cc09983c 100644 --- a/tests/core/functions/analytic/codac2_tests_AnalyticFunction.cpp +++ b/tests/core/functions/analytic/codac2_tests_AnalyticFunction.cpp @@ -71,7 +71,7 @@ TEST_CASE("AnalyticFunction") AnalyticFunction f({x}, vec(x,x)); AnalyticFunction fvec({x}, vec(x,x)); - CHECK(Approx(f.eval(m, 1)) == IntervalVector({{1},{1}})); + CHECK(Approx(f.eval(m, 1)) == IntervalVector({1,1})); } { @@ -112,7 +112,7 @@ TEST_CASE("AnalyticFunction") // .def("__rmul__", {}(const ScalarVar& e1, const Interval& e2); CHECK(AnalyticFunction({x1}, Interval(6.)*x1).eval(m, 5.) == 30.); // .def("__mul__", {}(const ScalarVar& e1, const VectorVar& e2); - CHECK(AnalyticFunction({v1,v2}, v1[0]*v2).eval(m, Vector({5.,10.}),IntervalVector(2,3.)) == Vector(2,15.)); + CHECK(AnalyticFunction({v1,v2}, v1[0]*v2).eval(m, Vector({5.,10.}),IntervalVector({3,3})) == Vector({15,15})); // .def("__mul__", {}(const ScalarVar& e1, const IntervalVector& e2); CHECK(AnalyticFunction({x1}, x1*IntervalVector({{-2,3},{0,1}})).centered_eval(5.) == IntervalVector({{-10,15},{0,5}})); // .def("__truediv__", {}(const ScalarVar& e1, const ScalarVar& e2); @@ -123,23 +123,24 @@ TEST_CASE("AnalyticFunction") CHECK(Approx(AnalyticFunction({x1}, Interval(2.)/x1).eval(m, 10.)) == 0.2); // ======> VectorVar + CHECK(-IntervalVector({-5.,-6.}) == Vector({5.,6.})); //.def("__pos__", {}(const VectorVar& e1); CHECK(AnalyticFunction({v1}, +v1).eval(m, Vector({5.,6.})) == Vector({5.,6.})); //.def("__add__", {}(const VectorVar& e1, const VectorVar& e2); CHECK(AnalyticFunction({v1,v2}, v1+v2).eval(m, Vector({5.,6.}),Vector({2.,3.})) == Vector({7.,9.})); //.def("__add__", {}(const VectorVar& e1, const IntervalVector& e2); - CHECK(AnalyticFunction({v1}, v1+IntervalVector({{2},{3}})).eval(m, Vector({5.,6.})) == IntervalVector({{7.},{9.}})); + CHECK(AnalyticFunction({v1}, v1+IntervalVector({2,3})).eval(m, Vector({5.,6.})) == IntervalVector({7.,9.})); //.def("__radd__", {}(const VectorVar& e1, const IntervalVector& e2); - CHECK(AnalyticFunction({v1}, IntervalVector({{2},{3}})+v1).eval(m, Vector({5.,6.})) == IntervalVector({{7.},{9.}})); + CHECK(AnalyticFunction({v1}, IntervalVector({2,3})+v1).eval(m, Vector({5.,6.})) == IntervalVector({7.,9.})); //.def("__neg__", {}(const VectorVar& e1); CHECK(AnalyticFunction({v1}, -v1).eval(m, Vector({5.,6.})) == -Vector({5.,6.})); //.def("__sub__", {}(const VectorVar& e1, const VectorVar& e2); CHECK(AnalyticFunction({v1,v2}, v1-v2).eval(m, Vector({5.,6.}),Vector({2.,3.})) == Vector({3.,3.})); //.def("__sub__", {}(const VectorVar& e1, const IntervalVector& e2); - CHECK(AnalyticFunction({v1}, v1-IntervalVector({{2},{3}})).eval(m, Vector({5.,6.})) == IntervalVector({{3.},{3.}})); + CHECK(AnalyticFunction({v1}, v1-IntervalVector({2,3})).eval(m, Vector({5.,6.})) == IntervalVector({3.,3.})); //.def("__rsub__", {}(const VectorVar& e1, const IntervalVector& e2); - CHECK(AnalyticFunction({v1}, IntervalVector({{2},{3}})-v1).eval(m, Vector({5.,6.})) == IntervalVector({{-3.},{-3.}})); + CHECK(AnalyticFunction({v1}, IntervalVector({2,3})-v1).eval(m, Vector({5.,6.})) == IntervalVector({-3.,-3.})); // ======> ScalarExpr @@ -178,7 +179,7 @@ TEST_CASE("AnalyticFunction") //.def("__rmul__", {}(const ScalarExpr& e1, const Interval& e2); CHECK(Approx(AnalyticFunction({x1}, Interval(10.)*cos(x1)).eval(m, codac2::pi),1e-9) == -10); //.def("__mul__", {}(const ScalarExpr& e1, const VectorExpr& e2); - CHECK(Approx(AnalyticFunction({v1,v2}, cos(v1[0])*(v2+v2)).eval(m, Vector({codac2::pi,-1}),Vector({2,3})),1e-9) == IntervalVector({{-4},{-6}})); + CHECK(Approx(AnalyticFunction({v1,v2}, cos(v1[0])*(v2+v2)).eval(m, Vector({codac2::pi,-1}),Vector({2,3})),1e-9) == IntervalVector({-4,-6})); //.def("__truediv__", {}(const ScalarExpr& e1, const ScalarExpr& e2); CHECK(Approx(AnalyticFunction({x1}, cos(x1)/cos(x1)).eval(m, Interval(0.))) == Interval(1.)); //.def("__truediv__", {}(const ScalarExpr& e1, const ScalarVar& e2); @@ -208,75 +209,75 @@ TEST_CASE("AnalyticFunction") CHECK(Approx(AnalyticFunction({v1}, -(v1+v1)).eval(m, IntervalVector({{0.},{-oo,5}}))) == (m == EvaluationMode::CENTERED ? IntervalVector({{0.},{-oo,oo}}) : IntervalVector({{0.},{-10,oo}}))); //.def(py::self - py::self); - CHECK(Approx(AnalyticFunction({v1,v2}, (v1-v2)).eval(m, IntervalVector({{2},{3}}),Vector({1,5}))) == IntervalVector({{1},{-2}})); + CHECK(Approx(AnalyticFunction({v1,v2}, (v1-v2)).eval(m, IntervalVector({2,3}),Vector({1,5}))) == IntervalVector({1,-2})); //.def("__sub__", {}(const VectorExpr& e1, const VectorVar& e2); - CHECK(Approx(AnalyticFunction({v1,v2}, (v1-v2)-v1).eval(m, IntervalVector({{2},{3}}),Vector({1,5}))) == IntervalVector({{-1},{-5}})); + CHECK(Approx(AnalyticFunction({v1,v2}, (v1-v2)-v1).eval(m, IntervalVector({2,3}),Vector({1,5}))) == IntervalVector({-1,-5})); //.def("__rsub__", {}(const VectorExpr& e1, const VectorVar& e2); - CHECK(Approx(AnalyticFunction({v1,v2}, v2-(v1-v2)).eval(m, IntervalVector({{2},{3}}),Vector({1,5}))) == IntervalVector({{0},{7}})); + CHECK(Approx(AnalyticFunction({v1,v2}, v2-(v1-v2)).eval(m, IntervalVector({2,3}),Vector({1,5}))) == IntervalVector({0,7})); //.def("__sub__", {}(const VectorExpr& e1, const IntervalVector& e2); - CHECK(Approx(AnalyticFunction({v1,v2}, (v1-v2)-IntervalVector({{2},{3}})).eval(m, IntervalVector({{2},{3}}),Vector({1,5}))) == IntervalVector({{-1},{-5}})); + CHECK(Approx(AnalyticFunction({v1,v2}, (v1-v2)-IntervalVector({2,3})).eval(m, IntervalVector({2,3}),Vector({1,5}))) == IntervalVector({-1,-5})); //.def("__rsub__", {}(const VectorExpr& e1, const IntervalVector& e2); - CHECK(Approx(AnalyticFunction({v1,v2}, Vector({1,5})-(v1-v2)).eval(m, IntervalVector({{2},{3}}),Vector({1,5}))) == IntervalVector({{0},{7}})); + CHECK(Approx(AnalyticFunction({v1,v2}, Vector({1,5})-(v1-v2)).eval(m, IntervalVector({2,3}),Vector({1,5}))) == IntervalVector({0,7})); //.def("__rmul__", {}(const VectorExpr& e1, const ScalarExpr& e2); - CHECK(Approx(AnalyticFunction({v1,v2}, cos(v1[0])*(v2+v2)).eval(m, Vector({codac2::pi,-1}),Vector({2,3})),1e-9) == IntervalVector({{-4},{-6}})); + CHECK(Approx(AnalyticFunction({v1,v2}, cos(v1[0])*(v2+v2)).eval(m, Vector({codac2::pi,-1}),Vector({2,3})),1e-9) == IntervalVector({-4,-6})); //.def("__rmul__", {}(const VectorExpr& e1, const ScalarVar& e2); - CHECK(Approx(AnalyticFunction({x1}, x1*vec(3*x1,2*x1)).eval(m, 3),1e-9) == IntervalVector({{27},{18}})); + CHECK(Approx(AnalyticFunction({x1}, x1*vec(3*x1,2*x1)).eval(m, 3),1e-9) == IntervalVector({27,18})); } } - { - VectorVar x(2); - AnalyticFunction f({x}, x[0]*(x[0]+x[1])+sqr(x[1])); - CHECK(f.diff(Vector({2,3}))(0,0) == 7); - CHECK(f.diff(Vector({2,3}))(0,1) == 8); - } + { + VectorVar x(2); + AnalyticFunction f({x}, x[0]*(x[0]+x[1])+sqr(x[1])); + CHECK(f.diff(Vector({2,3}))(0,0) == 7); + CHECK(f.diff(Vector({2,3}))(0,1) == 8); + } - { // int values - ScalarVar x, y; - AnalyticFunction f({x,y}, x*(x+y)+sqr(y)); - CHECK(f.diff(2,3)(0,0) == 7); - CHECK(f.diff(2,3)(0,1) == 8); - } + { // int values + ScalarVar x, y; + AnalyticFunction f({x,y}, x*(x+y)+sqr(y)); + CHECK(f.diff(2,3)(0,0) == 7); + CHECK(f.diff(2,3)(0,1) == 8); + } - { // double values - ScalarVar x, y; - AnalyticFunction f({x,y}, x*(x+y)+sqr(y)); - CHECK(f.diff(2.,3.)(0,0) == 7); - CHECK(f.diff(2.,3.)(0,1) == 8); - } + { // double values + ScalarVar x, y; + AnalyticFunction f({x,y}, x*(x+y)+sqr(y)); + CHECK(f.diff(2.,3.)(0,0) == 7); + CHECK(f.diff(2.,3.)(0,1) == 8); + } - { // Interval values - ScalarVar x, y; - AnalyticFunction f({x,y}, x*(x+y)+sqr(y)); - CHECK(f.diff(Interval(2.),Interval(3.))(0,0) == 7); - CHECK(f.diff(Interval(2.),Interval(3.))(0,1) == 8); - } + { // Interval values + ScalarVar x, y; + AnalyticFunction f({x,y}, x*(x+y)+sqr(y)); + CHECK(f.diff(Interval(2.),Interval(3.))(0,0) == 7); + CHECK(f.diff(Interval(2.),Interval(3.))(0,1) == 8); + } - { - ScalarVar x; - AnalyticFunction f({x}, x-x); - CHECK(f.natural_eval(Interval(-1,1)) == Interval(-2,2)); - CHECK(f.centered_eval(Interval(-1,1)) == Interval(0)); - CHECK(f.eval(Interval(-1,1)) == Interval(0)); - } + { + ScalarVar x; + AnalyticFunction f({x}, x-x); + CHECK(f.natural_eval(Interval(-1,1)) == Interval(-2,2)); + CHECK(f.centered_eval(Interval(-1,1)) == Interval(0)); + CHECK(f.eval(Interval(-1,1)) == Interval(0)); + } - // Subvector on variables - { - VectorVar p(2); - VectorVar x(4); - AnalyticFunction f({p}, p[0]*p[1]); - AnalyticFunction g({x}, f(x.subvector(0,1)) + f(x.subvector(2,3))); + // Subvector on variables + { + VectorVar p(2); + VectorVar x(4); + AnalyticFunction f({p}, p[0]*p[1]); + AnalyticFunction g({x}, f(x.subvector(0,1)) + f(x.subvector(2,3))); - IntervalVector a(4); + IntervalVector a(4); - a = IntervalVector({{1},{2},{3},{4}}); - CHECK(g.natural_eval(a) == 14); - CHECK(g.centered_eval(a) == 14); - CHECK(g.eval(a) == 14); + a = IntervalVector({1,2,3,4}); + CHECK(g.natural_eval(a) == 14); + CHECK(g.centered_eval(a) == 14); + CHECK(g.eval(a) == 14); - a = IntervalVector({{0},{2},{5},{4}}); - CHECK(g.natural_eval(a) == 20); - CHECK(g.centered_eval(a) == 20); - CHECK(g.eval(a) == 20); - } + a = IntervalVector({0,2,5,4}); + CHECK(g.natural_eval(a) == 20); + CHECK(g.centered_eval(a) == 20); + CHECK(g.eval(a) == 20); + } } \ No newline at end of file diff --git a/tests/core/matrices/codac2_tests_arithmetic_add.cpp b/tests/core/matrices/codac2_tests_arithmetic_add.cpp index aede6ceb..b9840998 100644 --- a/tests/core/matrices/codac2_tests_arithmetic_add.cpp +++ b/tests/core/matrices/codac2_tests_arithmetic_add.cpp @@ -8,6 +8,8 @@ */ #include +#include +#include #include #include #include @@ -39,7 +41,7 @@ TEST_CASE("arithmetic add") CHECK(IntervalVector({{-1,1},{-2,2},{-3,3}})+Vector({1,2,3}) == IntervalVector({{0,2},{0,4},{0,6}})); // inline IntervalVector operator+(const IntervalVector& x1, const IntervalVector& x2) - CHECK(IntervalVector({{-1,1},{-2,2},{-3,3}})+IntervalVector({{1},{2},{3}}) == IntervalVector({{0,2},{0,4},{0,6}})); + CHECK(IntervalVector({{-1,1},{-2,2},{-3,3}})+IntervalVector({1,2,3}) == IntervalVector({{0,2},{0,4},{0,6}})); // IntervalMatrix operator+(const IM& x1, const M& x2) CHECK(IntervalMatrix({{{-1,1},{-2,2}},{{-3,3},{-4,4}}})+Matrix({{1,2},{3,4}}) == IntervalMatrix({{{0,2},{0,4}},{{0,6},{0,8}}})); diff --git a/tests/core/matrices/codac2_tests_arithmetic_div.cpp b/tests/core/matrices/codac2_tests_arithmetic_div.cpp index cd8756ae..092531bd 100644 --- a/tests/core/matrices/codac2_tests_arithmetic_div.cpp +++ b/tests/core/matrices/codac2_tests_arithmetic_div.cpp @@ -8,6 +8,8 @@ */ #include +#include +#include #include #include #include @@ -19,30 +21,30 @@ using namespace codac2; TEST_CASE("arithmetic div") { //inline Vector operator/(const Vector& x1, double x2) - CHECK(Approx(Vector({1,2,3})/10.) == Vector({.1,.2,.3})); + CHECK(Approx(Vector({1,2,3})/10.) == Vector({.1,.2,.3})); //inline IntervalVector operator/(const Vector& x1, const Interval& x2) - CHECK(Approx(Vector({1,2,3})/Interval(10.,oo)) == IntervalVector({{0,.1},{0,.2},{0,.3}})); + CHECK(Approx(Vector({1,2,3})/Interval(10.,oo)) == IntervalVector({{0,.1},{0,.2},{0,.3}})); //Matrix operator/(const M& x1, double x2) - CHECK(Approx(Matrix({{1,2},{3,4}})/10.) == Matrix({{.1,.2},{.3,.4}})); - CHECK(Approx(Matrix({{1,2},{3,4}}).block(0,0,2,2)/10.) == Matrix({{.1,.2},{.3,.4}})); + CHECK(Approx(Matrix({{1,2},{3,4}})/10.) == Matrix({{.1,.2},{.3,.4}})); + CHECK(Approx(Matrix({{1,2},{3,4}}).block(0,0,2,2)/10.) == Matrix({{.1,.2},{.3,.4}})); //IntervalMatrix operator/(const M& x1, const Interval& x2) - CHECK(Approx(Matrix({{1,2},{3,4}})/Interval(10.,oo)) == IntervalMatrix({{{0,.1},{0,.2}},{{0,.3},{0,.4}}})); - CHECK(Approx(Matrix({{1,2},{3,4}}).block(0,0,2,2)/Interval(10.,oo)) == IntervalMatrix({{{0,.1},{0,.2}},{{0,.3},{0,.4}}})); + CHECK(Approx(Matrix({{1,2},{3,4}})/Interval(10.,oo)) == IntervalMatrix({{{0,.1},{0,.2}},{{0,.3},{0,.4}}})); + CHECK(Approx(Matrix({{1,2},{3,4}}).block(0,0,2,2)/Interval(10.,oo)) == IntervalMatrix({{{0,.1},{0,.2}},{{0,.3},{0,.4}}})); //inline IntervalVector operator/(const IntervalVector& x1, double x2) - CHECK(Approx(IntervalVector({{1},{2},{3}})/10.) == IntervalVector({{.1},{.2},{.3}})); + CHECK(Approx(IntervalVector({1,2,3})/10.) == IntervalVector({0.1,0.2,0.3})); //inline IntervalVector operator/(const IntervalVector& x1, const Interval& x2) - CHECK(Approx(IntervalVector({{1},{2},{3}})/Interval(10.,oo)) == IntervalVector({{0,.1},{0,.2},{0,.3}})); + CHECK(Approx(IntervalVector({1,2,3})/Interval(10.,oo)) == IntervalVector({{0,.1},{0,.2},{0,.3}})); //IntervalMatrix operator/(const IM& x1, double x2) - CHECK(Approx(IntervalMatrix({{{1},{2}},{{3},{4}}})/10.) == IntervalMatrix({{{.1},{.2}},{{.3},{.4}}})); - CHECK(Approx(IntervalMatrix({{{1},{2}},{{3},{4}}}).block(0,0,2,2)/10.) == IntervalMatrix({{{.1},{.2}},{{.3},{.4}}})); + CHECK(Approx(IntervalMatrix({{1,2},{3,4}})/10.) == IntervalMatrix({{.1,.2},{.3,.4}})); + CHECK(Approx(IntervalMatrix({{1,2},{3,4}}).block(0,0,2,2)/10.) == IntervalMatrix({{.1,.2},{.3,.4}})); //IntervalMatrix operator/(const IM& x1, const Interval& x2) - CHECK(Approx(IntervalMatrix({{{1},{2}},{{3},{4}}})/Interval(10.,oo)) == IntervalMatrix({{{0,.1},{0,.2}},{{0,.3},{0,.4}}})); - CHECK(Approx(IntervalMatrix({{{1},{2}},{{3},{4}}}).block(0,0,2,2)/Interval(10.,oo)) == IntervalMatrix({{{0,.1},{0,.2}},{{0,.3},{0,.4}}})); + CHECK(Approx(IntervalMatrix({{1,2},{3,4}})/Interval(10.,oo)) == IntervalMatrix({{{0,.1},{0,.2}},{{0,.3},{0,.4}}})); + CHECK(Approx(IntervalMatrix({{1,2},{3,4}}).block(0,0,2,2)/Interval(10.,oo)) == IntervalMatrix({{{0,.1},{0,.2}},{{0,.3},{0,.4}}})); } \ No newline at end of file diff --git a/tests/core/matrices/codac2_tests_arithmetic_mul.cpp b/tests/core/matrices/codac2_tests_arithmetic_mul.cpp index d75ad854..281b89ff 100644 --- a/tests/core/matrices/codac2_tests_arithmetic_mul.cpp +++ b/tests/core/matrices/codac2_tests_arithmetic_mul.cpp @@ -8,6 +8,8 @@ */ #include +#include +#include #include #include #include @@ -65,19 +67,39 @@ TEST_CASE("arithmetic mul") // Matrix operator*(const M& x1, const M_& x2) CHECK(Matrix({{1,2},{3,4}})*Matrix({{5,6},{7,8}}) == Matrix({{19,22},{43,50}})); - CHECK(Matrix({{1,2},{3,4}}).block(0,0,2,2)*Matrix({{5,6},{7,8}}) == Matrix({{19,22},{43,50}})); - CHECK(Matrix({{1,2},{3,4}})*Matrix({{5,6},{7,8}}).block(0,0,2,2) == Matrix({{19,22},{43,50}})); - CHECK(Matrix({{1,2},{3,4}}).block(0,0,2,2)*Matrix({{5,6},{7,8}}).block(0,0,2,2) == Matrix({{19,22},{43,50}})); + CHECK( + Matrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}}).block(0,0,2,2))*Matrix({{5,6},{7,8}}) == Matrix({{19,22},{43,50}})); + CHECK(Matrix({{1,2},{3,4}})* + Matrix( // <--- this explicit cast should be removed + Matrix({{5,6},{7,8}}).block(0,0,2,2)) == Matrix({{19,22},{43,50}})); + CHECK( + Matrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}}).block(0,0,2,2))* + Matrix( // <--- this explicit cast should be removed + Matrix({{5,6},{7,8}}).block(0,0,2,2)) == Matrix({{19,22},{43,50}})); // IntervalVector operator*(const M& x1, const IntervalVector& x2) CHECK(Matrix({{1,2},{3,4}})*IntervalVector({5,6}) == IntervalVector({17,39})); - CHECK(Matrix({{1,2},{3,4}}).block(0,0,2,2)*IntervalVector({5,6}) == IntervalVector({17,39})); + CHECK( + Matrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}}).block(0,0,2,2))*IntervalVector({5,6}) == IntervalVector({17,39})); // IntervalMatrix operator*(const M& x1, const IM& x2) - CHECK(Matrix({{1,2},{3,4}})*IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}) == IntervalMatrix({{{19,22},{22,25}},{{43,50},{50,57}}})); - CHECK(Matrix({{1,2},{3,4}}).block(0,0,2,2)*IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}) == IntervalMatrix({{{19,22},{22,25}},{{43,50},{50,57}}})); - CHECK(Matrix({{1,2},{3,4}})*IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2) == IntervalMatrix({{{19,22},{22,25}},{{43,50},{50,57}}})); - CHECK(Matrix({{1,2},{3,4}}).block(0,0,2,2)*IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2) == IntervalMatrix({{{19,22},{22,25}},{{43,50},{50,57}}})); + CHECK(IntervalMatrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}}))*IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}) == IntervalMatrix({{{19,22},{22,25}},{{43,50},{50,57}}})); + CHECK( + IntervalMatrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}}).block(0,0,2,2))*IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}) == IntervalMatrix({{{19,22},{22,25}},{{43,50},{50,57}}})); + CHECK(IntervalMatrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}}))* + IntervalMatrix( // <--- this explicit cast should be removed + IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2)) == IntervalMatrix({{{19,22},{22,25}},{{43,50},{50,57}}})); + CHECK( + IntervalMatrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}}).block(0,0,2,2))* + IntervalMatrix( // <--- this explicit cast should be removed + IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2)) == IntervalMatrix({{{19,22},{22,25}},{{43,50},{50,57}}})); // inline IntervalVector operator*(const IntervalVector& x1, double x2) CHECK(IntervalVector({{-1,1},{-2,2}})*2. == IntervalVector({{-2,2},{-4,4}})); @@ -94,14 +116,32 @@ TEST_CASE("arithmetic mul") CHECK(IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}).block(0,0,2,2)*Interval(-1,1) == IntervalMatrix({{{-2,2},{-3,3}},{{-4,4},{-5,5}}})); // IntervalVector operator*(const IM& x1, const Vector& x2) - CHECK(IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}})*Vector({5,6}) == IntervalVector({{17,28},{39,50}})); - CHECK(IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}).block(0,0,2,2)*Vector({5,6}) == IntervalVector({{17,28},{39,50}})); + CHECK(IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}})*Vector({5,6}) + .template cast() // <--- this explicit cast should be removed + == IntervalVector({{17,28},{39,50}})); + CHECK( + IntervalMatrix( // <--- this explicit cast should be removed + IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}).block(0,0,2,2))*Vector({5,6}) + .template cast() // <--- this explicit cast should be removed + == IntervalVector({{17,28},{39,50}})); // IntervalMatrix operator*(const IM& x1, const M& x2) - CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}})*Matrix({{1,2},{3,4}}) == IntervalMatrix({{{23,27},{34,40}},{{31,35},{46,52}}})); - CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2)*Matrix({{1,2},{3,4}}) == IntervalMatrix({{{23,27},{34,40}},{{31,35},{46,52}}})); - CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}})*Matrix({{1,2},{3,4}}).block(0,0,2,2) == IntervalMatrix({{{23,27},{34,40}},{{31,35},{46,52}}})); - CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2)*Matrix({{1,2},{3,4}}).block(0,0,2,2) == IntervalMatrix({{{23,27},{34,40}},{{31,35},{46,52}}})); + CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}})* + IntervalMatrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}})) == IntervalMatrix({{{23,27},{34,40}},{{31,35},{46,52}}})); + CHECK( + IntervalMatrix( // <--- this explicit cast should be removed + IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2))* + IntervalMatrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}})) == IntervalMatrix({{{23,27},{34,40}},{{31,35},{46,52}}})); + CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}})* + IntervalMatrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}}).block(0,0,2,2)) == IntervalMatrix({{{23,27},{34,40}},{{31,35},{46,52}}})); + CHECK( + IntervalMatrix( // <--- this explicit cast should be removed + IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2))* + IntervalMatrix( // <--- this explicit cast should be removed + Matrix({{1,2},{3,4}}).block(0,0,2,2)) == IntervalMatrix({{{23,27},{34,40}},{{31,35},{46,52}}})); // IntervalVector operator*(const IM& x1, const IntervalVector& x2) CHECK(IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}})*IntervalVector({{5,6},{7,8}}) == IntervalVector({{19,36},{43,64}})); @@ -109,7 +149,13 @@ TEST_CASE("arithmetic mul") // IntervalMatrix operator*(const IM& x1, const IM_& x2) CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}})*IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}) == IntervalMatrix({{{23,40},{34,53}},{{31,52},{46,69}}})); - CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2)*IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}) == IntervalMatrix({{{23,40},{34,53}},{{31,52},{46,69}}})); - CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}})*IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}).block(0,0,2,2) == IntervalMatrix({{{23,40},{34,53}},{{31,52},{46,69}}})); - CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2)*IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}).block(0,0,2,2) == IntervalMatrix({{{23,40},{34,53}},{{31,52},{46,69}}})); + CHECK( + IntervalMatrix( // <--- this explicit cast should be removed + IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}}).block(0,0,2,2))*IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}) == IntervalMatrix({{{23,40},{34,53}},{{31,52},{46,69}}})); + CHECK(IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}})* + IntervalMatrix( // <--- this explicit cast should be removed + IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}).block(0,0,2,2)) == IntervalMatrix({{{23,40},{34,53}},{{31,52},{46,69}}})); + CHECK( + IntervalMatrix( // <--- this explicit cast should be removed + IntervalMatrix({{{5,6},{6,7}},{{7,8},{8,9}}})).block(0,0,2,2)*IntervalMatrix({{{1,2},{2,3}},{{3,4},{4,5}}}).block(0,0,2,2) == IntervalMatrix({{{23,40},{34,53}},{{31,52},{46,69}}})); } \ No newline at end of file diff --git a/tests/core/matrices/codac2_tests_arithmetic_sub.cpp b/tests/core/matrices/codac2_tests_arithmetic_sub.cpp index fa4ff0bf..f40e7f93 100644 --- a/tests/core/matrices/codac2_tests_arithmetic_sub.cpp +++ b/tests/core/matrices/codac2_tests_arithmetic_sub.cpp @@ -8,6 +8,8 @@ */ #include +#include +#include #include #include #include @@ -39,7 +41,7 @@ TEST_CASE("arithmetic sub") CHECK(IntervalVector({{-1,1},{-2,2},{-3,3}})-Vector({1,2,3}) == IntervalVector({{-2,0},{-4,0},{-6,0}})); // inline IntervalVector operator-(const IntervalVector& x1, const IntervalVector& x2) - CHECK(IntervalVector({{-1,1},{-2,2},{-3,3}})-IntervalVector({{1},{2},{3}}) == IntervalVector({{-2,0},{-4,0},{-6,0}})); + CHECK(IntervalVector({{-1,1},{-2,2},{-3,3}})-IntervalVector({1,2,3}) == IntervalVector({{-2,0},{-4,0},{-6,0}})); // IntervalMatrix operator-(const IM& x1, const M& x2) CHECK(IntervalMatrix({{{-1,1},{-2,2}},{{-3,3},{-4,4}}})-Matrix({{1,2},{3,4}}) == IntervalMatrix({{{-2,0},{-4,0}},{{-6,0},{-8,0}}})); @@ -48,8 +50,8 @@ TEST_CASE("arithmetic sub") CHECK(IntervalMatrix({{{-1,1},{-2,2}},{{-3,3},{-4,4}}}).block(0,0,2,2)-Matrix({{1,2},{3,4}}).block(0,0,2,2) == IntervalMatrix({{{-2,0},{-4,0}},{{-6,0},{-8,0}}})); // IntervalMatrix operator-(const IM& x1, const IM_& x2) - CHECK(IntervalMatrix({{{-1,1},{-2,2}},{{-3,3},{-4,4}}})-IntervalMatrix({{{1},{2}},{{3},{4}}}) == IntervalMatrix({{{-2,0},{-4,0}},{{-6,0},{-8,0}}})); - CHECK(IntervalMatrix({{{-1,1},{-2,2}},{{-3,3},{-4,4}}}).block(0,0,2,2)-IntervalMatrix({{{1},{2}},{{3},{4}}}) == IntervalMatrix({{{-2,0},{-4,0}},{{-6,0},{-8,0}}})); + CHECK(IntervalMatrix({{{-1,1},{-2,2}},{{-3,3},{-4,4}}})-IntervalMatrix({{1,2},{3,4}}) == IntervalMatrix({{{-2,0},{-4,0}},{{-6,0},{-8,0}}})); + CHECK(IntervalMatrix({{{-1,1},{-2,2}},{{-3,3},{-4,4}}}).block(0,0,2,2)-IntervalMatrix({{1,2},{3,4}}) == IntervalMatrix({{{-2,0},{-4,0}},{{-6,0},{-8,0}}})); CHECK(IntervalMatrix({{{-1,1},{-2,2}},{{-3,3},{-4,4}}})-IntervalMatrix({{{1},{2}},{{3},{4}}}).block(0,0,2,2) == IntervalMatrix({{{-2,0},{-4,0}},{{-6,0},{-8,0}}})); CHECK(IntervalMatrix({{{-1,1},{-2,2}},{{-3,3},{-4,4}}}).block(0,0,2,2)-IntervalMatrix({{{1},{2}},{{3},{4}}}).block(0,0,2,2) == IntervalMatrix({{{-2,0},{-4,0}},{{-6,0},{-8,0}}})); } \ No newline at end of file diff --git a/tests/core/separators/codac2_tests_SepCtcBoundary.cpp b/tests/core/separators/codac2_tests_SepCtcBoundary.cpp index 23c71178..5244e80c 100644 --- a/tests/core/separators/codac2_tests_SepCtcBoundary.cpp +++ b/tests/core/separators/codac2_tests_SepCtcBoundary.cpp @@ -28,8 +28,8 @@ BoolInterval test_inside_diamond(const Vector& x) TEST_CASE("SepCtcBoundary") { - auto ctc_bound_diamond = CtcSegment({{-1},{0}}, {{0},{-1}}) | CtcSegment({{0},{-1}}, {{1},{0}}) - | CtcSegment({{1},{0}}, {{0},{1}}) | CtcSegment({{0},{1}}, {{-1},{0}}); + auto ctc_bound_diamond = CtcSegment({-1,0}, {0,-1}) | CtcSegment({0,-1}, {1,0}) + | CtcSegment({1,0}, {0,1}) | CtcSegment({0,1}, {-1,0}); SepCtcBoundary sep_diamond(ctc_bound_diamond,test_inside_diamond); @@ -61,5 +61,5 @@ TEST_CASE("SepCtcBoundary") //DefaultView::draw_box(xs.inner,Color::dark_green()); //DefaultView::draw_box(xs.outer,Color::blue()); CHECK(xs.inner == x); - CHECK(xs.outer == IntervalVector({{0.5},{0.5}})); + CHECK(xs.outer == IntervalVector({0.5,0.5})); } \ No newline at end of file diff --git a/tests/core/separators/codac2_tests_SepPolygon.cpp b/tests/core/separators/codac2_tests_SepPolygon.cpp index b78db3a2..24c20be4 100644 --- a/tests/core/separators/codac2_tests_SepPolygon.cpp +++ b/tests/core/separators/codac2_tests_SepPolygon.cpp @@ -35,24 +35,24 @@ TEST_CASE("SepPolygon - tests from Codac1") { SepPolygon s({ // external border - {{6,-6},{7,9}}, - {{7,9},{0,5}}, - {{0,5},{-9,8}}, - {{-9,8},{-8,-9}}, - {{-8,-9},{6,-6}}, + Edge({{6,-6},{7,9}}), + Edge({{7,9},{0,5}}), + Edge({{0,5},{-9,8}}), + Edge({{-9,8},{-8,-9}}), + Edge({{-8,-9},{6,-6}}), // hole - {{-2,3},{3.5,2}}, - {{3.5,2},{1.5,0.5}}, - {{1.5,0.5},{3,-4}}, - {{3,-4},{-3,-3}}, - {{-3,-3},{-2,3}} + Edge({{-2,3},{3.5,2}}), + Edge({{3.5,2},{1.5,0.5}}), + Edge({{1.5,0.5},{3,-4}}), + Edge({{3,-4},{-3,-3}}), + Edge({{-3,-3},{-2,3}}) }); //pave(IntervalVector({{-10,10},{-10,10}}), s, 0.1); // Check a box inside the hole { - IntervalVector x = IntervalVector({{0},{0}}).inflate(0.5); + IntervalVector x = IntervalVector({0,0}).inflate(0.5); //DefaultView::draw_box(x,Color::purple()); auto xs = s.separate(x); CHECK(xs.inner == x); @@ -61,7 +61,7 @@ TEST_CASE("SepPolygon - tests from Codac1") // Check a box inside the polygon { - IntervalVector x = IntervalVector({{5},{-5}}).inflate(0.5); + IntervalVector x = IntervalVector({5,-5}).inflate(0.5); //DefaultView::draw_box(x,Color::purple()); auto xs = s.separate(x); CHECK(xs.inner.is_empty()); @@ -70,7 +70,7 @@ TEST_CASE("SepPolygon - tests from Codac1") // Check a box outside the polygon { - IntervalVector x = IntervalVector({{-1},{8}}).inflate(0.5); + IntervalVector x = IntervalVector({-1,8}).inflate(0.5); //DefaultView::draw_box(x,Color::purple()); auto xs = s.separate(x); CHECK(xs.inner == x); @@ -83,7 +83,7 @@ TEST_CASE("SepPolygon - tests from Codac1") // Check a box inside the polygon { - IntervalVector x = IntervalVector({{5},{-5}}).inflate(0.5); + IntervalVector x = IntervalVector({5,-5}).inflate(0.5); auto xs = s.separate(x); CHECK(xs.inner.is_empty()); CHECK(xs.outer == x); @@ -91,7 +91,7 @@ TEST_CASE("SepPolygon - tests from Codac1") // Check a box outside the polygon { - IntervalVector x = IntervalVector({{-1},{8}}).inflate(0.5); + IntervalVector x = IntervalVector({-1,8}).inflate(0.5); auto xs = s.separate(x); CHECK(xs.inner == x); CHECK(xs.outer.is_empty()); diff --git a/tests/core/tools/codac2_tests_Approx.cpp b/tests/core/tools/codac2_tests_Approx.cpp index 16d8ceed..bfdfb6e8 100644 --- a/tests/core/tools/codac2_tests_Approx.cpp +++ b/tests/core/tools/codac2_tests_Approx.cpp @@ -21,8 +21,7 @@ TEST_CASE("Approx") CHECK(Interval(0.1) != Interval(1.)/Interval(10.)); CHECK(Approx(Interval(0.1)) == Interval(1.)/Interval(10.)); CHECK(Interval(0.1) == Approx(Interval(1.)/Interval(10.))); - - CHECK(IntervalVector({{0.1}}) != IntervalVector({{1.}})/Interval(10.)); - CHECK(Approx(IntervalVector({{0.1}})) == IntervalVector({{1.}})/Interval(10.)); - CHECK(IntervalVector({{0.1}}) == Approx(IntervalVector({{1.}})/Interval(10.))); + CHECK(IntervalVector({0.1}) != IntervalVector({1.})/Interval(10.)); + CHECK(Approx(IntervalVector({0.1})) == IntervalVector({1.})/Interval(10.)); + CHECK(IntervalVector({0.1}) == Approx(IntervalVector({1.})/Interval(10.))); } \ No newline at end of file From 67640a33f8e01fdde23ffd90c97677434f2bb1c0 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 21 Nov 2024 13:41:48 +0100 Subject: [PATCH 042/102] [core] revised matrix types: python binding --- doc/api/Doxyfile.in | 2 +- examples/02_centered_form/main.py | 2 +- examples/02_centered_form/main_evans.cpp | 2 +- examples/02_centered_form/main_parabolas.cpp | 12 +- examples/02_centered_form/main_parabolas.py | 2 +- python/src/core/CMakeLists.txt | 2 +- python/src/core/actions/codac2_py_OctaSym.cpp | 2 +- python/src/core/codac2_py_core.cpp | 26 ++- .../interval/codac2_py_IntervalMatrix.cpp | 61 +++--- .../interval/codac2_py_IntervalMatrixBase.h | 102 ++++----- .../interval/codac2_py_IntervalVector.cpp | 59 +++--- python/src/core/matrices/codac2_py_Matrix.cpp | 46 ++-- .../src/core/matrices/codac2_py_MatrixBase.h | 84 +++++--- .../core/matrices/codac2_py_MatrixBaseBlock.h | 61 ------ .../src/core/matrices/codac2_py_MatrixBlock.h | 56 +++++ python/src/core/matrices/codac2_py_Vector.cpp | 41 ++-- .../src/core/matrices/codac2_py_VectorBase.h | 34 +-- .../matrices/codac2_py_arithmetic_add.cpp | 65 +++--- .../matrices/codac2_py_arithmetic_div.cpp | 33 +-- .../matrices/codac2_py_arithmetic_mul.cpp | 113 +++++----- .../matrices/codac2_py_arithmetic_sub.cpp | 65 +++--- python/src/core/tools/codac2_py_Approx.cpp | 3 + scripts/pybind/doxygen2docstring.py | 30 +-- src/core/CMakeLists.txt | 5 - src/core/contractors/codac2_CtcSegment.cpp | 1 - src/core/contractors/codac2_directed_ctc.h | 1 - src/core/contractors/codac2_linear_ctc.h | 1 - .../codac2_IntervalMatrixBase_eigenaddons.h | 17 +- src/core/matrices/codac2_arithmetic.h | 15 -- src/core/matrices/codac2_arithmetic_add.h | 82 -------- src/core/matrices/codac2_arithmetic_div.h | 74 ------- src/core/matrices/codac2_arithmetic_mul.h | 196 ------------------ src/core/matrices/codac2_arithmetic_sub.h | 79 ------- src/core/matrices/codac2_matrices.h | 36 +++- .../matrices/eigen/codac2_Base_eigenaddons.h | 38 +--- src/core/separators/codac2_SepEllipse.cpp | 1 - .../contractors/codac2_tests_CtcFixpoint.cpp | 1 - .../core/contractors/codac2_tests_CtcLazy.cpp | 1 - .../interval/codac2_tests_IntervalMatrix.cpp | 1 - .../interval/codac2_tests_IntervalVector.cpp | 2 +- .../interval/codac2_tests_IntervalVector.py | 12 +- .../analytic/codac2_tests_AnalyticFunction.py | 2 +- tests/core/matrices/codac2_tests_Matrix.cpp | 1 - tests/core/matrices/codac2_tests_Vector.cpp | 1 - .../matrices/codac2_tests_arithmetic_add.cpp | 1 - .../matrices/codac2_tests_arithmetic_div.cpp | 1 - .../matrices/codac2_tests_arithmetic_mul.cpp | 1 - .../matrices/codac2_tests_arithmetic_sub.cpp | 1 - tests/core/tools/codac2_tests_Approx.cpp | 1 - 49 files changed, 528 insertions(+), 947 deletions(-) delete mode 100644 python/src/core/matrices/codac2_py_MatrixBaseBlock.h create mode 100644 python/src/core/matrices/codac2_py_MatrixBlock.h delete mode 100644 src/core/matrices/codac2_arithmetic.h delete mode 100644 src/core/matrices/codac2_arithmetic_add.h delete mode 100644 src/core/matrices/codac2_arithmetic_div.h delete mode 100644 src/core/matrices/codac2_arithmetic_mul.h delete mode 100644 src/core/matrices/codac2_arithmetic_sub.h diff --git a/doc/api/Doxyfile.in b/doc/api/Doxyfile.in index 31a0e71c..98532a04 100644 --- a/doc/api/Doxyfile.in +++ b/doc/api/Doxyfile.in @@ -1005,7 +1005,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = ../src/core/graphics/vibes/ +EXCLUDE = ../src/graphics/3rd/vibes/ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/examples/02_centered_form/main.py b/examples/02_centered_form/main.py index 34859894..374f861d 100644 --- a/examples/02_centered_form/main.py +++ b/examples/02_centered_form/main.py @@ -9,5 +9,5 @@ 2*x[2]*cos(x[2]*x[0])-sin(x[2]*x[1]) )) -ctc = CtcInverse(f, [[0],[0]]) +ctc = CtcInverse(f, [0,0]) graphics.draw_while_paving([[0,2],[2,4],[0,10]], ctc, 0.004) \ No newline at end of file diff --git a/examples/02_centered_form/main_evans.cpp b/examples/02_centered_form/main_evans.cpp index 1657579e..1e7351b9 100644 --- a/examples/02_centered_form/main_evans.cpp +++ b/examples/02_centered_form/main_evans.cpp @@ -11,7 +11,7 @@ int main() 2*x[0]*x[1]+2*exp(-x[0]*x[2])*(x[1]*cos(x[1]*x[2])-x[0]*sin(x[1]*x[2]))-exp(-x[0]*x[3])*sin(x[1]*x[3]) )); - CtcInverse_ ctc(f, {{0.},{0.}}); + CtcInverse_ ctc(f, {0.,0.}); IntervalVector x0({{-10,10},{0,20},{1,1},{2,2}}); shared_ptr g = make_shared("Evans", GraphicOutput::VIBES); diff --git a/examples/02_centered_form/main_parabolas.cpp b/examples/02_centered_form/main_parabolas.cpp index 75ac425a..6902f389 100644 --- a/examples/02_centered_form/main_parabolas.cpp +++ b/examples/02_centered_form/main_parabolas.cpp @@ -22,12 +22,13 @@ int main() ); AnalyticFunction h({a}, fa(a[0],a[1])-fb(a[2],a[3])); - CtcInverse_ ctc(h, {{0.},{0.},{0.}}); + CtcInverse_ ctc(h, {0.,0.,0.}); - // to be restored... - /*IntervalVector x0({{0,1},{0,1},{0,1},{0,1}}); - Paver p(x0); + IntervalVector x0({{0,1},{0,1},{0,1},{0,1}}); + draw_while_paving(x0, ctc, 0.001); + /* + // to be restored... Figure2D g("(u1,v1)", GraphicOutput::VIBES); g.set_axes(axis(0,x0[0]), axis(1,x0[1])); g.set_window_properties({100,100},{600,600}); @@ -42,5 +43,6 @@ int main() l_34.push_back(fb.eval_centered(li[2],li[3])); } export_to_ObjectFileFormat(l_12, "output_u1v1.off"); - export_to_ObjectFileFormat(l_34, "output_u2v2.off");*/ + export_to_ObjectFileFormat(l_34, "output_u2v2.off"); + */ } \ No newline at end of file diff --git a/examples/02_centered_form/main_parabolas.py b/examples/02_centered_form/main_parabolas.py index 8ffed1b7..d2a62388 100644 --- a/examples/02_centered_form/main_parabolas.py +++ b/examples/02_centered_form/main_parabolas.py @@ -18,5 +18,5 @@ IntervalVector([[2],[0],[0.55]]),IntervalVector([[2],[1],[-0.45]]),IntervalVector([[2],[2],[0.55]])) ) -ctc = CtcInverse(h, [[0],[0],[0]]) +ctc = CtcInverse(h, [0,0,0]) draw_while_paving([[0,1],[0,1],[0,1],[0,1]], ctc, 0.001) \ No newline at end of file diff --git a/python/src/core/CMakeLists.txt b/python/src/core/CMakeLists.txt index d114d4ea..e97e6646 100644 --- a/python/src/core/CMakeLists.txt +++ b/python/src/core/CMakeLists.txt @@ -57,7 +57,7 @@ matrices/codac2_py_arithmetic_div.cpp matrices/codac2_py_Matrix.cpp matrices/codac2_py_MatrixBase.h - matrices/codac2_py_MatrixBaseBlock.h + matrices/codac2_py_MatrixBlock.h matrices/codac2_py_Vector.cpp matrices/codac2_py_VectorBase.h diff --git a/python/src/core/actions/codac2_py_OctaSym.cpp b/python/src/core/actions/codac2_py_OctaSym.cpp index 558b48f3..152ea90c 100644 --- a/python/src/core/actions/codac2_py_OctaSym.cpp +++ b/python/src/core/actions/codac2_py_OctaSym.cpp @@ -57,7 +57,7 @@ void export_OctaSym(py::module& m) .def(py::self != py::self) .def("__call__", [](const OctaSym& a, const IntervalVector& x) { return a(x); }, - INTERVALVECTOR_OCTASYM_OPERATORCALL_CONST_INTERVALVECTOR_REF_CONST, + MAT_TMINUSONE1_OCTASYM_OPERATORCALL_CONST_MAT_TMINUSONE1_REF_CONST, "x"_a) .def("__call__", [](const OctaSym& a, const pyCtcIntervalVector& c) { return CtcAction(c.copy(),a); }, diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index a3f3c681..824dd56a 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -12,11 +12,13 @@ #include #include #include +#include +#include #include "codac2_py_AnalyticFunction.h" #include "codac2_py_CtcInverse.h" #include "codac2_py_CtcInverseNotIn.h" #include "codac2_py_SepInverse.h" -#include "codac2_py_MatrixBaseBlock.h" +#include "codac2_py_MatrixBlock.h" using namespace codac2; namespace py = pybind11; @@ -52,6 +54,7 @@ void export_linear_ctc(py::module& m); void export_BoolInterval(py::module& m); py::class_ export_Interval(py::module& m); void export_Interval_operations(py::module& m, py::class_& py_Interval); +py::class_ export_IntervalRow(py::module& m); py::class_ export_IntervalVector(py::module& m); py::class_ export_IntervalMatrix(py::module& m); void export_Paving(py::module& m); @@ -73,19 +76,20 @@ void export_Polygon(py::module& m); void export_arithmetic_add(py::module& m, py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, - py::class_>& py_B, py::class_>& py_IB); + py::class_>& py_B, py::class_>& py_IB); void export_arithmetic_sub(py::module& m, py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, - py::class_>& py_B, py::class_>& py_IB); + py::class_>& py_B, py::class_>& py_IB); void export_arithmetic_mul(py::module& m, py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, - py::class_>& py_B, py::class_>& py_IB); + py::class_>& py_B, py::class_>& py_IB); void export_arithmetic_div(py::module& m, py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, - py::class_>& py_B, py::class_>& py_IB); + py::class_>& py_B, py::class_>& py_IB); +py::class_ export_Row(py::module& m); py::class_ export_Vector(py::module& m); py::class_ export_Matrix(py::module& m); @@ -147,17 +151,23 @@ PYBIND11_MODULE(_core, m) export_linear_ctc(m); // matrices - auto py_M = export_Matrix(m); + py::class_ exported_row_class(m, "Row", DOC_TO_BE_DEFINED); auto py_V = export_Vector(m); - auto py_B = export_MatrixBaseBlock(m, "MatrixBaseBlock_Matrix_double"); + auto py_M = export_Matrix(m); + auto py_B = export_EigenBlock(m, "MatrixBlock"); + export_EigenBlock(m, "RowBlock"); + export_EigenBlock(m, "VectorBlock"); // domains export_BoolInterval(m); auto py_Interval = export_Interval(m); export_Interval_operations(m, py_Interval); + py::class_ exported_intervalrow_class(m, "IntervalRow", DOC_TO_BE_DEFINED); auto py_IV = export_IntervalVector(m); auto py_IM = export_IntervalMatrix(m); - auto py_IB = export_MatrixBaseBlock(m, "MatrixBaseBlock_IntervalMatrix_Interval"); + auto py_IB = export_EigenBlock(m, "IntervalMatrixBlock"); + export_EigenBlock(m, "IntervalRowBlock"); + export_EigenBlock(m, "IntervalVectorBlock"); export_arithmetic_add(m, py_V, py_IV, py_M, py_IM, py_B, py_IB); export_arithmetic_sub(m, py_V, py_IV, py_M, py_IM, py_B, py_IB); diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp index bf337d78..61057546 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp @@ -12,11 +12,18 @@ #include #include #include +#include +#include +#include #include -#include "codac2_py_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_doc.h" +#include "codac2_py_MatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_IntervalMatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Base_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_eigenaddons_test_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_IntervalMatrixBase.h" @@ -27,7 +34,7 @@ using namespace pybind11::literals; py::class_ export_IntervalMatrix(py::module& m) { - py::class_ exported_intervalmatrix_class(m, "IntervalMatrix", INTERVALMATRIX_MAIN); + py::class_ exported_intervalmatrix_class(m, "IntervalMatrix", DOC_TO_BE_DEFINED); export_IntervalMatrixBase(m, exported_intervalmatrix_class); exported_intervalmatrix_class @@ -38,7 +45,7 @@ py::class_ export_IntervalMatrix(py::module& m) matlab::test_integer(r,c); return std::make_unique(r,c); }), - INTERVALMATRIX_INTERVALMATRIX_SIZET_SIZET, + DOC_TO_BE_DEFINED, "r"_a, "c"_a) .def(py::init( @@ -47,59 +54,65 @@ py::class_ export_IntervalMatrix(py::module& m) matlab::test_integer(r,c); return std::make_unique(r,c,x); }), - INTERVALMATRIX_INTERVALMATRIX_SIZET_SIZET_CONST_INTERVAL_REF, + MATRIXBASE_EIGENADDONS_MATRIX_INT_INT_CONST_SCALAR_REF, "r"_a, "c"_a, "x"_a) .def(py::init(), "x"_a) .def(py::init(), - INTERVALMATRIX_INTERVALMATRIX_CONST_MATRIX_REF, + INTERVALMATRIXBASE_EIGENADDONS_MATRIX_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "x"_a) .def(py::init(), - INTERVALMATRIX_INTERVALMATRIX_CONST_MATRIX_REF_CONST_MATRIX_REF, + INTERVALMATRIXBASE_EIGENADDONS_MATRIX_CONST_MATRIX_DOUBLERC_REF_CONST_MATRIX_DOUBLERC_REF, "lb"_a, "ub"_a) + .def(py::init(), + DOC_TO_BE_DEFINED, + "x"_a) + + .def(py::init(), + DOC_TO_BE_DEFINED, + "x"_a) + + .def(py::init(), + DOC_TO_BE_DEFINED, + "x"_a) + .def(py::init(), - INTERVALMATRIX_INTERVALMATRIX_CONST_INTERVALVECTOR_REF, + DOC_TO_BE_DEFINED, "x"_a) - .def(py::init&>(), - INTERVALMATRIX_INTERVALMATRIX_CONST_MATRIXBASEBLOCK_QT_REF, + .def(py::init&>(), + DOC_TO_BE_DEFINED, "x"_a) - .def(py::init&>(), - INTERVALMATRIX_INTERVALMATRIX_CONST_MATRIXBASEBLOCK_QT_REF, + .def(py::init&>(), + DOC_TO_BE_DEFINED, "x"_a) .def(py::init( // this constructor must be the last one to be declared [](const std::vector& v) { assert_release(!std::empty(v)); - auto iv = std::make_unique(v.size(),v[0].size()); + auto im = std::make_unique(v.size(),v[0].size()); for(size_t i = 0 ; i < v.size() ; i++) { - assert_release(v[i].size() == iv->nb_cols() && "IntervalVector objects of different size"); - iv->row(i) = v[i].transpose(); + assert_release(v[i].size() == im->cols() && "IntervalVector objects of different size"); + im->row(i) = v[i].transpose(); } - return iv; + return im; }), - INTERVALMATRIX_INTERVALMATRIX_INITIALIZER_LIST_INITIALIZER_LIST_INTERVAL, + DOC_TO_BE_DEFINED, "v"_a) - - .def("transpose", &IntervalMatrix::transpose, - INTERVALMATRIX_INTERVALMATRIX_TRANSPOSE_CONST) - - .def("diag_matrix", &IntervalMatrix::diag_matrix, - INTERVALMATRIX_INTERVALMATRIX_DIAG_MATRIX_CONST) .def_static("empty", [](size_t_type r, size_t_type c) { matlab::test_integer(r,c); return IntervalMatrix::empty(r,c); }, - STATIC_INTERVALMATRIX_INTERVALMATRIX_EMPTY_SIZET_SIZET, + INTERVALMATRIXBASE_EIGENADDONS_STATIC_AUTO_EMPTY_SIZET_SIZET, "r"_a, "c"_a) .def("__repr__", [](const IntervalMatrix& x) diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h index fbd9f7a9..cdd0b87d 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h @@ -29,117 +29,117 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) pyclass .def("volume", &S::volume, - DOUBLE_INTERVALMATRIXBASE_SVROWSCOLS_VOLUME_CONST) + INTERVALMATRIXBASE_EIGENADDONS_DOUBLE_VOLUME_CONST) .def("is_empty", &S::is_empty, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_EMPTY_CONST) + EIGENADDONS_TEST_BOOL_IS_EMPTY_CONST) .def("set_empty", &S::set_empty, - VOID_INTERVALMATRIXBASE_SVROWSCOLS_SET_EMPTY) + INTERVALMATRIXBASE_EIGENADDONS_VOID_SET_EMPTY) - .def("lb", &S::lb, - V_INTERVALMATRIXBASE_SVROWSCOLS_LB_CONST) + .def("lb", [](const S& x) { return x.lb(); }, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_LB_CONST) - .def("ub", &S::ub, - V_INTERVALMATRIXBASE_SVROWSCOLS_UB_CONST) + .def("ub", [](const S& x) { return x.ub(); }, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_UB_CONST) - .def("mid", &S::mid, - V_INTERVALMATRIXBASE_SVROWSCOLS_MID_CONST) + .def("mid", [](const S& x) { return x.mid(); }, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_MID_CONST) - .def("mig", &S::mig, - V_INTERVALMATRIXBASE_SVROWSCOLS_MIG_CONST) + .def("mag", [](const S& x) { return x.mag(); }, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_MAG_CONST) - .def("mag", &S::mag, - V_INTERVALMATRIXBASE_SVROWSCOLS_MAG_CONST) + .def("mig", [](const S& x) { return x.mig(); }, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_MIG_CONST) - .def("rand", &S::rand, - V_INTERVALMATRIXBASE_SVROWSCOLS_RAND_CONST) + .def("rand", [](const S& x) { return x.rand(); }, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_RAND_CONST) - .def("rad", &S::rad, - V_INTERVALMATRIXBASE_SVROWSCOLS_RAD_CONST) + .def("rad", [](const S& x) { return x.rad(); }, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_RAD_CONST) - .def("diam", &S::diam, - V_INTERVALMATRIXBASE_SVROWSCOLS_DIAM_CONST) + .def("diam", [](const S& x) { return x.diam(); }, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_DIAM_CONST) - .def("min_diam", &S::min_diam, - DOUBLE_INTERVALMATRIXBASE_SVROWSCOLS_MIN_DIAM_CONST) + .def("min_diam", [](const S& x) { return x.min_diam(); }, + INTERVALMATRIXBASE_EIGENADDONS_DOUBLE_MIN_DIAM_CONST) - .def("max_diam", &S::max_diam, - DOUBLE_INTERVALMATRIXBASE_SVROWSCOLS_MAX_DIAM_CONST) + .def("max_diam", [](const S& x) { return x.max_diam(); }, + INTERVALMATRIXBASE_EIGENADDONS_DOUBLE_MAX_DIAM_CONST) .def("min_diam_index", [](const S& x) { return matlab::output_index(x.min_diam_index()); }, - SIZET_INTERVALMATRIXBASE_SVROWSCOLS_MIN_DIAM_INDEX_CONST) + INTERVALMATRIXBASE_EIGENADDONS_SIZET_MIN_DIAM_INDEX_CONST) .def("max_diam_index", [](const S& x) { return matlab::output_index(x.max_diam_index()); }, - SIZET_INTERVALMATRIXBASE_SVROWSCOLS_MAX_DIAM_INDEX_CONST) + INTERVALMATRIXBASE_EIGENADDONS_SIZET_MAX_DIAM_INDEX_CONST) .def("extr_diam_index", [](const S& x, bool min) { return matlab::output_index(x.extr_diam_index(min)); }, - SIZET_INTERVALMATRIXBASE_SVROWSCOLS_EXTR_DIAM_INDEX_BOOL_CONST, + INTERVALMATRIXBASE_EIGENADDONS_SIZET_EXTR_DIAM_INDEX_BOOL_CONST, "min"_a) .def("__contains__", &S::contains, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_CONTAINS_CONST_V_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_CONTAINS_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("contains", &S::contains, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_CONTAINS_CONST_V_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_CONTAINS_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("interior_contains", &S::interior_contains, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_INTERIOR_CONTAINS_CONST_V_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_INTERIOR_CONTAINS_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("is_unbounded", &S::is_unbounded, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_UNBOUNDED_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_UNBOUNDED_CONST) .def("is_degenerated", &S::is_degenerated, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_DEGENERATED_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_DEGENERATED_CONST) .def("is_flat", &S::is_flat, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_FLAT_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_FLAT_CONST) .def("intersects", &S::intersects, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_INTERSECTS_CONST_S_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_INTERSECTS_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("is_disjoint", &S::is_disjoint, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_DISJOINT_CONST_S_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_DISJOINT_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("overlaps", &S::overlaps, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_OVERLAPS_CONST_S_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_OVERLAPS_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("is_subset", &S::is_subset, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_SUBSET_CONST_S_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_SUBSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("is_strict_subset", &S::is_strict_subset, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_STRICT_SUBSET_CONST_S_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_STRICT_SUBSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("is_interior_subset", &S::is_interior_subset, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_INTERIOR_SUBSET_CONST_S_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_INTERIOR_SUBSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("is_strict_interior_subset", &S::is_strict_interior_subset, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_STRICT_INTERIOR_SUBSET_CONST_S_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_STRICT_INTERIOR_SUBSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("is_superset", &S::is_superset, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_SUPERSET_CONST_S_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_SUPERSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("is_strict_superset", &S::is_strict_superset, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_STRICT_SUPERSET_CONST_S_REF_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_STRICT_SUPERSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) .def("is_bisectable", &S::is_bisectable, - BOOL_INTERVALMATRIXBASE_SVROWSCOLS_IS_BISECTABLE_CONST) + INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_BISECTABLE_CONST) .def("inflate", (S&(S::*)(double))&S::inflate, - S_REF_INTERVALMATRIXBASE_SVROWSCOLS_INFLATE_DOUBLE, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_REF_INFLATE_DOUBLE, "r"_a) .def("inflate", (S&(S::*)(const V&))&S::inflate, - S_REF_INTERVALMATRIXBASE_SVROWSCOLS_INFLATE_CONST_V_REF, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_REF_INFLATE_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "r"_a) .def("bisect", [](const S& x, size_t_type i, double ratio) @@ -147,27 +147,27 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(i); return x.bisect(matlab::input_index(i),ratio); }, - PAIR_SS_INTERVALMATRIXBASE_SVROWSCOLS_BISECT_SIZET_FLOAT_CONST, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_BISECT_SIZET_FLOAT_CONST, "i"_a, "ratio"_a = 0.49) - .def("bisect_largest", &S::bisect_largest, - PAIR_SS_INTERVALMATRIXBASE_SVROWSCOLS_BISECT_LARGEST_FLOAT_CONST, + .def("bisect_largest", [](const S& x, double ratio = 0.49) { return x.bisect_largest(); }, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_BISECT_LARGEST_FLOAT_CONST, "ratio"_a = 0.49) .def(py::self &= py::self, - S_REF_INTERVALMATRIXBASE_SVROWSCOLS_OPERATORANDEQ_CONST_S_REF + INTERVALMATRIXBASE_EIGENADDONS_AUTO_REF_OPERATORANDEQ_CONST_MATRIX_U_ROWSATCOMPILETIMECOLSATCOMPILETIME_REF "x"_a) .def(py::self |= py::self, - S_REF_INTERVALMATRIXBASE_SVROWSCOLS_OPERATOROREQ_CONST_S_REF + INTERVALMATRIXBASE_EIGENADDONS_AUTO_REF_OPERATOROREQ_CONST_MATRIX_U_ROWSATCOMPILETIMECOLSATCOMPILETIME_REF "x"_a) .def(py::self & py::self, - S_INTERVALMATRIXBASE_SVROWSCOLS_OPERATORAND_CONST_S_REF_CONST + INTERVALMATRIXBASE_EIGENADDONS_AUTO_OPERATORAND_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST "x"_a) .def(py::self | py::self, - S_INTERVALMATRIXBASE_SVROWSCOLS_OPERATOROR_CONST_S_REF_CONST, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_OPERATOROR_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST, "x"_a) ; diff --git a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp index c7c758dd..b45faf64 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp @@ -13,11 +13,17 @@ #include #include #include +#include -#include "codac2_py_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_doc.h" +#include "codac2_py_MatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_VectorBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_IntervalMatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_IntervalVector_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Base_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_eigenaddons_test_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_VectorBase.h" #include "codac2_py_IntervalMatrixBase.h" @@ -29,7 +35,7 @@ using namespace pybind11::literals; py::class_ export_IntervalVector(py::module& m) { - py::class_ exported_intervalvector_class(m, "IntervalVector", INTERVALVECTOR_MAIN); + py::class_ exported_intervalvector_class(m, "IntervalVector", DOC_TO_BE_DEFINED); export_IntervalMatrixBase(m, exported_intervalvector_class); export_VectorBase(m, exported_intervalvector_class); @@ -41,27 +47,27 @@ py::class_ export_IntervalVector(py::module& m) matlab::test_integer(n); return std::make_unique(n); }), - INTERVALVECTOR_INTERVALVECTOR_SIZET, + INTERVALVECTOR_EIGENADDONS_MATRIX_INT, "n"_a) .def(py::init( [](size_t_type n, const Interval& x) { matlab::test_integer(n); - return std::make_unique(n,x); + return std::make_unique((int)n,x); }), - INTERVALVECTOR_INTERVALVECTOR_SIZET_CONST_INTERVAL_REF, + VECTORBASE_EIGENADDONS_MATRIX_INT_CONST_SCALAR_REF, "n"_a, "x"_a) .def(py::init(), "x"_a) .def(py::init(), - INTERVALVECTOR_INTERVALVECTOR_CONST_VECTOR_REF, + INTERVALMATRIXBASE_EIGENADDONS_MATRIX_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "x"_a) .def(py::init(), - INTERVALVECTOR_INTERVALVECTOR_CONST_VECTOR_REF_CONST_VECTOR_REF, + INTERVALMATRIXBASE_EIGENADDONS_MATRIX_CONST_MATRIX_DOUBLERC_REF_CONST_MATRIX_DOUBLERC_REF, "lb"_a, "ub"_a) .def(py::init( // this constructor must be the last one to be declared @@ -72,32 +78,14 @@ py::class_ export_IntervalVector(py::module& m) (*iv)[i] = v[i]; return iv; }), - INTERVALVECTOR_INTERVALVECTOR_INITIALIZER_LIST_INTERVAL, + INTERVALVECTOR_EIGENADDONS_MATRIX_CONST_INITIALIZER_LIST_INTERVAL_REF, "v"_a) - .def(py::init( // this constructor must be the last one to be declared - [](const std::vector>& v) - { - auto iv = std::make_unique(v.size()); - for(size_t i = 0 ; i < v.size() ; i++) - { - if(v[i].size() == 1) - (*iv)[i] = Interval(v[i][0]); - else if(v[i].size() == 2) - (*iv)[i] = Interval(v[i][0],v[i][1]); - else - throw invalid_argument("Interval is not made of one or two values."); - } - return iv; - }), - INTERVALVECTOR_INTERVALVECTOR_INITIALIZER_LIST_INTERVAL, - "v"_a) - - .def("complementary", &IntervalVector::complementary, - LIST_INTERVALVECTOR_INTERVALVECTOR_COMPLEMENTARY_CONST) + .def("complementary", [](const IntervalVector& x) { return x.complementary(); }, + INTERVALVECTOR_EIGENADDONS_AUTO_COMPLEMENTARY_CONST) - .def("diff", &IntervalVector::diff, - LIST_INTERVALVECTOR_INTERVALVECTOR_DIFF_CONST_INTERVALVECTOR_REF_BOOL_CONST, + .def("diff", [](const IntervalVector& x, const IntervalVector& y, bool compactness = true) { return x.diff(y,compactness); }, + INTERVALVECTOR_EIGENADDONS_LIST_MATRIX_INTERVALRC_DIFF_CONST_MATRIX_INTERVALRC_REF_BOOL_CONST, "y"_a, "compactness"_a = true) .def_static("empty", [](size_t_type n) @@ -105,7 +93,7 @@ py::class_ export_IntervalVector(py::module& m) matlab::test_integer(n); return IntervalVector::empty(n); }, - STATIC_INTERVALVECTOR_INTERVALVECTOR_EMPTY_SIZET, + INTERVALVECTOR_EIGENADDONS_STATIC_AUTO_EMPTY_SIZET, "n"_a) .def("__repr__", [](const IntervalVector& x) @@ -119,6 +107,7 @@ py::class_ export_IntervalVector(py::module& m) ; py::implicitly_convertible(); + py::implicitly_convertible(); m.def("cart_prod_boxes", [](const std::list& l) { @@ -130,8 +119,8 @@ py::class_ export_IntervalVector(py::module& m) INTERVALVECTOR_CART_PROD_CONST_X_REF_VARIADIC); // The variadic version of this function is defined in __init__.py file - m.def("hull", &codac2::hull, - INTERVALVECTOR_HULL_CONST_LIST_INTERVALVECTOR_REF, + m.def("hull", [](const std::list& l) { return hull(l); }, + AUTO_HULL_CONST_LIST_EIGEN_MATRIX_SCALARROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "l"_a); return exported_intervalvector_class; diff --git a/python/src/core/matrices/codac2_py_Matrix.cpp b/python/src/core/matrices/codac2_py_Matrix.cpp index bc38b11e..bc21190b 100644 --- a/python/src/core/matrices/codac2_py_Matrix.cpp +++ b/python/src/core/matrices/codac2_py_Matrix.cpp @@ -14,9 +14,12 @@ #include #include -#include "codac2_py_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_doc.h" +#include "codac2_py_MatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Base_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_eigenaddons_test_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_MatrixBase.h" @@ -27,7 +30,7 @@ using namespace pybind11::literals; py::class_ export_Matrix(py::module& m) { - py::class_ exported_matrix_class(m, "Matrix", MATRIX_MAIN); + py::class_ exported_matrix_class(m, "Matrix", DOC_TO_BE_DEFINED); export_MatrixBase(m, exported_matrix_class); exported_matrix_class @@ -38,53 +41,46 @@ py::class_ export_Matrix(py::module& m) matlab::test_integer(r,c); return std::make_unique(r,c); }), - MATRIX_MATRIX_SIZET_SIZET, + DOC_TO_BE_DEFINED, "r"_a, "c"_a) .def(py::init( [](size_t_type r, size_t_type c, double x) { matlab::test_integer(r,c); - return std::make_unique(r,c,x); + return std::make_unique((int)r,(int)c,x); }), - MATRIX_MATRIX_SIZET_SIZET_DOUBLE, + MATRIXBASE_EIGENADDONS_MATRIX_INT_INT_CONST_SCALAR_REF, "r"_a, "c"_a, "x"_a) .def(py::init(), - MATRIX_MATRIX_CONST_MATRIXBASE_MATRIXDOUBLE_REF, + DOC_TO_BE_DEFINED, "x"_a) .def(py::init(), - MATRIX_MATRIX_CONST_VECTOR_REF, - "x"_a) - - .def(py::init&>(), - MATRIX_MATRIX_CONST_MATRIXBASEBLOCK_QDOUBLE_REF, + DOC_TO_BE_DEFINED, "x"_a) .def(py::init( // this constructor must be the last one to be declared [](const std::vector& v) { assert_release(!std::empty(v)); - auto iv = std::make_unique(v.size(),v[0].size()); + auto m = std::make_unique(v.size(),v[0].size()); for(size_t i = 0 ; i < v.size() ; i++) { - assert_release(v[i].size() == iv->nb_cols() && "Vector objects of different size"); - iv->row(i) = v[i].transpose(); + assert_release(v[i].size() == m->cols() && "Vector objects of different size"); + m->row(i) = v[i].transpose(); } - return iv; + return m; }), - MATRIX_MATRIX_INITIALIZER_LIST_INITIALIZER_LIST_DOUBLE, + DOC_TO_BE_DEFINED, "v"_a) - .def("transpose", &Matrix::transpose, - MATRIX_MATRIX_TRANSPOSE_CONST) - - .def("diag_matrix", &Matrix::diag_matrix, - MATRIX_MATRIX_DIAG_MATRIX_CONST) - - .def("inverse", &Matrix::inverse, - MATRIX_MATRIX_INVERSE_CONST) + .def("inverse", [](const Matrix& x) + { + return x.inverse().eval(); + }, + DOC_TO_BE_DEFINED) ; diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index f6d182ef..f64f2243 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include "codac2_py_matlab.h" using namespace std; @@ -33,37 +33,37 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { return x.size(); }, - SIZET_MATRIXBASE_STROWSCOLS_SIZE_CONST) + BASE_EIGENADDONS_SIZET_SIZE_CONST) .def("size", [](const S& x) { return x.size(); }, - SIZET_MATRIXBASE_STROWSCOLS_SIZE_CONST) + BASE_EIGENADDONS_SIZET_SIZE_CONST) - .def("nb_rows", [](const S& x) + .def("rows", [](const S& x) { - return x.nb_rows(); + return x.rows(); }, - SIZET_MATRIXBASE_STROWSCOLS_NB_ROWS_CONST) + BASE_EIGENADDONS_SIZET_ROWS_CONST) - .def("nb_cols", [](const S& x) + .def("cols", [](const S& x) { - return x.nb_cols(); + return x.cols(); }, - SIZET_MATRIXBASE_STROWSCOLS_NB_COLS_CONST) + BASE_EIGENADDONS_SIZET_COLS_CONST) .def("min_coeff", [](const S& x) { return x.min_coeff(); }, - T_MATRIXBASE_STROWSCOLS_MIN_COEFF_CONST) + BASE_EIGENADDONS_SCALAR_MIN_COEFF_CONST) .def("max_coeff", [](const S& x) { return x.max_coeff(); }, - T_MATRIXBASE_STROWSCOLS_MAX_COEFF_CONST) + BASE_EIGENADDONS_SCALAR_MAX_COEFF_CONST) ; @@ -75,7 +75,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { return x.is_squared(); }, - BOOL_MATRIXBASE_STROWSCOLS_IS_SQUARED_CONST) + BASE_EIGENADDONS_BOOL_IS_SQUARED_CONST) .def("__getitem__", [](const S& x, const py::tuple& ij) -> const T& { @@ -87,7 +87,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) return x(matlab::input_index(i), matlab::input_index(j)); }, py::return_value_policy::reference_internal, - CONST_T_REF_MATRIXBASE_STROWSCOLS_OPERATORCALL_SIZET_SIZET_CONST) + BASE_EIGENADDONS_CONST_SCALAR_REF_OPERATORCALL_SIZET_SIZET_CONST) .def("__setitem__", [](S& x, const py::tuple& ij, const T& a) { @@ -99,7 +99,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) x(matlab::input_index(i), matlab::input_index(j)) = a; }, - T_REF_MATRIXBASE_STROWSCOLS_OPERATORCALL_SIZET_SIZET) + BASE_EIGENADDONS_SCALAR_REF_OPERATORCALL_SIZET_SIZET) ; } @@ -110,14 +110,14 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { x.init(a); }, - VOID_MATRIXBASE_STROWSCOLS_INIT_CONST_T_REF, + BASE_EIGENADDONS_AUTO_REF_INIT_CONST_SCALAR_REF, "x"_a) .def("init", [](S& x, const S& a) { x.init(a); }, - VOID_MATRIXBASE_STROWSCOLS_INIT_CONST_S_REF, + BASE_EIGENADDONS_AUTO_REF_INIT_CONST_MATRIX_SCALARROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "x"_a) .def("__repr__", [](const S& x) @@ -126,7 +126,19 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) s << x; return string(s.str()); }, - OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_MATRIXBASE_STROWSCOLS_REF) + DOC_TO_BE_DEFINED) + + .def("transpose", [](const S& x) -> Eigen::Matrix + { + return x.transpose().eval(); + }, + DOC_TO_BE_DEFINED) + + .def("diag_matrix", [](const S& x) + { + return x.diagonal().asDiagonal(); + }, + DOC_TO_BE_DEFINED) ; if constexpr(!VECTOR_INHERITANCE) @@ -136,44 +148,50 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) pyclass - .def("block", [](S& x, size_t_type i, size_t_type j, size_t_type p, size_t_type q) -> MatrixBaseBlock + .def("block", [](S& x, size_t_type i, size_t_type j, size_t_type p, size_t_type q) -> Eigen::Block { matlab::test_integer(i,j); matlab::test_integer(p,q); return x.block(matlab::input_index(i),matlab::input_index(j),matlab::input_index(p),matlab::input_index(q)); }, py::keep_alive<0,1>(), - MATRIXBASEBLOCK_EIGENTYPE_REFT_MATRIXBASE_STROWSCOLS_BLOCK_SIZET_SIZET_SIZET_SIZET) + DOC_TO_BE_DEFINED) - .def("col", [](S& x, size_t_type i) -> MatrixBaseBlock + .def("col", [](S& x, size_t_type i) -> Eigen::Matrix { matlab::test_integer(i); - return x.col(matlab::input_index(i)); + return x.col(matlab::input_index(i)).eval(); }, - py::keep_alive<0,1>(), - MATRIXBASEBLOCK_EIGENTYPE_REFT_MATRIXBASE_STROWSCOLS_COL_SIZET) + DOC_TO_BE_DEFINED) - .def("row", [](S& x, size_t_type i) -> MatrixBaseBlock + .def("row", [](S& x, size_t_type i) -> Eigen::Matrix { matlab::test_integer(i); - return x.row(matlab::input_index(i)); + return x.row(matlab::input_index(i)).eval(); }, - py::keep_alive<0,1>(), - MATRIXBASEBLOCK_EIGENTYPE_REFT_MATRIXBASE_STROWSCOLS_ROW_SIZET) + DOC_TO_BE_DEFINED) .def("__call__", [](S& x, size_t_type i, size_t_type j) -> T& { matlab::test_integer(i,j); return x(matlab::input_index(i),matlab::input_index(j)); }, py::return_value_policy::reference_internal, - T_REF_MATRIXBASE_STROWSCOLS_OPERATORCALL_SIZET_SIZET) + BASE_EIGENADDONS_SCALAR_REF_OPERATORCALL_SIZET_SIZET) .def("resize", [](S& x, size_t_type nb_rows, size_t_type nb_cols) { matlab::test_integer(nb_rows, nb_cols); x.resize(nb_rows, nb_cols); }, - VOID_MATRIXBASE_STROWSCOLS_RESIZE_SIZET_SIZET, + DOC_TO_BE_DEFINED, + "nb_rows"_a, "nb_cols"_a) + + .def("resize_save_values", [](S& x, size_t_type nb_rows, size_t_type nb_cols) + { + matlab::test_integer(nb_rows, nb_cols); + x.resize_save_values(nb_rows, nb_cols); + }, + MATRIXBASE_EIGENADDONS_VOID_RESIZE_SAVE_VALUES_SIZET_SIZET, "nb_rows"_a, "nb_cols"_a) .def_static("zeros", [](size_t_type r, size_t_type c) @@ -181,7 +199,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::zeros(r,c); }, - STATIC_S_MATRIXBASE_STROWSCOLS_ZEROS_SIZET_SIZET, + MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ZEROS_SIZET_SIZET, "r"_a, "c"_a) .def_static("ones", [](size_t_type r, size_t_type c) @@ -189,7 +207,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::ones(r,c); }, - STATIC_S_MATRIXBASE_STROWSCOLS_ONES_SIZET_SIZET, + MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ONES_SIZET_SIZET, "r"_a, "c"_a) .def_static("eye", [](size_t_type r, size_t_type c) @@ -197,7 +215,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::ones(r,c); }, - STATIC_S_MATRIXBASE_STROWSCOLS_EYE_SIZET_SIZET, + MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_EYE_SIZET_SIZET, "r"_a, "c"_a) ; @@ -205,5 +223,5 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) //S abs(const MatrixBase& x) m.def("abs", [](const S& x) { return abs(x); }, - S_ABS_CONST_MATRIXBASE_STROWSCOLS_REF); + AUTO_ABS_CONST_EIGEN_MATRIX_SCALARROWSATCOMPILETIMECOLSATCOMPILETIME_REF); } \ No newline at end of file diff --git a/python/src/core/matrices/codac2_py_MatrixBaseBlock.h b/python/src/core/matrices/codac2_py_MatrixBaseBlock.h deleted file mode 100644 index 14d1a562..00000000 --- a/python/src/core/matrices/codac2_py_MatrixBaseBlock.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * MatrixBase binding - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#pragma once - -#include -#include -#include -#include -#include -#include "codac2_py_MatrixBaseBlock_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) - -using namespace std; -using namespace codac2; -namespace py = pybind11; -using namespace pybind11::literals; - -template -py::class_> export_MatrixBaseBlock(py::module& m, const std::string& name) -{ - py::class_> exported_mbb_class(m, name.c_str(), MATRIXBASEBLOCK_MAIN); - - exported_mbb_class - - .def("init", [](MatrixBaseBlock& x, const S& a) - { - return x = a; - }, - VOID_MATRIXBASEBLOCK_QT_INIT_CONST_S__REF, - "x"_a) - - .def("nb_rows", &MatrixBaseBlock::nb_rows, - SIZET_MATRIXBASEBLOCK_QT_NB_ROWS_CONST) - - .def("nb_cols", &MatrixBaseBlock::nb_cols, - SIZET_MATRIXBASEBLOCK_QT_NB_COLS_CONST) - - .def("eval", &MatrixBaseBlock::eval, - AUTO_MATRIXBASEBLOCK_QT_EVAL_CONST) - - .def(py::self == py::self) - .def(py::self != py::self) - - .def("__repr__", [](const MatrixBaseBlock& x) - { - std::ostringstream s; - s << x; - return string(s.str()); - }, - OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_MATRIXBASEBLOCK_QT_REF) - - ; - - return exported_mbb_class; -} \ No newline at end of file diff --git a/python/src/core/matrices/codac2_py_MatrixBlock.h b/python/src/core/matrices/codac2_py_MatrixBlock.h new file mode 100644 index 00000000..99b51a4f --- /dev/null +++ b/python/src/core/matrices/codac2_py_MatrixBlock.h @@ -0,0 +1,56 @@ +/** + * MatrixBase binding + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include +#include +#include +#include + +#include "codac2_py_doc.h" + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +template +py::class_> export_EigenBlock(py::module& m, const std::string& name) +{ + py::class_> exported_mbb_class(m, name.c_str(), DOC_TO_BE_DEFINED); + + exported_mbb_class + + .def("rows", &Eigen::Block::rows, + DOC_TO_BE_DEFINED) + + .def("cols", &Eigen::Block::cols, + DOC_TO_BE_DEFINED) + + .def("eval", &Eigen::Block::eval, + DOC_TO_BE_DEFINED) + + .def(py::self == py::self) + .def(py::self != py::self) + + .def("__repr__", [](const Eigen::Block& x) + { + std::ostringstream s; + s << x; + return string(s.str()); + }, + DOC_TO_BE_DEFINED) + + ; + + py::implicitly_convertible,S>(); + + return exported_mbb_class; +} \ No newline at end of file diff --git a/python/src/core/matrices/codac2_py_Vector.cpp b/python/src/core/matrices/codac2_py_Vector.cpp index 1eb00908..d47f1530 100644 --- a/python/src/core/matrices/codac2_py_Vector.cpp +++ b/python/src/core/matrices/codac2_py_Vector.cpp @@ -14,9 +14,14 @@ #include #include -#include "codac2_py_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_doc.h" +#include "codac2_py_MatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Vector_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_VectorBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Base_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_eigenaddons_test_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_VectorBase.h" @@ -27,7 +32,7 @@ using namespace pybind11::literals; py::class_ export_Vector(py::module& m) { - py::class_ exported_vector_class(m, "Vector", VECTOR_MAIN); + py::class_ exported_vector_class(m, "Vector", DOC_TO_BE_DEFINED); export_MatrixBase(m, exported_vector_class); export_VectorBase(m, exported_vector_class); @@ -39,36 +44,34 @@ py::class_ export_Vector(py::module& m) matlab::test_integer(n); return std::make_unique(n); }), - VECTOR_VECTOR_SIZET, + VECTOR_EIGENADDONS_MATRIX_INT, "n"_a) - .def(py::init( - [](size_t_type n, double x) - { - matlab::test_integer(n); - return std::make_unique(n,x); - }), - VECTOR_VECTOR_SIZET_DOUBLE, - "n"_a, "x"_a) - .def(py::init(), "x"_a) - .def(py::init>(), // this constructor must be the last one to be declared - VECTOR_VECTOR_CONST_VECTOR_DOUBLE_REF, - "x"_a) + .def(py::init( // this constructor must be the last one to be declared + [](const std::vector& v_) + { + auto v = std::make_unique(v_.size()); + for(size_t i = 0 ; i < v_.size() ; i++) + (*v)[i] = v_[i]; + return v; + }), + VECTOR_EIGENADDONS_MATRIX_INITIALIZER_LIST_DOUBLE, + "v"_a) .def("min_coeff_index", [](const Vector& x) { return matlab::output_index(x.min_coeff_index()); }, - SIZET_VECTOR_MIN_COEFF_INDEX_CONST) + VECTOR_EIGENADDONS_SIZET_MIN_COEFF_INDEX_CONST) .def("max_coeff_index", [](const Vector& x) { return matlab::output_index(x.max_coeff_index()); }, - SIZET_VECTOR_MAX_COEFF_INDEX_CONST) + VECTOR_EIGENADDONS_SIZET_MAX_COEFF_INDEX_CONST) .def("__repr__", [](const Vector& x) { @@ -76,7 +79,7 @@ py::class_ export_Vector(py::module& m) s << x; return string(s.str()); }, - OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_VECTOR_REF) + DOC_TO_BE_DEFINED) ; diff --git a/python/src/core/matrices/codac2_py_VectorBase.h b/python/src/core/matrices/codac2_py_VectorBase.h index 62a1a57b..92972d70 100644 --- a/python/src/core/matrices/codac2_py_VectorBase.h +++ b/python/src/core/matrices/codac2_py_VectorBase.h @@ -36,21 +36,21 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(index); return x[matlab::input_index(index)]; }, py::return_value_policy::reference_internal, - CONST_T_REF_VECTORBASE_SMT_OPERATORCOMPO_SIZET_CONST) + VECTORBASE_EIGENADDONS_CONST_SCALAR_REF_OPERATORCOMPO_SIZET_CONST) .def("__setitem__", [](S& x, size_t_type index, const T& a) { matlab::test_integer(index); x[matlab::input_index(index)] = a; }, - T_REF_VECTORBASE_SMT_OPERATORCOMPO_SIZET) + VECTORBASE_EIGENADDONS_SCALAR_REF_OPERATORCOMPO_SIZET) - .def("subvector", [](const S& x, size_t_type start_id, size_t_type end_id) + .def("subvector", [](const S& x, size_t_type start_id, size_t_type end_id) -> S { matlab::test_integer(start_id, end_id); return x.subvector(matlab::input_index(start_id), matlab::input_index(end_id)); }, - S_VECTORBASE_SMT_SUBVECTOR_SIZET_SIZET_CONST, + VECTORBASE_EIGENADDONS_AUTO_SUBVECTOR_SIZET_SIZET_CONST, "start_id"_a, "end_id"_a) .def("resize", [](S& x, size_t_type n) @@ -58,7 +58,15 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(n); x.resize(n); }, - VOID_VECTORBASE_SMT_RESIZE_SIZET, + DOC_TO_BE_DEFINED, + "n"_a) + + .def("resize_save_values", [](S& x, size_t_type n) + { + matlab::test_integer(n); + x.resize_save_values(n); + }, + VECTORBASE_EIGENADDONS_VOID_RESIZE_SAVE_VALUES_SIZET, "n"_a) .def("put", [](S& x, size_t_type start_id, const S& x1) @@ -66,21 +74,15 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(start_id); x.put(matlab::input_index(start_id), x1); }, - VOID_VECTORBASE_SMT_PUT_SIZET_CONST_S_REF, + VECTORBASE_EIGENADDONS_VOID_PUT_SIZET_CONST_MATRIX_SCALARRC_REF, "start_id"_a, "x"_a) - - .def("transpose", &S::transpose, - M_VECTORBASE_SMT_TRANSPOSE_CONST) - - .def("diag_matrix", &S::diag_matrix, - M_VECTORBASE_SMT_DIAG_MATRIX_CONST) .def_static("zeros", [](size_t_type n) { matlab::test_integer(n); return S::zeros(n); }, - STATIC_S_VECTORBASE_SMT_ZEROS_SIZET, + VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ZEROS_SIZET, "n"_a) .def_static("ones", [](size_t_type n) @@ -88,7 +90,7 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(n); return S::ones(n); }, - STATIC_S_VECTORBASE_SMT_ONES_SIZET, + VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ONES_SIZET, "n"_a) .def("__repr__", [](const S& x) @@ -97,11 +99,11 @@ void export_VectorBase(py::module& m, py::class_& pyclass) s << x; return string(s.str()); }, - OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_VECTORBASE_SMT_REF) + DOC_TO_BE_DEFINED) .def("__iter__", [](const S &x) { - return py::make_iterator(x._e.begin(), x._e.end()); + return py::make_iterator(x.begin(), x.end()); }, py::keep_alive<0, 1>() /* keep object alive while iterator exists */) ; diff --git a/python/src/core/matrices/codac2_py_arithmetic_add.cpp b/python/src/core/matrices/codac2_py_arithmetic_add.cpp index 2adb8232..3395221c 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_add.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_add.cpp @@ -11,15 +11,18 @@ #include #include #include -#include +#include +#include +#include +#include using namespace std; using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -using B = MatrixBaseBlock; -using IB = MatrixBaseBlock; +using B = Eigen::Block; +using IB = Eigen::Block; void export_arithmetic_add(py::module& m, py::class_& py_V, py::class_& py_IV, @@ -28,63 +31,63 @@ void export_arithmetic_add(py::module& m, { // ====== First operand: vector - py_V.def(+py::self); + py_V.def("__add__", [](const Vector& x1) { return x1; }, py::is_operator()); //inline Vector operator+(const Vector& x1, const Vector& x2) - py_V.def("__add__", [](const Vector& x1, const Vector& x2) { return x1+x2; }, py::is_operator()); + py_V.def("__add__", [](const Vector& x1, const Vector& x2) { return Vector(x1+x2); }, py::is_operator()); //inline IntervalVector operator+(const Vector& x1, const IntervalVector& x2) - py_V.def("__add__", [](const Vector& x1, const IntervalVector& x2) { return x1+x2; }, py::is_operator()); + py_V.def("__add__", [](const Vector& x1, const IntervalVector& x2) { return IntervalVector(x1+x2); }, py::is_operator()); py_V.def("__iadd__", [](Vector& x1, const Vector& x2) { return x1+=x2; }, py::is_operator()); // ====== First operand: matrix - py_M.def(+py::self); + py_M.def("__add__", [](const Matrix& x1) { return x1; }, py::is_operator()); //Matrix operator+(const M& x1, const M_& x2) - py_M.def("__add__", [](const Matrix& x1, const Matrix& x2) { return x1+x2; }, py::is_operator()); - py_M.def("__add__", [](const Matrix& x1, const B& x2) { return x1+x2; }, py::is_operator()); - py_B.def("__add__", [](const B& x1, const Matrix& x2) { return x1+x2; }, py::is_operator()); - py_B.def("__add__", [](const B& x1, const B& x2) { return x1+x2; }, py::is_operator()); + py_M.def("__add__", [](const Matrix& x1, const Matrix& x2) { return Matrix(x1+x2); }, py::is_operator()); + py_M.def("__add__", [](const Matrix& x1, const B& x2) { return Matrix(x1+x2); }, py::is_operator()); + py_B.def("__add__", [](const B& x1, const Matrix& x2) { return Matrix(x1+x2); }, py::is_operator()); + py_B.def("__add__", [](const B& x1, const B& x2) { return Matrix(x1+x2); }, py::is_operator()); //IntervalMatrix operator+(const M& x1, const IM& x2) - py_M.def("__add__", [](const Matrix& x1, const IntervalMatrix& x2) { return x1+x2; }, py::is_operator()); - py_M.def("__add__", [](const Matrix& x1, const IB& x2) { return x1+x2; }, py::is_operator()); - py_B.def("__add__", [](const B& x1, const IntervalMatrix& x2) { return x1+x2; }, py::is_operator()); - py_B.def("__add__", [](const B& x1, const IB& x2) { return x1+x2; }, py::is_operator()); + py_M.def("__add__", [](const Matrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + py_M.def("__add__", [](const Matrix& x1, const IB& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + py_B.def("__add__", [](const B& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + py_B.def("__add__", [](const B& x1, const IB& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_V.def("__iadd__", [](Matrix& x1, const Matrix& x2) { return x1+=x2; }, py::is_operator()); - py_V.def("__iadd__", [](Matrix& x1, const B& x2) { return x1+=x2; }, py::is_operator()); + py_M.def("__iadd__", [](Matrix& x1, const Matrix& x2) { return x1+=x2; }, py::is_operator()); + py_M.def("__iadd__", [](Matrix& x1, const B& x2) { return x1+=x2; }, py::is_operator()); // ====== First operand: interval vector - py_IV.def(+py::self); + py_IV.def("__add__", [](const IntervalVector& x1) { return x1; }, py::is_operator()); //inline IntervalVector operator+(const IntervalVector& x1, const Vector& x2) - py_IV.def("__add__", [](const IntervalVector& x1, const Vector& x2) { return x1+x2; }, py::is_operator()); + py_IV.def("__add__", [](const IntervalVector& x1, const Vector& x2) { return IntervalVector(x1+x2); }, py::is_operator()); //inline IntervalVector operator+(const IntervalVector& x1, const IntervalVector& x2) - py_IV.def("__add__", [](const IntervalVector& x1, const IntervalVector& x2) { return x1+x2; }, py::is_operator()); + py_IV.def("__add__", [](const IntervalVector& x1, const IntervalVector& x2) { return IntervalVector(x1+x2); }, py::is_operator()); - py_V.def("__iadd__", [](IntervalVector& x1, const Vector& x2) { return x1+=x2; }, py::is_operator()); - py_V.def("__iadd__", [](IntervalVector& x1, const IntervalVector& x2) { return x1+=x2; }, py::is_operator()); + py_IV.def("__iadd__", [](IntervalVector& x1, const Vector& x2) { return x1+=x2; }, py::is_operator()); + py_IV.def("__iadd__", [](IntervalVector& x1, const IntervalVector& x2) { return x1+=x2; }, py::is_operator()); // ====== First operand: interval matrix - py_IM.def(+py::self); + py_IM.def("__add__", [](const IntervalMatrix& x1) { return x1; }, py::is_operator()); //IntervalMatrix operator+(const IM& x1, const M& x2) - py_IM.def("__add__", [](const IntervalMatrix& x1, const Matrix& x2) { return x1+x2; }, py::is_operator()); - py_IM.def("__add__", [](const IntervalMatrix& x1, const B& x2) { return x1+x2; }, py::is_operator()); - py_IB.def("__add__", [](const IB& x1, const Matrix& x2) { return x1+x2; }, py::is_operator()); - py_IB.def("__add__", [](const IB& x1, const B& x2) { return x1+x2; }, py::is_operator()); + py_IM.def("__add__", [](const IntervalMatrix& x1, const Matrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + py_IM.def("__add__", [](const IntervalMatrix& x1, const B& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + py_IB.def("__add__", [](const IB& x1, const Matrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + py_IB.def("__add__", [](const IB& x1, const B& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); //IntervalMatrix operator+(const IM& x1, const IM_& x2) - py_IM.def("__add__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) { return x1+x2; }, py::is_operator()); - py_IM.def("__add__", [](const IntervalMatrix& x1, const IB& x2) { return x1+x2; }, py::is_operator()); - py_IB.def("__add__", [](const IB& x1, const IntervalMatrix& x2) { return x1+x2; }, py::is_operator()); - py_IB.def("__add__", [](const IB& x1, const IB& x2) { return x1+x2; }, py::is_operator()); + py_IM.def("__add__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + py_IM.def("__add__", [](const IntervalMatrix& x1, const IB& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + py_IB.def("__add__", [](const IB& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + py_IB.def("__add__", [](const IB& x1, const IB& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); py_IM.def("__iadd__", [](IntervalMatrix& x1, const Matrix& x2) { return x1+=x2; }, py::is_operator()); py_IM.def("__iadd__", [](IntervalMatrix& x1, const B& x2) { return x1+=x2; }, py::is_operator()); diff --git a/python/src/core/matrices/codac2_py_arithmetic_div.cpp b/python/src/core/matrices/codac2_py_arithmetic_div.cpp index ee430951..e4e8b3e1 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_div.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_div.cpp @@ -11,15 +11,18 @@ #include #include #include -#include +#include +#include +#include +#include using namespace std; using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -using B = MatrixBaseBlock; -using IB = MatrixBaseBlock; +using B = Eigen::Block; +using IB = Eigen::Block; void export_arithmetic_div(py::module& m, py::class_& py_V, py::class_& py_IV, @@ -29,32 +32,32 @@ void export_arithmetic_div(py::module& m, // ====== First operand: vector //inline Vector operator/(const Vector& x1, double x2) - py_V.def("__truediv__", [](const Vector& x1, double x2) { return x1/x2; }, py::is_operator()); + py_V.def("__truediv__", [](const Vector& x1, double x2) { return Vector(x1/x2); }, py::is_operator()); //inline IntervalVector operator/(const Vector& x1, const Interval& x2) - py_V.def("__truediv__", [](const Vector& x1, const Interval& x2) { return x1/x2; }, py::is_operator()); + py_V.def("__truediv__", [](const Vector& x1, const Interval& x2) { return IntervalVector(x1/x2); }, py::is_operator()); py_V.def("__itruediv__", [](Vector& x1, double x2) { return x1/=x2; }, py::is_operator()); // ====== First operand: matrix //Matrix operator/(const M& x1, double x2) - py_M.def("__truediv__", [](const Matrix& x1, double x2) { return x1/x2; }, py::is_operator()); - py_B.def("__truediv__", [](const B& x1, double x2) { return x1/x2; }, py::is_operator()); + py_M.def("__truediv__", [](const Matrix& x1, double x2) { return Matrix(x1/x2); }, py::is_operator()); + py_B.def("__truediv__", [](const Eigen::Block& x1, double x2) { return Matrix(x1/x2); }, py::is_operator()); //IntervalMatrix operator/(const M& x1, const Interval& x2) - py_M.def("__truediv__", [](const Matrix& x1, const Interval& x2) { return x1/x2; }, py::is_operator()); - py_B.def("__truediv__", [](const B& x1, const Interval& x2) { return x1/x2; }, py::is_operator()); + py_M.def("__truediv__", [](const Matrix& x1, const Interval& x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); + py_B.def("__truediv__", [](const B& x1, const Interval& x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); py_M.def("__itruediv__", [](Matrix& x1, double x2) { return x1/=x2; }, py::is_operator()); // ====== First operand: interval vector //inline IntervalVector operator/(const IntervalVector& x1, double x2) - py_IV.def("__truediv__", [](const IntervalVector& x1, double x2) { return x1/x2; }, py::is_operator()); + py_IV.def("__truediv__", [](const IntervalVector& x1, double x2) { return IntervalVector(x1/x2); }, py::is_operator()); //inline IntervalVector operator/(const IntervalVector& x1, const Interval& x2) - py_IV.def("__truediv__", [](const IntervalVector& x1, const Interval& x2) { return x1/x2; }, py::is_operator()); + py_IV.def("__truediv__", [](const IntervalVector& x1, const Interval& x2) { return IntervalVector(x1/x2); }, py::is_operator()); py_IV.def("__itruediv__", [](IntervalVector& x1, double x2) { return x1/=x2; }, py::is_operator()); py_IV.def("__itruediv__", [](IntervalVector& x1, const Interval& x2) { return x1/=x2; }, py::is_operator()); @@ -62,12 +65,12 @@ void export_arithmetic_div(py::module& m, // ====== First operand: interval matrix //IntervalMatrix operator/(const IM& x1, double x2) - py_IM.def("__truediv__", [](const IntervalMatrix& x1, double x2) { return x1/x2; }, py::is_operator()); - py_IB.def("__truediv__", [](const IB& x1, double x2) { return x1/x2; }, py::is_operator()); + py_IM.def("__truediv__", [](const IntervalMatrix& x1, double x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); + py_IB.def("__truediv__", [](const IB& x1, double x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); //IntervalMatrix operator/(const IM& x1, const Interval& x2) - py_IM.def("__truediv__", [](const IntervalMatrix& x1, const Interval& x2) { return x1/x2; }, py::is_operator()); - py_IB.def("__truediv__", [](const IB& x1, const Interval& x2) { return x1/x2; }, py::is_operator()); + py_IM.def("__truediv__", [](const IntervalMatrix& x1, const Interval& x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); + py_IB.def("__truediv__", [](const IB& x1, const Interval& x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); py_IM.def("__itruediv__", [](IntervalMatrix& x1, double x2) { return x1/=x2; }, py::is_operator()); py_IM.def("__itruediv__", [](IntervalMatrix& x1, const Interval& x2) { return x1/=x2; }, py::is_operator()); diff --git a/python/src/core/matrices/codac2_py_arithmetic_mul.cpp b/python/src/core/matrices/codac2_py_arithmetic_mul.cpp index adfeaf1d..d5ff6f58 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_mul.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_mul.cpp @@ -11,15 +11,18 @@ #include #include #include -#include +#include +#include +#include +#include using namespace std; using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -using B = MatrixBaseBlock; -using IB = MatrixBaseBlock; +using B = Eigen::Block; +using IB = Eigen::Block; void export_arithmetic_mul(py::module& m, py::class_& py_V, py::class_& py_IV, @@ -29,86 +32,86 @@ void export_arithmetic_mul(py::module& m, // ====== First operand: double //inline Vector operator*(double x1, const Vector& x2) - py_V.def("__rmul__", [](const Vector& x2, double x1) { return x1*x2; }, py::is_operator()); + py_V.def("__rmul__", [](const Vector& x2, double x1) { return Vector(x1*x2); }, py::is_operator()); //Matrix operator*(double x1, const M& x2) - py_M.def("__rmul__", [](const Matrix& x2, double x1) { return x1*x2; }, py::is_operator()); - py_B.def("__rmul__", [](const B& x2, double x1) { return x1*x2; }, py::is_operator()); + py_M.def("__rmul__", [](const Matrix& x2, double x1) { return Matrix(x1*x2); }, py::is_operator()); + py_B.def("__rmul__", [](const B& x2, double x1) { return Matrix(x1*x2); }, py::is_operator()); //inline IntervalVector operator*(double x1, const IntervalVector& x2) - py_IV.def("__rmul__", [](const IntervalVector& x2, double x1) { return x1*x2; }, py::is_operator()); + py_IV.def("__rmul__", [](const IntervalVector& x2, double x1) { return IntervalVector(x1*x2); }, py::is_operator()); //IntervalMatrix operator*(double x1, const IM& x2) - py_IM.def("__rmul__", [](const IntervalMatrix& x2, double x1) { return x1*x2; }, py::is_operator()); - py_IB.def("__rmul__", [](const IB& x2, double x1) { return x1*x2; }, py::is_operator()); + py_IM.def("__rmul__", [](const IntervalMatrix& x2, double x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_IB.def("__rmul__", [](const IB& x2, double x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); // ====== First operand: interval //inline IntervalVector operator*(const Interval& x1, const Vector& x2) - py_V.def("__rmul__", [](const Vector& x2, const Interval& x1) { return x1*x2; }, py::is_operator()); + py_V.def("__rmul__", [](const Vector& x2, const Interval& x1) { return IntervalVector(x1*x2); }, py::is_operator()); //IntervalMatrix operator*(const Interval& x1, const M& x2) - py_M.def("__rmul__", [](const Matrix& x2, const Interval& x1) { return x1*x2; }, py::is_operator()); - py_B.def("__rmul__", [](const B& x2, const Interval& x1) { return x1*x2; }, py::is_operator()); + py_M.def("__rmul__", [](const Matrix& x2, const Interval& x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_B.def("__rmul__", [](const B& x2, const Interval& x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); //inline IntervalVector operator*(const Interval& x1, const IntervalVector& x2) - py_IV.def("__rmul__", [](const IntervalVector& x2, const Interval& x1) { return x1*x2; }, py::is_operator()); + py_IV.def("__rmul__", [](const IntervalVector& x2, const Interval& x1) { return IntervalVector(x1*x2); }, py::is_operator()); //IntervalMatrix operator*(const Interval& x1, const IM& x2) - py_IM.def("__rmul__", [](const IntervalMatrix& x2, const Interval& x1) { return x1*x2; }, py::is_operator()); - py_IB.def("__rmul__", [](const IB& x2, const Interval& x1) { return x1*x2; }, py::is_operator()); + py_IM.def("__rmul__", [](const IntervalMatrix& x2, const Interval& x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_IB.def("__rmul__", [](const IB& x2, const Interval& x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); // ====== First operand: vector //inline Vector operator*(const Vector& x1, double x2) - py_V.def("__mul__", [](const Vector& x1, double x2) { return x1*x2; }, py::is_operator()); + py_V.def("__mul__", [](const Vector& x1, double x2) { return Vector(x1*x2); }, py::is_operator()); //inline IntervalVector operator*(const Vector& x1, const Interval& x2) - py_V.def("__mul__", [](const Vector& x1, const Interval& x2) { return x1*x2; }, py::is_operator()); + py_V.def("__mul__", [](const Vector& x1, const Interval& x2) { return IntervalVector(x1*x2); }, py::is_operator()); py_V.def("__imul__", [](Vector& x1, double x2) { return x1*=x2; }, py::is_operator()); // ====== First operand: matrix //Interval operator*(const M& x1, double x2) - py_M.def("__mul__", [](const Matrix& x1, double x2) { return x1*x2; }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, double x2) { return x1*x2; }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, double x2) { return Matrix(x1*x2); }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, double x2) { return Matrix(x1*x2); }, py::is_operator()); //IntervalMatrix operator*(const M& x1, const Interval& x2) - py_M.def("__mul__", [](const Matrix& x1, const Interval& x2) { return x1*x2; }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const Interval& x2) { return x1*x2; }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const Interval& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const Interval& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); //Vector operator*(const M& x1, const Vector& x2) - py_M.def("__mul__", [](const Matrix& x1, const Vector& x2) { return x1*x2; }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const Vector& x2) { return x1*x2; }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const Vector& x2) { return Vector(x1*x2); }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const Vector& x2) { return Vector(x1*x2); }, py::is_operator()); //Matrix operator*(const M& x1, const M_& x2) - py_M.def("__mul__", [](const Matrix& x1, const Matrix& x2) { return x1*x2; }, py::is_operator()); - py_M.def("__mul__", [](const Matrix& x1, const B& x2) { return x1*x2; }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const Matrix& x2) { return x1*x2; }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const B& x2) { return x1*x2; }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const Matrix& x2) { return Matrix(x1*x2); }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const B& x2) { return Matrix(x1*x2.eval()); }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const Matrix& x2) { return Matrix(x1.eval()*x2); }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const B& x2) { return Matrix(x1.eval()*x2.eval()); }, py::is_operator()); //IntervalVector operator*(const M& x1, const IntervalVector& x2) - py_M.def("__mul__", [](const Matrix& x1, const IntervalVector& x2) { return x1*x2; }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const IntervalVector& x2) { return x1*x2; }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const IntervalVector& x2) { return IntervalVector(x1*x2); }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const IntervalVector& x2) { return IntervalVector(x1*x2); }, py::is_operator()); //IntervalMatrix operator*(const M& x1, const IM& x2) - py_M.def("__mul__", [](const Matrix& x1, const IntervalMatrix& x2) { return x1*x2; }, py::is_operator()); - py_M.def("__mul__", [](const Matrix& x1, const IB& x2) { return x1*x2; }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const IntervalMatrix& x2) { return x1*x2; }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const IB& x2) { return x1*x2; }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(IntervalMatrix(x1)*x2); }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const IB& x2) { return IntervalMatrix(IntervalMatrix(x1)*x2.eval()); }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const IntervalMatrix& x2) { return IntervalMatrix(IntervalMatrix(x1)*x2); }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const IB& x2) { return IntervalMatrix(IntervalMatrix(x1)*x2.eval()); }, py::is_operator()); py_M.def("__imul__", [](Matrix& x1, double x2) { return x1*=x2; }, py::is_operator()); py_M.def("__imul__", [](Matrix& x1, const Matrix& x2) { return x1*=x2; }, py::is_operator()); - py_M.def("__imul__", [](Matrix& x1, const B& x2) { return x1*=x2; }, py::is_operator()); + py_M.def("__imul__", [](Matrix& x1, const B& x2) { return x1*=x2.eval(); }, py::is_operator()); // ====== First operand: interval vector //inline IntervalVector operator*(const IntervalVector& x1, double x2) - py_IV.def("__mul__", [](const IntervalVector& x1, double x2) { return x1*x2; }, py::is_operator()); + py_IV.def("__mul__", [](const IntervalVector& x1, double x2) { return IntervalVector(x1*x2); }, py::is_operator()); //inline IntervalVector operator*(const IntervalVector& x1, const Interval& x2) - py_IV.def("__mul__", [](const IntervalVector& x1, const Interval& x2) { return x1*x2; }, py::is_operator()); + py_IV.def("__mul__", [](const IntervalVector& x1, const Interval& x2) { return IntervalVector(x1*x2); }, py::is_operator()); py_IV.def("__imul__", [](IntervalVector& x1, double x2) { return x1*=x2; }, py::is_operator()); py_IV.def("__imul__", [](IntervalVector& x1, const Interval& x2) { return x1*=x2; }, py::is_operator()); @@ -116,38 +119,38 @@ void export_arithmetic_mul(py::module& m, // ====== First operand: interval matrix //IntervalMatrix operator*(const IM& x1, double x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, double x2) { return x1*x2; }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, double x2) { return x1*x2; }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, double x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, double x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); //IntervalMatrix operator*(const IM& x1, const Interval& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const Interval& x2) { return x1*x2; }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const Interval& x2) { return x1*x2; }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const Interval& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const Interval& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); //IntervalVector operator*(const IM& x1, const Vector& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const Vector& x2) { return x1*x2; }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const Vector& x2) { return x1*x2; }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const Vector& x2) { return IntervalVector(x1*IntervalVector(x2)); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const Vector& x2) { return IntervalVector(x1*x2.template cast()); }, py::is_operator()); //IntervalMatrix operator*(const IM& x1, const M& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const Matrix& x2) { return x1*x2; }, py::is_operator()); - py_IM.def("__mul__", [](const IntervalMatrix& x1, const B& x2) { return x1*x2; }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const Matrix& x2) { return x1*x2; }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const B& x2) { return x1*x2; }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const Matrix& x2) { return IntervalMatrix(x1*IntervalMatrix(x2)); }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const B& x2) { return IntervalMatrix(x1*x2.template cast().eval()); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const Matrix& x2) { return IntervalMatrix(x1.eval()*IntervalMatrix(x2)); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const B& x2) { return IntervalMatrix(x1.eval()*x2.template cast().eval()); }, py::is_operator()); //IntervalVector operator*(const IM& x1, const IntervalVector& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const IntervalVector& x2) { return x1*x2; }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const IntervalVector& x2) { return x1*x2; }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const IntervalVector& x2) { return IntervalVector(x1*x2); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const IntervalVector& x2) { return IntervalVector(x1*x2); }, py::is_operator()); //IntervalMatrix operator*(const IM& x1, const IM_& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) { return x1*x2; }, py::is_operator()); - py_IM.def("__mul__", [](const IntervalMatrix& x1, const IB& x2) { return x1*x2; }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const IntervalMatrix& x2) { return x1*x2; }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const IB& x2) { return x1*x2; }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const IB& x2) { return IntervalMatrix(x1*x2.eval()); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1.eval()*x2); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const IB& x2) { return IntervalMatrix(x1.eval()*x2.eval()); }, py::is_operator()); py_IM.def("__imul__", [](IntervalMatrix& x1, double x2) { return x1*=x2; }, py::is_operator()); - py_IM.def("__imul__", [](IntervalMatrix& x1, const Matrix& x2) { return x1*=x2; }, py::is_operator()); - py_IM.def("__imul__", [](IntervalMatrix& x1, const B& x2) { return x1*=x2; }, py::is_operator()); + py_IM.def("__imul__", [](IntervalMatrix& x1, const Matrix& x2) { return x1*=IntervalMatrix(x2); }, py::is_operator()); + py_IM.def("__imul__", [](IntervalMatrix& x1, const B& x2) { return x1*=IntervalMatrix(x2); }, py::is_operator()); py_IM.def("__imul__", [](IntervalMatrix& x1, const Interval& x2) { return x1*=x2; }, py::is_operator()); py_IM.def("__imul__", [](IntervalMatrix& x1, const IntervalMatrix& x2) { return x1*=x2; }, py::is_operator()); - py_IM.def("__imul__", [](IntervalMatrix& x1, const IB& x2) { return x1*=x2; }, py::is_operator()); + py_IM.def("__imul__", [](IntervalMatrix& x1, const IB& x2) { return x1*=x2.eval(); }, py::is_operator()); } \ No newline at end of file diff --git a/python/src/core/matrices/codac2_py_arithmetic_sub.cpp b/python/src/core/matrices/codac2_py_arithmetic_sub.cpp index eaca2259..f0fb7690 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_sub.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_sub.cpp @@ -11,15 +11,18 @@ #include #include #include -#include +#include +#include +#include +#include using namespace std; using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -using B = MatrixBaseBlock; -using IB = MatrixBaseBlock; +using B = Eigen::Block; +using IB = Eigen::Block; void export_arithmetic_sub(py::module& m, py::class_& py_V, py::class_& py_IV, @@ -28,63 +31,63 @@ void export_arithmetic_sub(py::module& m, { // ====== First operand: vector - py_V.def(-py::self); + py_V.def("__neg__", [](const Vector& x1) { return Vector(-x1); }, py::is_operator()); //inline Vector operator-(const Vector& x1, const Vector& x2) - py_V.def("__sub__", [](const Vector& x1, const Vector& x2) { return x1-x2; }, py::is_operator()); + py_V.def("__sub__", [](const Vector& x1, const Vector& x2) { return Vector(x1-x2); }, py::is_operator()); //inline IntervalVector operator-(const Vector& x1, const IntervalVector& x2) - py_V.def("__sub__", [](const Vector& x1, const IntervalVector& x2) { return x1-x2; }, py::is_operator()); + py_V.def("__sub__", [](const Vector& x1, const IntervalVector& x2) { return IntervalVector(x1-x2); }, py::is_operator()); py_V.def("__isub__", [](Vector& x1, const Vector& x2) { return x1-=x2; }, py::is_operator()); // ====== First operand: matrix - py_M.def(-py::self); + py_M.def("__neg__", [](const Matrix& x1) { return Matrix(-x1); }, py::is_operator()); //Matrix operator-(const M& x1, const M_& x2) - py_M.def("__sub__", [](const Matrix& x1, const Matrix& x2) { return x1-x2; }, py::is_operator()); - py_M.def("__sub__", [](const Matrix& x1, const B& x2) { return x1-x2; }, py::is_operator()); - py_B.def("__sub__", [](const B& x1, const Matrix& x2) { return x1-x2; }, py::is_operator()); - py_B.def("__sub__", [](const B& x1, const B& x2) { return x1-x2; }, py::is_operator()); + py_M.def("__sub__", [](const Matrix& x1, const Matrix& x2) { return Matrix(x1-x2); }, py::is_operator()); + py_M.def("__sub__", [](const Matrix& x1, const B& x2) { return Matrix(x1-x2); }, py::is_operator()); + py_B.def("__sub__", [](const B& x1, const Matrix& x2) { return Matrix(x1-x2); }, py::is_operator()); + py_B.def("__sub__", [](const B& x1, const B& x2) { return Matrix(x1-x2); }, py::is_operator()); //IntervalMatrix operator-(const M& x1, const IM& x2) - py_M.def("__sub__", [](const Matrix& x1, const IntervalMatrix& x2) { return x1-x2; }, py::is_operator()); - py_M.def("__sub__", [](const Matrix& x1, const IB& x2) { return x1-x2; }, py::is_operator()); - py_B.def("__sub__", [](const B& x1, const IntervalMatrix& x2) { return x1-x2; }, py::is_operator()); - py_B.def("__sub__", [](const B& x1, const IB& x2) { return x1-x2; }, py::is_operator()); + py_M.def("__sub__", [](const Matrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_M.def("__sub__", [](const Matrix& x1, const IB& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_B.def("__sub__", [](const B& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_B.def("__sub__", [](const B& x1, const IB& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_V.def("__isub__", [](Matrix& x1, const Matrix& x2) { return x1-=x2; }, py::is_operator()); - py_V.def("__isub__", [](Matrix& x1, const B& x2) { return x1-=x2; }, py::is_operator()); + py_M.def("__isub__", [](Matrix& x1, const Matrix& x2) { return x1-=x2; }, py::is_operator()); + py_M.def("__isub__", [](Matrix& x1, const B& x2) { return x1-=x2; }, py::is_operator()); // ====== First operand: interval vector - py_IV.def(-py::self); + py_IV.def("__neg__", [](const IntervalVector& x1) { return IntervalVector(-x1); }, py::is_operator()); //inline IntervalVector operator-(const IntervalVector& x1, const Vector& x2) - py_IV.def("__sub__", [](const IntervalVector& x1, const Vector& x2) { return x1-x2; }, py::is_operator()); + py_IV.def("__sub__", [](const IntervalVector& x1, const Vector& x2) { return IntervalVector(x1-x2); }, py::is_operator()); //inline IntervalVector operator-(const IntervalVector& x1, const IntervalVector& x2) - py_IV.def("__sub__", [](const IntervalVector& x1, const IntervalVector& x2) { return x1-x2; }, py::is_operator()); + py_IV.def("__sub__", [](const IntervalVector& x1, const IntervalVector& x2) { return IntervalVector(x1-x2); }, py::is_operator()); - py_V.def("__isub__", [](IntervalVector& x1, const Vector& x2) { return x1-=x2; }, py::is_operator()); - py_V.def("__isub__", [](IntervalVector& x1, const IntervalVector& x2) { return x1-=x2; }, py::is_operator()); + py_IV.def("__isub__", [](IntervalVector& x1, const Vector& x2) { return x1-=x2; }, py::is_operator()); + py_IV.def("__isub__", [](IntervalVector& x1, const IntervalVector& x2) { return x1-=x2; }, py::is_operator()); // ====== First operand: interval matrix - py_IM.def(-py::self); + py_IM.def("__neg__", [](const IntervalMatrix& x1) { return IntervalMatrix(-x1); }, py::is_operator()); //IntervalMatrix operator-(const IM& x1, const M& x2) - py_IM.def("__sub__", [](const IntervalMatrix& x1, const Matrix& x2) { return x1-x2; }, py::is_operator()); - py_IM.def("__sub__", [](const IntervalMatrix& x1, const B& x2) { return x1-x2; }, py::is_operator()); - py_IB.def("__sub__", [](const IB& x1, const Matrix& x2) { return x1-x2; }, py::is_operator()); - py_IB.def("__sub__", [](const IB& x1, const B& x2) { return x1-x2; }, py::is_operator()); + py_IM.def("__sub__", [](const IntervalMatrix& x1, const Matrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_IM.def("__sub__", [](const IntervalMatrix& x1, const B& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_IB.def("__sub__", [](const IB& x1, const Matrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_IB.def("__sub__", [](const IB& x1, const B& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); //IntervalMatrix operator-(const IM& x1, const IM_& x2) - py_IM.def("__sub__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) { return x1-x2; }, py::is_operator()); - py_IM.def("__sub__", [](const IntervalMatrix& x1, const IB& x2) { return x1-x2; }, py::is_operator()); - py_IB.def("__sub__", [](const IB& x1, const IntervalMatrix& x2) { return x1-x2; }, py::is_operator()); - py_IB.def("__sub__", [](const IB& x1, const IB& x2) { return x1-x2; }, py::is_operator()); + py_IM.def("__sub__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_IM.def("__sub__", [](const IntervalMatrix& x1, const IB& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_IB.def("__sub__", [](const IB& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_IB.def("__sub__", [](const IB& x1, const IB& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); py_IM.def("__isub__", [](IntervalMatrix& x1, const Matrix& x2) { return x1-=x2; }, py::is_operator()); py_IM.def("__isub__", [](IntervalMatrix& x1, const B& x2) { return x1-=x2; }, py::is_operator()); diff --git a/python/src/core/tools/codac2_py_Approx.cpp b/python/src/core/tools/codac2_py_Approx.cpp index 4b14a393..c3d52c8c 100644 --- a/python/src/core/tools/codac2_py_Approx.cpp +++ b/python/src/core/tools/codac2_py_Approx.cpp @@ -12,7 +12,10 @@ #include #include #include +#include #include +#include +#include #include #include "codac2_py_Approx_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py): #include "codac2_py_doc.h" diff --git a/scripts/pybind/doxygen2docstring.py b/scripts/pybind/doxygen2docstring.py index 1c3a4dc5..de333bdc 100644 --- a/scripts/pybind/doxygen2docstring.py +++ b/scripts/pybind/doxygen2docstring.py @@ -68,9 +68,9 @@ def normalize_label(str_label): .replace("__PTR", "_PTR") \ .replace("-1", "MINUSONE") -def docstring_varname(memberdef): +def docstring_varname(memberdef, prefix=''): - txt = normalize_label(memberdef.find(".//definition").text) + txt = prefix + normalize_label(memberdef.find(".//definition").text) for param in memberdef.findall("param"): if param.find("type") != None: @@ -105,24 +105,30 @@ def get_originate_file(m): class_compound = root.find("./compounddef") if class_compound == None or (class_compound.get('kind') != None and \ - (class_compound.attrib['kind'] == "file" or class_compound.attrib['kind'] == "dir")): + class_compound.attrib['kind'] == "dir"): continue class_name = class_compound.find("./compoundname").text - with open(sys.argv[2] + "/" + get_originate_file(class_compound), 'a', encoding='utf-8') as f: + if class_compound.attrib['kind'] != "file": - print("/// Class " + class_name, file=f) - #print("const char* " - # + normalize_label(class_name + "_MAIN").upper() - # + " = R\"Docstring documentation will be available in next release.\";", file=f) - print("#define " - + normalize_label(class_name + "_MAIN").upper() - + " \"Docstring documentation will be available in next release.\"", file=f) + with open(sys.argv[2] + "/" + get_originate_file(class_compound), 'a', encoding='utf-8') as f: + + print("/// Class " + class_name, file=f) + #print("const char* " + # + normalize_label(class_name + "_MAIN").upper() + # + " = R\"Docstring documentation will be available in next release.\";", file=f) + print("#define " + + normalize_label(class_name + "_MAIN").upper() + + " \"Docstring documentation will be available in next release.\"", file=f) # Members documentation (ex: methods, functions, etc.) + prefix = "" + if class_compound.attrib['kind'] == "file": + prefix = class_name.replace(".h", "").replace("codac2_", "") + "_" + for memberdef in root.findall(".//memberdef"): with open(sys.argv[2] + "/" + get_originate_file(memberdef), 'a', encoding='utf-8') as f: @@ -152,7 +158,7 @@ def get_originate_file(m): # + " = R\"Docstring documentation will be available in next release.\";", file=f) print("#define " - + docstring_varname(memberdef) + + docstring_varname(memberdef, prefix) + " \"Docstring documentation will be available in next release.\"", file=f) print("\n", file=f) \ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 53893d82..cc43a918 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -90,11 +90,6 @@ ${CMAKE_CURRENT_SOURCE_DIR}/geometry/codac2_Polygon.cpp ${CMAKE_CURRENT_SOURCE_DIR}/geometry/codac2_Polygon.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_arithmetic.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_arithmetic_add.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_arithmetic_div.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_arithmetic_mul.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_arithmetic_sub.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_GaussJordan.cpp ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_GaussJordan.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_matrices.h diff --git a/src/core/contractors/codac2_CtcSegment.cpp b/src/core/contractors/codac2_CtcSegment.cpp index 84764630..6ec82cbd 100644 --- a/src/core/contractors/codac2_CtcSegment.cpp +++ b/src/core/contractors/codac2_CtcSegment.cpp @@ -9,7 +9,6 @@ #include "codac2_CtcSegment.h" #include "codac2_directed_ctc.h" -#include "codac2_arithmetic.h" using namespace std; using namespace codac2; diff --git a/src/core/contractors/codac2_directed_ctc.h b/src/core/contractors/codac2_directed_ctc.h index 69bdb963..1d6ec7b6 100644 --- a/src/core/contractors/codac2_directed_ctc.h +++ b/src/core/contractors/codac2_directed_ctc.h @@ -11,7 +11,6 @@ #include #include "codac2_analytic_values.h" -#include "codac2_arithmetic.h" #include "codac2_template_tools.h" namespace codac2 diff --git a/src/core/contractors/codac2_linear_ctc.h b/src/core/contractors/codac2_linear_ctc.h index 81c9f608..a402706e 100644 --- a/src/core/contractors/codac2_linear_ctc.h +++ b/src/core/contractors/codac2_linear_ctc.h @@ -11,7 +11,6 @@ #pragma once #include -#include "codac2_arithmetic.h" #include "codac2_Collection.h" #include "codac2_template_tools.h" #include "codac2_Matrix.h" diff --git a/src/core/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h b/src/core/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h index f21af3c6..9729f767 100644 --- a/src/core/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h +++ b/src/core/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h @@ -18,10 +18,10 @@ * \license GNU Lesser General Public License (LGPL) */ -template +template requires IsIntervalDomain -Matrix(const Matrix& x) - : Matrix(x.template cast()) +Matrix(const Matrix& x) + : Matrix(x.template cast()) { } template @@ -599,17 +599,6 @@ inline auto operator|(const Matrix - requires IsIntervalDomain -inline auto diam() const -{ - const Eigen::Matrix& e = *this; - Eigen::Matrix d(this->rows(),this->cols()); - for(size_t i = 0 ; i < this->size() ; i++) - *(d.data()+i) = (e.data()+i)->diam(); - return d; -} - template requires IsIntervalDomain inline static auto empty(size_t r, size_t c) diff --git a/src/core/matrices/codac2_arithmetic.h b/src/core/matrices/codac2_arithmetic.h deleted file mode 100644 index fe022cba..00000000 --- a/src/core/matrices/codac2_arithmetic.h +++ /dev/null @@ -1,15 +0,0 @@ -/** - * \file codac2_arithmetic.h - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#pragma once - -#include "codac2_arithmetic_add.h" -#include "codac2_arithmetic_sub.h" -#include "codac2_arithmetic_mul.h" -#include "codac2_arithmetic_div.h" \ No newline at end of file diff --git a/src/core/matrices/codac2_arithmetic_add.h b/src/core/matrices/codac2_arithmetic_add.h deleted file mode 100644 index 6a7c31b9..00000000 --- a/src/core/matrices/codac2_arithmetic_add.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * \file codac2_arithmetic_add.h - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#pragma once - -#include "codac2_template_tools.h" -#include "codac2_IntervalMatrix.h" -#include "codac2_IntervalVector.h" -//#include "codac2_MatrixBaseBlock.h" - -namespace codac2 -{ - // ====== First operand: vector - - /*inline Vector operator+(const Vector& x1, const Vector& x2) - { - assert_release(x1.size() == x2.size()); - return eigen(x1) + eigen(x2); - }*/ -/* - inline IntervalVector operator+(const Vector& x1, const IntervalVector& x2) - { - assert_release(x1.size() == x2.size()); - return x1.template cast() + eigen(x2); - } - - // ====== First operand: matrix - - template - requires IsMatrix && IsMatrix - Matrix operator+(const M& x1, const M_& x2) - { - assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); - return eigen(x1) + eigen(x2); - } - - template - requires IsMatrix && IsIntervalMatrix - IntervalMatrix operator+(const M& x1, const IM& x2) - { - assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); - return eigen(x1).template cast() + eigen(x2); - } - - // ====== First operand: interval vector - - inline IntervalVector operator+(const IntervalVector& x1, const Vector& x2) - { - assert_release(x1.size() == x2.size()); - return eigen(x1) + eigen(x2).template cast(); - } - - inline IntervalVector operator+(const IntervalVector& x1, const IntervalVector& x2) - { - assert_release(x1.size() == x2.size()); - return eigen(x1) + eigen(x2); - } - - // ====== First operand: interval matrix - - template - requires IsIntervalMatrix && IsMatrix - IntervalMatrix operator+(const IM& x1, const M& x2) - { - assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); - return eigen(x1) + eigen(x2).template cast(); - } - - template - requires IsIntervalMatrix && IsIntervalMatrix - IntervalMatrix operator+(const IM& x1, const IM_& x2) - { - assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); - return eigen(x1) + eigen(x2); - }*/ -} \ No newline at end of file diff --git a/src/core/matrices/codac2_arithmetic_div.h b/src/core/matrices/codac2_arithmetic_div.h deleted file mode 100644 index 5a45d56c..00000000 --- a/src/core/matrices/codac2_arithmetic_div.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * \file codac2_arithmetic_div.h - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#pragma once - -#include "codac2_template_tools.h" -#include "codac2_IntervalMatrix.h" -#include "codac2_IntervalVector.h" -//#include "codac2_MatrixBaseBlock.h" - -namespace codac2 -{ - // ====== First operand: vector -/* - inline Vector operator/(const Vector& x1, double x2) - { - return eigen(x1) / x2; - } - - inline IntervalVector operator/(const Vector& x1, const Interval& x2) - { - return eigen(x1).template cast() / x2; - } - - // ====== First operand: matrix - - template - requires IsMatrix - Matrix operator/(const M& x1, double x2) - { - return eigen(x1) / x2; - } - - template - requires IsMatrix - IntervalMatrix operator/(const M& x1, const Interval& x2) - { - return eigen(x1).template cast() / x2; - } - - // ====== First operand: interval vector - - inline IntervalVector operator/(const IntervalVector& x1, double x2) - { - return eigen(x1) / Interval(x2); - } - - inline IntervalVector operator/(const IntervalVector& x1, const Interval& x2) - { - return eigen(x1) / x2; - } - - // ====== First operand: interval matrix - - template - requires IsIntervalMatrix - IntervalMatrix operator/(const IM& x1, double x2) - { - return eigen(x1) / Interval(x2); - } - - template - requires IsIntervalMatrix - IntervalMatrix operator/(const IM& x1, const Interval& x2) - { - return eigen(x1) / x2; - }*/ -} \ No newline at end of file diff --git a/src/core/matrices/codac2_arithmetic_mul.h b/src/core/matrices/codac2_arithmetic_mul.h deleted file mode 100644 index 88b7f849..00000000 --- a/src/core/matrices/codac2_arithmetic_mul.h +++ /dev/null @@ -1,196 +0,0 @@ -/** - * \file codac2_arithmetic_mul.h - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#pragma once - -#include "codac2_template_tools.h" -#include "codac2_IntervalMatrix.h" -#include "codac2_IntervalVector.h" -//#include "codac2_MatrixBaseBlock.h" - -namespace codac2 -{ - // ====== First operand: double -/* - inline Vector operator*(double x1, const Vector& x2) - { - return x1 * eigen(x2); - } - - template - requires IsMatrix - Matrix operator*(double x1, const M& x2) - { - return x1 * eigen(x2); - } - - inline IntervalVector operator*(double x1, const IntervalVector& x2) - { - return Interval(x1) * eigen(x2); - } - - template - requires IsIntervalMatrix - IntervalMatrix operator*(double x1, const IM& x2) - { - return Interval(x1) * eigen(x2); - } - - // ====== First operand: interval - - inline IntervalVector operator*(const Interval& x1, const Vector& x2) - { - return x1 * eigen(x2).template cast(); - } - - template - requires IsMatrix - IntervalMatrix operator*(const Interval& x1, const M& x2) - { - return x1 * eigen(x2).template cast(); - } - - inline IntervalVector operator*(const Interval& x1, const IntervalVector& x2) - { - return x1 * eigen(x2); - } - - template - requires IsIntervalMatrix - IntervalMatrix operator*(const Interval& x1, const IM& x2) - { - return x1 * eigen(x2); - } - - // ====== First operand: vector - - inline Vector operator*(const Vector& x1, double x2) - { - return eigen(x1) * x2; - } - - inline IntervalVector operator*(const Vector& x1, const Interval& x2) - { - return eigen(x1).template cast() * x2; - } - - // ====== First operand: matrix - - template - requires IsMatrix - Matrix operator*(const M& x1, double x2) - { - return eigen(x1) * x2; - } - - template - requires IsMatrix - IntervalMatrix operator*(const M& x1, const Interval& x2) - { - return eigen(x1).template cast() * x2; - } - - template - requires IsMatrix - Vector operator*(const M& x1, const Vector& x2) - { - assert_release(x1.cols() == x2.size()); - return eigen(x1) * eigen(x2); - } - - template - requires IsMatrix && IsMatrix - Matrix operator*(const M& x1, const M_& x2) - { - assert_release(x1.cols() == x2.rows()); - return eigen(x1) * eigen(x2); - } - - template - requires IsMatrix - IntervalVector operator*(const M& x1, const IntervalVector& x2) - { - assert_release(x1.cols() == x2.size()); - return eigen(x1).template cast() * eigen(x2); - } - - template - requires IsMatrix && IsIntervalMatrix*/ - - /*auto operator*(const Matrix& x1, const IntervalMatrix& x2) - { - assert_release(x1.cols() == x2.rows()); - - //return Eigen::operator*(x1.template cast(), x2); - - //const Eigen::Product Eigen::MatrixBase::operator*(const Eigen::MatrixBase&) const [with OtherDerived = Eigen::Matrix; Derived = Eigen::CwiseUnaryOp, const Eigen::Matrix >] - - return x1.template cast() * x2; - }*/ -/* - // ====== First operand: interval vector - - inline IntervalVector operator*(const IntervalVector& x1, double x2) - { - return eigen(x1) * Interval(x2); - } - - inline IntervalVector operator*(const IntervalVector& x1, const Interval& x2) - { - return eigen(x1) * x2; - } - - // ====== First operand: interval matrix - - template - requires IsIntervalMatrix - IntervalMatrix operator*(const IM& x1, double x2) - { - return eigen(x1) * Interval(x2); - } - - template - requires IsIntervalMatrix - IntervalMatrix operator*(const IM& x1, const Interval& x2) - { - return eigen(x1) * x2; - } - - template - requires IsIntervalMatrix - IntervalVector operator*(const IM& x1, const Vector& x2) - { - assert_release(x1.cols() == x2.size()); - return eigen(x1) * eigen(x2).template cast(); - } - - template - requires IsIntervalMatrix && IsMatrix - IntervalMatrix operator*(const IM& x1, const M& x2) - { - assert_release(x1.cols() == x2.rows()); - return eigen(x1) * eigen(x2).template cast(); - } - - template - requires IsIntervalMatrix - IntervalVector operator*(const IM& x1, const IntervalVector& x2) - { - assert_release(x1.cols() == x2.size()); - return eigen(x1) * eigen(x2); - } - - template - requires IsIntervalMatrix && IsIntervalMatrix - IntervalMatrix operator*(const IM& x1, const IM_& x2) - { - assert_release(x1.cols() == x2.rows()); - return eigen(x1) * eigen(x2); - }*/ -} \ No newline at end of file diff --git a/src/core/matrices/codac2_arithmetic_sub.h b/src/core/matrices/codac2_arithmetic_sub.h deleted file mode 100644 index 21fefbc2..00000000 --- a/src/core/matrices/codac2_arithmetic_sub.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * \file codac2_arithmetic_sub.h - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#pragma once - -#include "codac2_template_tools.h" - -namespace codac2 -{ - // ====== First operand: vector -/* - inline Vector operator-(const Vector& x1, const Vector& x2) - { - assert_release(x1.size() == x2.size()); - return eigen(x1) - eigen(x2); - } - - inline IntervalVector operator-(const Vector& x1, const IntervalVector& x2) - { - assert_release(x1.size() == x2.size()); - return eigen(x1).template cast() - eigen(x2); - } - - // ====== First operand: matrix - - template - requires IsMatrix && IsMatrix - Matrix operator-(const M& x1, const M_& x2) - { - assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); - return eigen(x1) - eigen(x2); - } - - template - requires IsMatrix && IsIntervalMatrix - IntervalMatrix operator-(const M& x1, const IM& x2) - { - assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); - return eigen(x1).template cast() - eigen(x2); - } - - // ====== First operand: interval vector - - inline IntervalVector operator-(const IntervalVector& x1, const Vector& x2) - { - assert_release(x1.size() == x2.size()); - return eigen(x1) - eigen(x2).template cast(); - } - - inline IntervalVector operator-(const IntervalVector& x1, const IntervalVector& x2) - { - assert_release(x1.size() == x2.size()); - return eigen(x1) - eigen(x2); - } - - // ====== First operand: interval matrix - - template - requires IsIntervalMatrix && IsMatrix - IntervalMatrix operator-(const IM& x1, const M& x2) - { - assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); - return eigen(x1) - eigen(x2).template cast(); - } - - template - requires IsIntervalMatrix && IsIntervalMatrix - IntervalMatrix operator-(const IM& x1, const IM_& x2) - { - assert_release(x1.rows() == x2.rows() && x1.cols() == x2.cols()); - return eigen(x1) - eigen(x2); - }*/ -} \ No newline at end of file diff --git a/src/core/matrices/codac2_matrices.h b/src/core/matrices/codac2_matrices.h index d552d195..1ed30272 100644 --- a/src/core/matrices/codac2_matrices.h +++ b/src/core/matrices/codac2_matrices.h @@ -76,12 +76,6 @@ namespace Eigen template struct ScalarBinaryOpTraits { typedef codac2::Interval ReturnType; }; - - /*inline bool operator==(const codac2::Interval& x1, double x2) - { return x1 == codac2::Interval(x2); } // todo: keep this? - - inline bool operator==(double x2, const codac2::Interval& x1) - { return codac2::Interval(x1) == x2; } // todo: keep this?*/ } namespace codac2 @@ -96,4 +90,34 @@ namespace codac2 template using Mat = Eigen::Matrix; +} + +namespace codac2 +{ + template + inline auto abs(const Eigen::Matrix& x) + { + Eigen::Matrix a(x); + + for(size_t i = 0 ; i < x.size() ; i++) + { + if constexpr(std::is_same_v) + *(a.data()+i) = fabs(*(x.data()+i)); + else + *(a.data()+i) = abs(*(x.data()+i)); + } + + return a; + } + + template + requires Eigen::IsIntervalDomain + inline auto hull(const std::list>& l) + { + assert_release(!l.empty()); + Eigen::Matrix h(l.front()); + for(const auto& li : l) + h |= li; + return h; + } } \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_Base_eigenaddons.h b/src/core/matrices/eigen/codac2_Base_eigenaddons.h index 12698227..be070ccf 100644 --- a/src/core/matrices/eigen/codac2_Base_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_Base_eigenaddons.h @@ -13,19 +13,27 @@ * \license GNU Lesser General Public License (LGPL) */ +template + requires (R_ != RowsAtCompileTime || C_ != ColsAtCompileTime) +Matrix(const Matrix& x) + : Matrix(x.rows(),x.cols()) +{ + *this = x.template cast(); +} + inline size_t size() const { - return Eigen::PlainObjectBase>::size(); + return Base::size(); } inline size_t rows() const { - return Eigen::PlainObjectBase>::rows(); + return Base::rows(); } inline size_t cols() const { - return Eigen::PlainObjectBase>::cols(); + return Base::cols(); } template @@ -89,30 +97,6 @@ inline Scalar max_coeff() const minmax_item(max); } -inline friend auto abs(const Matrix& x) -{ - Matrix a(x); - - for(size_t i = 0 ; i < x.size() ; i++) - { - if constexpr(std::is_same_v) - *(a.data()+i) = fabs(*(x.data()+i)); - else - *(a.data()+i) = abs(*(x.data()+i)); - } - - return a; -} - -inline friend auto hull(const std::list>& l) -{ - assert_release(!l.empty()); - Matrix h(l.front()); - for(const auto& li : l) - h |= li; - return h; -} - template inline bool operator==(const Matrix& x) const { diff --git a/src/core/separators/codac2_SepEllipse.cpp b/src/core/separators/codac2_SepEllipse.cpp index b3c658d8..c77e1426 100644 --- a/src/core/separators/codac2_SepEllipse.cpp +++ b/src/core/separators/codac2_SepEllipse.cpp @@ -8,7 +8,6 @@ */ #include "codac2_SepEllipse.h" -#include "codac2_arithmetic.h" using namespace std; using namespace codac2; diff --git a/tests/core/contractors/codac2_tests_CtcFixpoint.cpp b/tests/core/contractors/codac2_tests_CtcFixpoint.cpp index d44fa825..697a4247 100644 --- a/tests/core/contractors/codac2_tests_CtcFixpoint.cpp +++ b/tests/core/contractors/codac2_tests_CtcFixpoint.cpp @@ -10,7 +10,6 @@ #include #include #include -#include using namespace std; using namespace codac2; diff --git a/tests/core/contractors/codac2_tests_CtcLazy.cpp b/tests/core/contractors/codac2_tests_CtcLazy.cpp index 7c3be9b5..9fb06ad7 100644 --- a/tests/core/contractors/codac2_tests_CtcLazy.cpp +++ b/tests/core/contractors/codac2_tests_CtcLazy.cpp @@ -10,7 +10,6 @@ #include #include #include -#include using namespace std; using namespace codac2; diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp index 2f23b0dc..f227ea11 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp @@ -17,7 +17,6 @@ #include #include #include -#include using namespace std; using namespace codac2; diff --git a/tests/core/domains/interval/codac2_tests_IntervalVector.cpp b/tests/core/domains/interval/codac2_tests_IntervalVector.cpp index 92681bfc..850522e5 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalVector.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalVector.cpp @@ -14,8 +14,8 @@ #include #include +#include #include -#include using namespace std; using namespace codac2; diff --git a/tests/core/domains/interval/codac2_tests_IntervalVector.py b/tests/core/domains/interval/codac2_tests_IntervalVector.py index 218b57d3..740d4c35 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalVector.py +++ b/tests/core/domains/interval/codac2_tests_IntervalVector.py @@ -27,10 +27,10 @@ def CHECK_diff(self, x, y, compactness, result): if not c: return not result - + for ci in c: found = False - for i in range(0,result_.nb_rows()): + for i in range(0,result_.rows()): if IntervalMatrix(ci).transpose() == IntervalMatrix(result_.row(i)): found = True break @@ -92,7 +92,7 @@ def tests_intervalvector(self): x = IntervalVector(1) x[0] = Interval(1,2) - x.resize(3) + x.resize_save_values(3) self.assertTrue(x.size() == 3) self.assertTrue(x[0] == Interval(1,2)) self.assertTrue(x[1] == Interval(-oo,oo)) @@ -100,14 +100,14 @@ def tests_intervalvector(self): x = IntervalVector(1) x[0] = Interval(1,2) - x.resize(1) + x.resize_save_values(1) self.assertTrue(x.size() == 1) self.assertTrue(x[0] == Interval(1,2)) x = IntervalVector(2) x[0] = Interval(1,2) x.set_empty() - x.resize(3) + x.resize_save_values(3) self.assertTrue(x.size() == 3) self.assertTrue(x.is_empty()) self.assertTrue(x[2] == Interval(-oo,oo)) @@ -115,7 +115,7 @@ def tests_intervalvector(self): x = IntervalVector(5) x[0] = Interval(1,2) x[1] = Interval(3,4) - x.resize(2) + x.resize_save_values(2) self.assertTrue(x.size() == 2) self.assertTrue(x[0] == Interval(1,2)) self.assertTrue(x[1] == Interval(3,4)) diff --git a/tests/core/functions/analytic/codac2_tests_AnalyticFunction.py b/tests/core/functions/analytic/codac2_tests_AnalyticFunction.py index 3ffeb800..ffefce83 100644 --- a/tests/core/functions/analytic/codac2_tests_AnalyticFunction.py +++ b/tests/core/functions/analytic/codac2_tests_AnalyticFunction.py @@ -96,7 +96,7 @@ def test_eval(f,*args): # .def("__rmul__", [](const ScalarVar& e1, const Interval& e2) self.assertTrue(test_eval(AnalyticFunction([x1], Interval(6.)*x1), 5.) == 30.) # .def("__mul__", [](const ScalarVar& e1, const VectorVar& e2) - self.assertTrue(test_eval(AnalyticFunction([v1,v2], v1[0]*v2), Vector([5.,10.]),IntervalVector(2,3.)) == Vector(2,15.)) + self.assertTrue(test_eval(AnalyticFunction([v1,v2], v1[0]*v2), Vector([5.,10.]),IntervalVector(2,3.)) == Vector([15,15])) # .def("__mul__", [](const ScalarVar& e1, const IntervalVector& e2) self.assertTrue(test_eval(AnalyticFunction([x1], x1*IntervalVector([[-2,3],[0,1]])), 5.) == IntervalVector([[-10,15],[0,5]])) # .def("__truediv__", [](const ScalarVar& e1, const ScalarVar& e2) diff --git a/tests/core/matrices/codac2_tests_Matrix.cpp b/tests/core/matrices/codac2_tests_Matrix.cpp index 8d1a9704..b4f4f65d 100644 --- a/tests/core/matrices/codac2_tests_Matrix.cpp +++ b/tests/core/matrices/codac2_tests_Matrix.cpp @@ -10,7 +10,6 @@ #include #include #include -#include using namespace std; using namespace codac2; diff --git a/tests/core/matrices/codac2_tests_Vector.cpp b/tests/core/matrices/codac2_tests_Vector.cpp index 9c8e5f21..c34abe0a 100644 --- a/tests/core/matrices/codac2_tests_Vector.cpp +++ b/tests/core/matrices/codac2_tests_Vector.cpp @@ -9,7 +9,6 @@ #include #include -#include using namespace std; using namespace codac2; diff --git a/tests/core/matrices/codac2_tests_arithmetic_add.cpp b/tests/core/matrices/codac2_tests_arithmetic_add.cpp index b9840998..d9df0c02 100644 --- a/tests/core/matrices/codac2_tests_arithmetic_add.cpp +++ b/tests/core/matrices/codac2_tests_arithmetic_add.cpp @@ -12,7 +12,6 @@ #include #include #include -#include using namespace std; using namespace codac2; diff --git a/tests/core/matrices/codac2_tests_arithmetic_div.cpp b/tests/core/matrices/codac2_tests_arithmetic_div.cpp index 092531bd..4eaf1372 100644 --- a/tests/core/matrices/codac2_tests_arithmetic_div.cpp +++ b/tests/core/matrices/codac2_tests_arithmetic_div.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include using namespace std; diff --git a/tests/core/matrices/codac2_tests_arithmetic_mul.cpp b/tests/core/matrices/codac2_tests_arithmetic_mul.cpp index 281b89ff..b2a84113 100644 --- a/tests/core/matrices/codac2_tests_arithmetic_mul.cpp +++ b/tests/core/matrices/codac2_tests_arithmetic_mul.cpp @@ -12,7 +12,6 @@ #include #include #include -#include using namespace std; using namespace codac2; diff --git a/tests/core/matrices/codac2_tests_arithmetic_sub.cpp b/tests/core/matrices/codac2_tests_arithmetic_sub.cpp index f40e7f93..7d125a1e 100644 --- a/tests/core/matrices/codac2_tests_arithmetic_sub.cpp +++ b/tests/core/matrices/codac2_tests_arithmetic_sub.cpp @@ -12,7 +12,6 @@ #include #include #include -#include using namespace std; using namespace codac2; diff --git a/tests/core/tools/codac2_tests_Approx.cpp b/tests/core/tools/codac2_tests_Approx.cpp index bfdfb6e8..d5d2d129 100644 --- a/tests/core/tools/codac2_tests_Approx.cpp +++ b/tests/core/tools/codac2_tests_Approx.cpp @@ -11,7 +11,6 @@ #include #include #include -#include using namespace std; using namespace codac2; From 1488e47aa1b4e62e8ebb8d9845a50627b37c89b4 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 21 Nov 2024 15:02:47 +0100 Subject: [PATCH 043/102] [mat] solving mul problem with mixed types --- .../src/core/matrices/codac2_py_MatrixBase.h | 8 +- .../matrices/codac2_py_arithmetic_add.cpp | 70 ++++++------ .../matrices/codac2_py_arithmetic_div.cpp | 24 ++-- .../matrices/codac2_py_arithmetic_mul.cpp | 104 +++++++++--------- .../matrices/codac2_py_arithmetic_sub.cpp | 54 ++++----- src/core/matrices/codac2_GaussJordan.cpp | 5 +- src/core/matrices/codac2_matrices.h | 3 +- .../matrices/eigen/codac2_Base_eigenaddons.h | 15 --- 8 files changed, 135 insertions(+), 148 deletions(-) diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index f64f2243..ec8b0d02 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -33,25 +33,25 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { return x.size(); }, - BASE_EIGENADDONS_SIZET_SIZE_CONST) + DOC_TO_BE_DEFINED) .def("size", [](const S& x) { return x.size(); }, - BASE_EIGENADDONS_SIZET_SIZE_CONST) + DOC_TO_BE_DEFINED) .def("rows", [](const S& x) { return x.rows(); }, - BASE_EIGENADDONS_SIZET_ROWS_CONST) + DOC_TO_BE_DEFINED) .def("cols", [](const S& x) { return x.cols(); }, - BASE_EIGENADDONS_SIZET_COLS_CONST) + DOC_TO_BE_DEFINED) .def("min_coeff", [](const S& x) { diff --git a/python/src/core/matrices/codac2_py_arithmetic_add.cpp b/python/src/core/matrices/codac2_py_arithmetic_add.cpp index 3395221c..7176336f 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_add.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_add.cpp @@ -31,66 +31,66 @@ void export_arithmetic_add(py::module& m, { // ====== First operand: vector - py_V.def("__add__", [](const Vector& x1) { return x1; }, py::is_operator()); + py_V.def("__add__", [](const Vector& x1) -> Vector { return x1; }, py::is_operator()); - //inline Vector operator+(const Vector& x1, const Vector& x2) - py_V.def("__add__", [](const Vector& x1, const Vector& x2) { return Vector(x1+x2); }, py::is_operator()); + //inline Vector operator-(const Vector& x1, const Vector& x2) + py_V.def("__add__", [](const Vector& x1, const Vector& x2) -> Vector { return x1+x2; }, py::is_operator()); - //inline IntervalVector operator+(const Vector& x1, const IntervalVector& x2) - py_V.def("__add__", [](const Vector& x1, const IntervalVector& x2) { return IntervalVector(x1+x2); }, py::is_operator()); + //inline IntervalVector operator-(const Vector& x1, const IntervalVector& x2) + py_V.def("__add__", [](const Vector& x1, const IntervalVector& x2) -> IntervalVector { return x1.template cast()+x2; }, py::is_operator()); py_V.def("__iadd__", [](Vector& x1, const Vector& x2) { return x1+=x2; }, py::is_operator()); // ====== First operand: matrix - py_M.def("__add__", [](const Matrix& x1) { return x1; }, py::is_operator()); + py_M.def("__add__", [](const Matrix& x1) -> Matrix { return x1; }, py::is_operator()); - //Matrix operator+(const M& x1, const M_& x2) - py_M.def("__add__", [](const Matrix& x1, const Matrix& x2) { return Matrix(x1+x2); }, py::is_operator()); - py_M.def("__add__", [](const Matrix& x1, const B& x2) { return Matrix(x1+x2); }, py::is_operator()); - py_B.def("__add__", [](const B& x1, const Matrix& x2) { return Matrix(x1+x2); }, py::is_operator()); - py_B.def("__add__", [](const B& x1, const B& x2) { return Matrix(x1+x2); }, py::is_operator()); + //Matrix operator-(const M& x1, const M_& x2) + py_M.def("__add__", [](const Matrix& x1, const Matrix& x2) -> Matrix { return x1+x2; }, py::is_operator()); + py_M.def("__add__", [](const Matrix& x1, const B& x2) -> Matrix { return x1+x2; }, py::is_operator()); + py_B.def("__add__", [](const B& x1, const Matrix& x2) -> Matrix { return x1+x2; }, py::is_operator()); + py_B.def("__add__", [](const B& x1, const B& x2) -> Matrix { return x1+x2; }, py::is_operator()); - //IntervalMatrix operator+(const M& x1, const IM& x2) - py_M.def("__add__", [](const Matrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_M.def("__add__", [](const Matrix& x1, const IB& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_B.def("__add__", [](const B& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_B.def("__add__", [](const B& x1, const IB& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + //IntervalMatrix operator-(const M& x1, const IM& x2) + py_M.def("__add__", [](const Matrix& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1.template cast()+x2; }, py::is_operator()); + py_M.def("__add__", [](const Matrix& x1, const IB& x2) -> IntervalMatrix { return x1.template cast()+x2; }, py::is_operator()); + py_B.def("__add__", [](const B& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1.template cast()+x2; }, py::is_operator()); + py_B.def("__add__", [](const B& x1, const IB& x2) -> IntervalMatrix { return x1.template cast()+x2; }, py::is_operator()); py_M.def("__iadd__", [](Matrix& x1, const Matrix& x2) { return x1+=x2; }, py::is_operator()); py_M.def("__iadd__", [](Matrix& x1, const B& x2) { return x1+=x2; }, py::is_operator()); // ====== First operand: interval vector - py_IV.def("__add__", [](const IntervalVector& x1) { return x1; }, py::is_operator()); + py_IV.def("__add__", [](const IntervalVector& x1) -> IntervalVector { return x1; }, py::is_operator()); - //inline IntervalVector operator+(const IntervalVector& x1, const Vector& x2) - py_IV.def("__add__", [](const IntervalVector& x1, const Vector& x2) { return IntervalVector(x1+x2); }, py::is_operator()); + //inline IntervalVector operator-(const IntervalVector& x1, const Vector& x2) + py_IV.def("__add__", [](const IntervalVector& x1, const Vector& x2) -> IntervalVector { return x1+x2.template cast(); }, py::is_operator()); - //inline IntervalVector operator+(const IntervalVector& x1, const IntervalVector& x2) - py_IV.def("__add__", [](const IntervalVector& x1, const IntervalVector& x2) { return IntervalVector(x1+x2); }, py::is_operator()); + //inline IntervalVector operator-(const IntervalVector& x1, const IntervalVector& x2) + py_IV.def("__add__", [](const IntervalVector& x1, const IntervalVector& x2) -> IntervalVector { return x1+x2; }, py::is_operator()); - py_IV.def("__iadd__", [](IntervalVector& x1, const Vector& x2) { return x1+=x2; }, py::is_operator()); + py_IV.def("__iadd__", [](IntervalVector& x1, const Vector& x2) { return x1+=x2.template cast(); }, py::is_operator()); py_IV.def("__iadd__", [](IntervalVector& x1, const IntervalVector& x2) { return x1+=x2; }, py::is_operator()); // ====== First operand: interval matrix - py_IM.def("__add__", [](const IntervalMatrix& x1) { return x1; }, py::is_operator()); + py_IM.def("__add__", [](const IntervalMatrix& x1) -> IntervalMatrix { return x1; }, py::is_operator()); - //IntervalMatrix operator+(const IM& x1, const M& x2) - py_IM.def("__add__", [](const IntervalMatrix& x1, const Matrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_IM.def("__add__", [](const IntervalMatrix& x1, const B& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_IB.def("__add__", [](const IB& x1, const Matrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_IB.def("__add__", [](const IB& x1, const B& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + //IntervalMatrix operator-(const IM& x1, const M& x2) + py_IM.def("__add__", [](const IntervalMatrix& x1, const Matrix& x2) -> IntervalMatrix { return x1+x2.template cast(); }, py::is_operator()); + py_IM.def("__add__", [](const IntervalMatrix& x1, const B& x2) -> IntervalMatrix { return x1+x2.template cast(); }, py::is_operator()); + py_IB.def("__add__", [](const IB& x1, const Matrix& x2) -> IntervalMatrix { return x1+x2.template cast(); }, py::is_operator()); + py_IB.def("__add__", [](const IB& x1, const B& x2) -> IntervalMatrix { return x1+x2.template cast(); }, py::is_operator()); - //IntervalMatrix operator+(const IM& x1, const IM_& x2) - py_IM.def("__add__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_IM.def("__add__", [](const IntervalMatrix& x1, const IB& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_IB.def("__add__", [](const IB& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); - py_IB.def("__add__", [](const IB& x1, const IB& x2) { return IntervalMatrix(x1+x2); }, py::is_operator()); + //IntervalMatrix operator-(const IM& x1, const IM_& x2) + py_IM.def("__add__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1+x2; }, py::is_operator()); + py_IM.def("__add__", [](const IntervalMatrix& x1, const IB& x2) -> IntervalMatrix { return x1+x2; }, py::is_operator()); + py_IB.def("__add__", [](const IB& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1+x2; }, py::is_operator()); + py_IB.def("__add__", [](const IB& x1, const IB& x2) -> IntervalMatrix { return x1+x2; }, py::is_operator()); - py_IM.def("__iadd__", [](IntervalMatrix& x1, const Matrix& x2) { return x1+=x2; }, py::is_operator()); - py_IM.def("__iadd__", [](IntervalMatrix& x1, const B& x2) { return x1+=x2; }, py::is_operator()); + py_IM.def("__iadd__", [](IntervalMatrix& x1, const Matrix& x2) { return x1+=x2.template cast(); }, py::is_operator()); + py_IM.def("__iadd__", [](IntervalMatrix& x1, const B& x2) { return x1+=x2.template cast(); }, py::is_operator()); py_IM.def("__iadd__", [](IntervalMatrix& x1, const IntervalMatrix& x2) { return x1+=x2; }, py::is_operator()); py_IM.def("__iadd__", [](IntervalMatrix& x1, const IB& x2) { return x1+=x2; }, py::is_operator()); diff --git a/python/src/core/matrices/codac2_py_arithmetic_div.cpp b/python/src/core/matrices/codac2_py_arithmetic_div.cpp index e4e8b3e1..3d16ae8c 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_div.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_div.cpp @@ -32,32 +32,32 @@ void export_arithmetic_div(py::module& m, // ====== First operand: vector //inline Vector operator/(const Vector& x1, double x2) - py_V.def("__truediv__", [](const Vector& x1, double x2) { return Vector(x1/x2); }, py::is_operator()); + py_V.def("__truediv__", [](const Vector& x1, double x2) -> Vector { return x1/x2; }, py::is_operator()); //inline IntervalVector operator/(const Vector& x1, const Interval& x2) - py_V.def("__truediv__", [](const Vector& x1, const Interval& x2) { return IntervalVector(x1/x2); }, py::is_operator()); + py_V.def("__truediv__", [](const Vector& x1, const Interval& x2) -> IntervalVector { return x1.template cast()/x2; }, py::is_operator()); py_V.def("__itruediv__", [](Vector& x1, double x2) { return x1/=x2; }, py::is_operator()); // ====== First operand: matrix //Matrix operator/(const M& x1, double x2) - py_M.def("__truediv__", [](const Matrix& x1, double x2) { return Matrix(x1/x2); }, py::is_operator()); - py_B.def("__truediv__", [](const Eigen::Block& x1, double x2) { return Matrix(x1/x2); }, py::is_operator()); + py_M.def("__truediv__", [](const Matrix& x1, double x2) -> Matrix { return x1/x2; }, py::is_operator()); + py_B.def("__truediv__", [](const Eigen::Block& x1, double x2) -> Matrix { return x1/x2; }, py::is_operator()); //IntervalMatrix operator/(const M& x1, const Interval& x2) - py_M.def("__truediv__", [](const Matrix& x1, const Interval& x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); - py_B.def("__truediv__", [](const B& x1, const Interval& x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); + py_M.def("__truediv__", [](const Matrix& x1, const Interval& x2) -> IntervalMatrix { return x1.template cast()/x2; }, py::is_operator()); + py_B.def("__truediv__", [](const B& x1, const Interval& x2) -> IntervalMatrix { return x1.template cast()/x2; }, py::is_operator()); py_M.def("__itruediv__", [](Matrix& x1, double x2) { return x1/=x2; }, py::is_operator()); // ====== First operand: interval vector //inline IntervalVector operator/(const IntervalVector& x1, double x2) - py_IV.def("__truediv__", [](const IntervalVector& x1, double x2) { return IntervalVector(x1/x2); }, py::is_operator()); + py_IV.def("__truediv__", [](const IntervalVector& x1, double x2) -> IntervalVector { return x1/x2; }, py::is_operator()); //inline IntervalVector operator/(const IntervalVector& x1, const Interval& x2) - py_IV.def("__truediv__", [](const IntervalVector& x1, const Interval& x2) { return IntervalVector(x1/x2); }, py::is_operator()); + py_IV.def("__truediv__", [](const IntervalVector& x1, const Interval& x2) -> IntervalVector { return x1/x2; }, py::is_operator()); py_IV.def("__itruediv__", [](IntervalVector& x1, double x2) { return x1/=x2; }, py::is_operator()); py_IV.def("__itruediv__", [](IntervalVector& x1, const Interval& x2) { return x1/=x2; }, py::is_operator()); @@ -65,12 +65,12 @@ void export_arithmetic_div(py::module& m, // ====== First operand: interval matrix //IntervalMatrix operator/(const IM& x1, double x2) - py_IM.def("__truediv__", [](const IntervalMatrix& x1, double x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); - py_IB.def("__truediv__", [](const IB& x1, double x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); + py_IM.def("__truediv__", [](const IntervalMatrix& x1, double x2) -> IntervalMatrix { return x1/x2; }, py::is_operator()); + py_IB.def("__truediv__", [](const IB& x1, double x2) -> IntervalMatrix { return x1/x2; }, py::is_operator()); //IntervalMatrix operator/(const IM& x1, const Interval& x2) - py_IM.def("__truediv__", [](const IntervalMatrix& x1, const Interval& x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); - py_IB.def("__truediv__", [](const IB& x1, const Interval& x2) { return IntervalMatrix(x1/x2); }, py::is_operator()); + py_IM.def("__truediv__", [](const IntervalMatrix& x1, const Interval& x2) -> IntervalMatrix { return x1/x2; }, py::is_operator()); + py_IB.def("__truediv__", [](const IB& x1, const Interval& x2) -> IntervalMatrix { return x1/x2; }, py::is_operator()); py_IM.def("__itruediv__", [](IntervalMatrix& x1, double x2) { return x1/=x2; }, py::is_operator()); py_IM.def("__itruediv__", [](IntervalMatrix& x1, const Interval& x2) { return x1/=x2; }, py::is_operator()); diff --git a/python/src/core/matrices/codac2_py_arithmetic_mul.cpp b/python/src/core/matrices/codac2_py_arithmetic_mul.cpp index d5ff6f58..97aa6439 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_mul.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_mul.cpp @@ -32,86 +32,86 @@ void export_arithmetic_mul(py::module& m, // ====== First operand: double //inline Vector operator*(double x1, const Vector& x2) - py_V.def("__rmul__", [](const Vector& x2, double x1) { return Vector(x1*x2); }, py::is_operator()); + py_V.def("__rmul__", [](const Vector& x2, double x1) -> Vector { return x1*x2; }, py::is_operator()); //Matrix operator*(double x1, const M& x2) - py_M.def("__rmul__", [](const Matrix& x2, double x1) { return Matrix(x1*x2); }, py::is_operator()); - py_B.def("__rmul__", [](const B& x2, double x1) { return Matrix(x1*x2); }, py::is_operator()); + py_M.def("__rmul__", [](const Matrix& x2, double x1) -> Matrix { return x1*x2; }, py::is_operator()); + py_B.def("__rmul__", [](const B& x2, double x1) -> Matrix { return x1*x2; }, py::is_operator()); //inline IntervalVector operator*(double x1, const IntervalVector& x2) - py_IV.def("__rmul__", [](const IntervalVector& x2, double x1) { return IntervalVector(x1*x2); }, py::is_operator()); + py_IV.def("__rmul__", [](const IntervalVector& x2, double x1) -> IntervalVector { return x1*x2; }, py::is_operator()); //IntervalMatrix operator*(double x1, const IM& x2) - py_IM.def("__rmul__", [](const IntervalMatrix& x2, double x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); - py_IB.def("__rmul__", [](const IB& x2, double x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_IM.def("__rmul__", [](const IntervalMatrix& x2, double x1) -> IntervalMatrix { return x1*x2; }, py::is_operator()); + py_IB.def("__rmul__", [](const IB& x2, double x1) -> IntervalMatrix { return x1*x2; }, py::is_operator()); // ====== First operand: interval //inline IntervalVector operator*(const Interval& x1, const Vector& x2) - py_V.def("__rmul__", [](const Vector& x2, const Interval& x1) { return IntervalVector(x1*x2); }, py::is_operator()); + py_V.def("__rmul__", [](const Vector& x2, const Interval& x1) -> IntervalVector { return x1*x2; }, py::is_operator()); //IntervalMatrix operator*(const Interval& x1, const M& x2) - py_M.def("__rmul__", [](const Matrix& x2, const Interval& x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); - py_B.def("__rmul__", [](const B& x2, const Interval& x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_M.def("__rmul__", [](const Matrix& x2, const Interval& x1) -> IntervalMatrix { return x1*x2; }, py::is_operator()); + py_B.def("__rmul__", [](const B& x2, const Interval& x1) -> IntervalMatrix { return x1*x2; }, py::is_operator()); //inline IntervalVector operator*(const Interval& x1, const IntervalVector& x2) - py_IV.def("__rmul__", [](const IntervalVector& x2, const Interval& x1) { return IntervalVector(x1*x2); }, py::is_operator()); + py_IV.def("__rmul__", [](const IntervalVector& x2, const Interval& x1) -> IntervalVector { return x1*x2; }, py::is_operator()); //IntervalMatrix operator*(const Interval& x1, const IM& x2) - py_IM.def("__rmul__", [](const IntervalMatrix& x2, const Interval& x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); - py_IB.def("__rmul__", [](const IB& x2, const Interval& x1) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_IM.def("__rmul__", [](const IntervalMatrix& x2, const Interval& x1) -> IntervalMatrix{ return x1*x2; }, py::is_operator()); + py_IB.def("__rmul__", [](const IB& x2, const Interval& x1) -> IntervalMatrix { return x1*x2; }, py::is_operator()); // ====== First operand: vector //inline Vector operator*(const Vector& x1, double x2) - py_V.def("__mul__", [](const Vector& x1, double x2) { return Vector(x1*x2); }, py::is_operator()); + py_V.def("__mul__", [](const Vector& x1, double x2) -> Vector { return x1*x2; }, py::is_operator()); //inline IntervalVector operator*(const Vector& x1, const Interval& x2) - py_V.def("__mul__", [](const Vector& x1, const Interval& x2) { return IntervalVector(x1*x2); }, py::is_operator()); + py_V.def("__mul__", [](const Vector& x1, const Interval& x2) -> IntervalVector { return x1*x2; }, py::is_operator()); py_V.def("__imul__", [](Vector& x1, double x2) { return x1*=x2; }, py::is_operator()); // ====== First operand: matrix //Interval operator*(const M& x1, double x2) - py_M.def("__mul__", [](const Matrix& x1, double x2) { return Matrix(x1*x2); }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, double x2) { return Matrix(x1*x2); }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, double x2) -> Matrix { return x1*x2; }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, double x2) -> Matrix { return x1*x2; }, py::is_operator()); //IntervalMatrix operator*(const M& x1, const Interval& x2) - py_M.def("__mul__", [](const Matrix& x1, const Interval& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const Interval& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const Interval& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const Interval& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); //Vector operator*(const M& x1, const Vector& x2) - py_M.def("__mul__", [](const Matrix& x1, const Vector& x2) { return Vector(x1*x2); }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const Vector& x2) { return Vector(x1*x2); }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const Vector& x2) -> Vector { return x1*x2; }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const Vector& x2) -> Vector { return x1*x2; }, py::is_operator()); //Matrix operator*(const M& x1, const M_& x2) - py_M.def("__mul__", [](const Matrix& x1, const Matrix& x2) { return Matrix(x1*x2); }, py::is_operator()); - py_M.def("__mul__", [](const Matrix& x1, const B& x2) { return Matrix(x1*x2.eval()); }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const Matrix& x2) { return Matrix(x1.eval()*x2); }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const B& x2) { return Matrix(x1.eval()*x2.eval()); }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const Matrix& x2) -> Matrix { return x1*x2; }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const B& x2) -> Matrix { return x1*x2; }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const Matrix& x2) -> Matrix { return x1*x2; }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const B& x2) -> Matrix { return x1*x2; }, py::is_operator()); //IntervalVector operator*(const M& x1, const IntervalVector& x2) - py_M.def("__mul__", [](const Matrix& x1, const IntervalVector& x2) { return IntervalVector(x1*x2); }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const IntervalVector& x2) { return IntervalVector(x1*x2); }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const IntervalVector& x2) -> IntervalVector { return x1*x2; }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const IntervalVector& x2) -> IntervalVector { return x1*x2; }, py::is_operator()); //IntervalMatrix operator*(const M& x1, const IM& x2) - py_M.def("__mul__", [](const Matrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(IntervalMatrix(x1)*x2); }, py::is_operator()); - py_M.def("__mul__", [](const Matrix& x1, const IB& x2) { return IntervalMatrix(IntervalMatrix(x1)*x2.eval()); }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const IntervalMatrix& x2) { return IntervalMatrix(IntervalMatrix(x1)*x2); }, py::is_operator()); - py_B.def("__mul__", [](const B& x1, const IB& x2) { return IntervalMatrix(IntervalMatrix(x1)*x2.eval()); }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1.template cast()*x2; }, py::is_operator()); + py_M.def("__mul__", [](const Matrix& x1, const IB& x2) -> IntervalMatrix { return x1.template cast()*x2; }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1.template cast()*x2; }, py::is_operator()); + py_B.def("__mul__", [](const B& x1, const IB& x2) -> IntervalMatrix { return x1.template cast()*x2; }, py::is_operator()); py_M.def("__imul__", [](Matrix& x1, double x2) { return x1*=x2; }, py::is_operator()); py_M.def("__imul__", [](Matrix& x1, const Matrix& x2) { return x1*=x2; }, py::is_operator()); - py_M.def("__imul__", [](Matrix& x1, const B& x2) { return x1*=x2.eval(); }, py::is_operator()); + py_M.def("__imul__", [](Matrix& x1, const B& x2) { return x1*=x2; }, py::is_operator()); // ====== First operand: interval vector //inline IntervalVector operator*(const IntervalVector& x1, double x2) - py_IV.def("__mul__", [](const IntervalVector& x1, double x2) { return IntervalVector(x1*x2); }, py::is_operator()); + py_IV.def("__mul__", [](const IntervalVector& x1, double x2) -> IntervalVector { return x1*x2; }, py::is_operator()); //inline IntervalVector operator*(const IntervalVector& x1, const Interval& x2) - py_IV.def("__mul__", [](const IntervalVector& x1, const Interval& x2) { return IntervalVector(x1*x2); }, py::is_operator()); + py_IV.def("__mul__", [](const IntervalVector& x1, const Interval& x2) -> IntervalVector { return x1*x2; }, py::is_operator()); py_IV.def("__imul__", [](IntervalVector& x1, double x2) { return x1*=x2; }, py::is_operator()); py_IV.def("__imul__", [](IntervalVector& x1, const Interval& x2) { return x1*=x2; }, py::is_operator()); @@ -119,38 +119,38 @@ void export_arithmetic_mul(py::module& m, // ====== First operand: interval matrix //IntervalMatrix operator*(const IM& x1, double x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, double x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, double x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, double x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, double x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); //IntervalMatrix operator*(const IM& x1, const Interval& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const Interval& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const Interval& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const Interval& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const Interval& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); //IntervalVector operator*(const IM& x1, const Vector& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const Vector& x2) { return IntervalVector(x1*IntervalVector(x2)); }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const Vector& x2) { return IntervalVector(x1*x2.template cast()); }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const Vector& x2) -> IntervalVector { return x1*x2.template cast(); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const Vector& x2) -> IntervalVector { return x1*x2.template cast(); }, py::is_operator()); //IntervalMatrix operator*(const IM& x1, const M& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const Matrix& x2) { return IntervalMatrix(x1*IntervalMatrix(x2)); }, py::is_operator()); - py_IM.def("__mul__", [](const IntervalMatrix& x1, const B& x2) { return IntervalMatrix(x1*x2.template cast().eval()); }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const Matrix& x2) { return IntervalMatrix(x1.eval()*IntervalMatrix(x2)); }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const B& x2) { return IntervalMatrix(x1.eval()*x2.template cast().eval()); }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const Matrix& x2) -> IntervalMatrix { return x1*x2.template cast(); }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const B& x2) -> IntervalMatrix { return x1*x2.template cast(); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const Matrix& x2) -> IntervalMatrix { return x1*x2.template cast(); }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const B& x2) -> IntervalMatrix { return x1*x2.template cast(); }, py::is_operator()); //IntervalVector operator*(const IM& x1, const IntervalVector& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const IntervalVector& x2) { return IntervalVector(x1*x2); }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const IntervalVector& x2) { return IntervalVector(x1*x2); }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const IntervalVector& x2) -> IntervalVector { return x1*x2; }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const IntervalVector& x2) -> IntervalVector { return x1*x2; }, py::is_operator()); //IntervalMatrix operator*(const IM& x1, const IM_& x2) - py_IM.def("__mul__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1*x2); }, py::is_operator()); - py_IM.def("__mul__", [](const IntervalMatrix& x1, const IB& x2) { return IntervalMatrix(x1*x2.eval()); }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1.eval()*x2); }, py::is_operator()); - py_IB.def("__mul__", [](const IB& x1, const IB& x2) { return IntervalMatrix(x1.eval()*x2.eval()); }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); + py_IM.def("__mul__", [](const IntervalMatrix& x1, const IB& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); + py_IB.def("__mul__", [](const IB& x1, const IB& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator()); py_IM.def("__imul__", [](IntervalMatrix& x1, double x2) { return x1*=x2; }, py::is_operator()); - py_IM.def("__imul__", [](IntervalMatrix& x1, const Matrix& x2) { return x1*=IntervalMatrix(x2); }, py::is_operator()); - py_IM.def("__imul__", [](IntervalMatrix& x1, const B& x2) { return x1*=IntervalMatrix(x2); }, py::is_operator()); + py_IM.def("__imul__", [](IntervalMatrix& x1, const Matrix& x2) { return x1*=x2.template cast(); }, py::is_operator()); + py_IM.def("__imul__", [](IntervalMatrix& x1, const B& x2) { return x1*=x2.template cast(); }, py::is_operator()); py_IM.def("__imul__", [](IntervalMatrix& x1, const Interval& x2) { return x1*=x2; }, py::is_operator()); py_IM.def("__imul__", [](IntervalMatrix& x1, const IntervalMatrix& x2) { return x1*=x2; }, py::is_operator()); - py_IM.def("__imul__", [](IntervalMatrix& x1, const IB& x2) { return x1*=x2.eval(); }, py::is_operator()); + py_IM.def("__imul__", [](IntervalMatrix& x1, const IB& x2) { return x1*=x2; }, py::is_operator()); } \ No newline at end of file diff --git a/python/src/core/matrices/codac2_py_arithmetic_sub.cpp b/python/src/core/matrices/codac2_py_arithmetic_sub.cpp index f0fb7690..683e4c50 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_sub.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_sub.cpp @@ -31,66 +31,66 @@ void export_arithmetic_sub(py::module& m, { // ====== First operand: vector - py_V.def("__neg__", [](const Vector& x1) { return Vector(-x1); }, py::is_operator()); + py_V.def("__neg__", [](const Vector& x1) -> Vector { return -x1; }, py::is_operator()); //inline Vector operator-(const Vector& x1, const Vector& x2) - py_V.def("__sub__", [](const Vector& x1, const Vector& x2) { return Vector(x1-x2); }, py::is_operator()); + py_V.def("__sub__", [](const Vector& x1, const Vector& x2) -> Vector { return x1-x2; }, py::is_operator()); //inline IntervalVector operator-(const Vector& x1, const IntervalVector& x2) - py_V.def("__sub__", [](const Vector& x1, const IntervalVector& x2) { return IntervalVector(x1-x2); }, py::is_operator()); + py_V.def("__sub__", [](const Vector& x1, const IntervalVector& x2) -> IntervalVector { return x1.template cast()-x2; }, py::is_operator()); py_V.def("__isub__", [](Vector& x1, const Vector& x2) { return x1-=x2; }, py::is_operator()); // ====== First operand: matrix - py_M.def("__neg__", [](const Matrix& x1) { return Matrix(-x1); }, py::is_operator()); + py_M.def("__neg__", [](const Matrix& x1) -> Matrix { return -x1; }, py::is_operator()); //Matrix operator-(const M& x1, const M_& x2) - py_M.def("__sub__", [](const Matrix& x1, const Matrix& x2) { return Matrix(x1-x2); }, py::is_operator()); - py_M.def("__sub__", [](const Matrix& x1, const B& x2) { return Matrix(x1-x2); }, py::is_operator()); - py_B.def("__sub__", [](const B& x1, const Matrix& x2) { return Matrix(x1-x2); }, py::is_operator()); - py_B.def("__sub__", [](const B& x1, const B& x2) { return Matrix(x1-x2); }, py::is_operator()); + py_M.def("__sub__", [](const Matrix& x1, const Matrix& x2) -> Matrix { return x1-x2; }, py::is_operator()); + py_M.def("__sub__", [](const Matrix& x1, const B& x2) -> Matrix { return x1-x2; }, py::is_operator()); + py_B.def("__sub__", [](const B& x1, const Matrix& x2) -> Matrix { return x1-x2; }, py::is_operator()); + py_B.def("__sub__", [](const B& x1, const B& x2) -> Matrix { return x1-x2; }, py::is_operator()); //IntervalMatrix operator-(const M& x1, const IM& x2) - py_M.def("__sub__", [](const Matrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_M.def("__sub__", [](const Matrix& x1, const IB& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_B.def("__sub__", [](const B& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_B.def("__sub__", [](const B& x1, const IB& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_M.def("__sub__", [](const Matrix& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1.template cast()-x2; }, py::is_operator()); + py_M.def("__sub__", [](const Matrix& x1, const IB& x2) -> IntervalMatrix { return x1.template cast()-x2; }, py::is_operator()); + py_B.def("__sub__", [](const B& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1.template cast()-x2; }, py::is_operator()); + py_B.def("__sub__", [](const B& x1, const IB& x2) -> IntervalMatrix { return x1.template cast()-x2; }, py::is_operator()); py_M.def("__isub__", [](Matrix& x1, const Matrix& x2) { return x1-=x2; }, py::is_operator()); py_M.def("__isub__", [](Matrix& x1, const B& x2) { return x1-=x2; }, py::is_operator()); // ====== First operand: interval vector - py_IV.def("__neg__", [](const IntervalVector& x1) { return IntervalVector(-x1); }, py::is_operator()); + py_IV.def("__neg__", [](const IntervalVector& x1) -> IntervalVector { return -x1; }, py::is_operator()); //inline IntervalVector operator-(const IntervalVector& x1, const Vector& x2) - py_IV.def("__sub__", [](const IntervalVector& x1, const Vector& x2) { return IntervalVector(x1-x2); }, py::is_operator()); + py_IV.def("__sub__", [](const IntervalVector& x1, const Vector& x2) -> IntervalVector { return x1-x2.template cast(); }, py::is_operator()); //inline IntervalVector operator-(const IntervalVector& x1, const IntervalVector& x2) - py_IV.def("__sub__", [](const IntervalVector& x1, const IntervalVector& x2) { return IntervalVector(x1-x2); }, py::is_operator()); + py_IV.def("__sub__", [](const IntervalVector& x1, const IntervalVector& x2) -> IntervalVector { return x1-x2; }, py::is_operator()); - py_IV.def("__isub__", [](IntervalVector& x1, const Vector& x2) { return x1-=x2; }, py::is_operator()); + py_IV.def("__isub__", [](IntervalVector& x1, const Vector& x2) { return x1-=x2.template cast(); }, py::is_operator()); py_IV.def("__isub__", [](IntervalVector& x1, const IntervalVector& x2) { return x1-=x2; }, py::is_operator()); // ====== First operand: interval matrix - py_IM.def("__neg__", [](const IntervalMatrix& x1) { return IntervalMatrix(-x1); }, py::is_operator()); + py_IM.def("__neg__", [](const IntervalMatrix& x1) -> IntervalMatrix { return -x1; }, py::is_operator()); //IntervalMatrix operator-(const IM& x1, const M& x2) - py_IM.def("__sub__", [](const IntervalMatrix& x1, const Matrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_IM.def("__sub__", [](const IntervalMatrix& x1, const B& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_IB.def("__sub__", [](const IB& x1, const Matrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_IB.def("__sub__", [](const IB& x1, const B& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_IM.def("__sub__", [](const IntervalMatrix& x1, const Matrix& x2) -> IntervalMatrix { return x1-x2.template cast(); }, py::is_operator()); + py_IM.def("__sub__", [](const IntervalMatrix& x1, const B& x2) -> IntervalMatrix { return x1-x2.template cast(); }, py::is_operator()); + py_IB.def("__sub__", [](const IB& x1, const Matrix& x2) -> IntervalMatrix { return x1-x2.template cast(); }, py::is_operator()); + py_IB.def("__sub__", [](const IB& x1, const B& x2) -> IntervalMatrix { return x1-x2.template cast(); }, py::is_operator()); //IntervalMatrix operator-(const IM& x1, const IM_& x2) - py_IM.def("__sub__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_IM.def("__sub__", [](const IntervalMatrix& x1, const IB& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_IB.def("__sub__", [](const IB& x1, const IntervalMatrix& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); - py_IB.def("__sub__", [](const IB& x1, const IB& x2) { return IntervalMatrix(x1-x2); }, py::is_operator()); + py_IM.def("__sub__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1-x2; }, py::is_operator()); + py_IM.def("__sub__", [](const IntervalMatrix& x1, const IB& x2) -> IntervalMatrix { return x1-x2; }, py::is_operator()); + py_IB.def("__sub__", [](const IB& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1-x2; }, py::is_operator()); + py_IB.def("__sub__", [](const IB& x1, const IB& x2) -> IntervalMatrix { return x1-x2; }, py::is_operator()); - py_IM.def("__isub__", [](IntervalMatrix& x1, const Matrix& x2) { return x1-=x2; }, py::is_operator()); - py_IM.def("__isub__", [](IntervalMatrix& x1, const B& x2) { return x1-=x2; }, py::is_operator()); + py_IM.def("__isub__", [](IntervalMatrix& x1, const Matrix& x2) { return x1-=x2.template cast(); }, py::is_operator()); + py_IM.def("__isub__", [](IntervalMatrix& x1, const B& x2) { return x1-=x2.template cast(); }, py::is_operator()); py_IM.def("__isub__", [](IntervalMatrix& x1, const IntervalMatrix& x2) { return x1-=x2; }, py::is_operator()); py_IM.def("__isub__", [](IntervalMatrix& x1, const IB& x2) { return x1-=x2; }, py::is_operator()); diff --git a/src/core/matrices/codac2_GaussJordan.cpp b/src/core/matrices/codac2_GaussJordan.cpp index 75329fdd..60d9e5ae 100644 --- a/src/core/matrices/codac2_GaussJordan.cpp +++ b/src/core/matrices/codac2_GaussJordan.cpp @@ -32,8 +32,9 @@ namespace codac2 Matrix precond(const Matrix& P, const Matrix& L, const Matrix& U) { - Matrix A = P.inverse()*(L*U); - Matrix R = (P.inverse().eval()*L).inverse().eval(); + auto P_inv = P.inverse(); + Matrix A = P_inv*(L*U); + Matrix R = (P_inv*L).inverse(); return rising(R,U,A); } diff --git a/src/core/matrices/codac2_matrices.h b/src/core/matrices/codac2_matrices.h index 1ed30272..1ff59486 100644 --- a/src/core/matrices/codac2_matrices.h +++ b/src/core/matrices/codac2_matrices.h @@ -81,6 +81,7 @@ namespace Eigen namespace codac2 { using Eigen::Dynamic; + using Eigen::Index; inline const Interval& conj(const Interval& x) { return x; } inline const Interval& real(const Interval& x) { return x; } @@ -99,7 +100,7 @@ namespace codac2 { Eigen::Matrix a(x); - for(size_t i = 0 ; i < x.size() ; i++) + for(int i = 0 ; i < x.size() ; i++) { if constexpr(std::is_same_v) *(a.data()+i) = fabs(*(x.data()+i)); diff --git a/src/core/matrices/eigen/codac2_Base_eigenaddons.h b/src/core/matrices/eigen/codac2_Base_eigenaddons.h index be070ccf..40d744f5 100644 --- a/src/core/matrices/eigen/codac2_Base_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_Base_eigenaddons.h @@ -21,21 +21,6 @@ Matrix(const Matrix& x) *this = x.template cast(); } -inline size_t size() const -{ - return Base::size(); -} - -inline size_t rows() const -{ - return Base::rows(); -} - -inline size_t cols() const -{ - return Base::cols(); -} - template inline Scalar& operator()(size_t i, size_t j) { From 7bcdbbd45eff923a112be3d4efb333f40c3c6500 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 21 Nov 2024 16:49:21 +0100 Subject: [PATCH 044/102] [core] now using Index instead of std::size_t (compatibility with Eigen::Index) --- python/src/codac2_py_matlab.h | 8 +- python/src/core/actions/codac2_py_OctaSym.cpp | 2 +- python/src/core/contractors/codac2_py_Ctc.cpp | 6 +- python/src/core/contractors/codac2_py_Ctc.h | 2 +- .../core/contractors/codac2_py_CtcEmpty.cpp | 4 +- .../contractors/codac2_py_CtcIdentity.cpp | 4 +- .../core/contractors/codac2_py_CtcInter.cpp | 4 +- .../core/contractors/codac2_py_CtcProj.cpp | 12 +-- .../core/contractors/codac2_py_CtcUnion.cpp | 4 +- .../contractors/codac2_py_directed_ctc.cpp | 8 +- .../domains/interval/codac2_py_Interval.cpp | 2 +- .../interval/codac2_py_IntervalMatrix.cpp | 8 +- .../interval/codac2_py_IntervalMatrixBase.h | 10 +-- .../interval/codac2_py_IntervalVector.cpp | 8 +- .../core/domains/paving/codac2_py_Paving.cpp | 10 +-- .../analytic/codac2_py_AnalyticFunction.h | 4 +- .../analytic/codac2_py_analytic_variables.cpp | 24 +++--- python/src/core/matrices/codac2_py_Matrix.cpp | 4 +- .../src/core/matrices/codac2_py_MatrixBase.h | 32 ++++---- python/src/core/matrices/codac2_py_Vector.cpp | 6 +- .../src/core/matrices/codac2_py_VectorBase.h | 30 +++---- python/src/core/separators/codac2_py_Sep.cpp | 6 +- python/src/core/separators/codac2_py_Sep.h | 2 +- .../src/core/separators/codac2_py_SepProj.cpp | 18 ++-- .../graphics/figures/codac2_py_Figure2D.cpp | 6 +- src/core/3rd/codac2_ibex.cpp | 6 +- src/core/CMakeLists.txt | 1 + src/core/actions/codac2_OctaSym.cpp | 2 +- src/core/actions/codac2_OctaSym.h | 2 +- src/core/contractors/codac2_Ctc.h | 9 +- src/core/contractors/codac2_CtcAction.h | 2 +- src/core/contractors/codac2_CtcCartProd.h | 4 +- .../contractors/codac2_CtcCtcBoundary.cpp | 4 +- src/core/contractors/codac2_CtcEmpty.cpp | 2 +- src/core/contractors/codac2_CtcEmpty.h | 2 +- src/core/contractors/codac2_CtcIdentity.cpp | 2 +- src/core/contractors/codac2_CtcIdentity.h | 2 +- src/core/contractors/codac2_CtcInter.h | 2 +- src/core/contractors/codac2_CtcProj.h | 8 +- src/core/contractors/codac2_CtcUnion.h | 2 +- src/core/contractors/codac2_directed_ctc.cpp | 82 +++++++++---------- src/core/contractors/codac2_directed_ctc.h | 22 ++--- src/core/contractors/codac2_linear_ctc.cpp | 14 ++-- src/core/domains/interval/codac2_Interval.cpp | 2 +- src/core/domains/interval/codac2_Interval.h | 3 +- .../domains/interval/codac2_IntervalMatrix.h | 4 +- .../domains/interval/codac2_IntervalVector.h | 6 +- .../codac2_IntervalMatrixBase_eigenaddons.h | 68 +++++++-------- .../eigen/codac2_IntervalMatrix_eigenaddons.h | 2 +- .../eigen/codac2_IntervalVector_eigenaddons.h | 20 ++--- src/core/domains/paving/codac2_Paving.cpp | 4 +- src/core/domains/paving/codac2_Paving.h | 12 +-- src/core/domains/paving/codac2_Subpaving.h | 2 +- .../functions/analytic/codac2_AnalyticExpr.h | 16 ++-- .../analytic/codac2_AnalyticFunction.h | 16 ++-- .../analytic/codac2_analytic_constants.h | 4 +- .../analytic/codac2_analytic_values.h | 2 +- .../analytic/codac2_analytic_variables.h | 14 ++-- src/core/functions/codac2_ExprBase.cpp | 4 +- src/core/functions/codac2_ExprBase.h | 6 +- src/core/functions/codac2_FunctionArgsList.h | 4 +- src/core/functions/codac2_FunctionBase.h | 2 +- src/core/functions/codac2_VarBase.h | 2 +- src/core/functions/set/codac2_SetExpr.h | 6 +- src/core/functions/set/codac2_SetFunction.h | 6 +- .../functions/set/codac2_set_operations.h | 4 +- src/core/functions/set/codac2_set_operators.h | 8 +- src/core/functions/set/codac2_set_variables.h | 10 +-- src/core/geometry/codac2_Polygon.cpp | 4 +- src/core/matrices/codac2_GaussJordan.cpp | 8 +- src/core/matrices/codac2_matrices.h | 1 - .../matrices/eigen/codac2_Base_eigenaddons.h | 10 +-- .../eigen/codac2_MatrixBase_eigenaddons.h | 22 ++--- .../eigen/codac2_VectorBase_eigenaddons.h | 20 ++--- .../eigen/codac2_Vector_eigenaddons.h | 10 +-- .../matrices/eigen/codac2_eigenaddons_test.h | 4 +- src/core/proj/codac2_ProjBase.cpp | 22 ++--- src/core/proj/codac2_ProjBase.h | 8 +- src/core/separators/codac2_Sep.h | 8 +- src/core/separators/codac2_SepAction.h | 2 +- src/core/separators/codac2_SepCartProd.cpp | 2 +- src/core/separators/codac2_SepCartProd.h | 2 +- src/core/separators/codac2_SepCtcBoundary.cpp | 4 +- src/core/separators/codac2_SepEllipse.cpp | 2 +- src/core/separators/codac2_SepProj.h | 8 +- src/core/tools/codac2_Approx.h | 6 +- src/core/tools/codac2_Index.h | 16 ++++ src/core/tools/codac2_template_tools.h | 12 +-- src/graphics/figures/codac2_Figure2D.cpp | 3 +- src/graphics/figures/codac2_Figure2D.h | 7 +- .../figures/codac2_OutputFigure2D.cpp | 4 +- src/graphics/figures/codac2_OutputFigure2D.h | 4 +- src/graphics/paver/codac2_drawwhilepaving.cpp | 4 +- .../interval/codac2_tests_IntervalVector.cpp | 2 +- 94 files changed, 419 insertions(+), 395 deletions(-) create mode 100644 src/core/tools/codac2_Index.h diff --git a/python/src/codac2_py_matlab.h b/python/src/codac2_py_matlab.h index 84854d6a..232ea746 100644 --- a/python/src/codac2_py_matlab.h +++ b/python/src/codac2_py_matlab.h @@ -10,15 +10,17 @@ #pragma once +#include + #define FOR_MATLAB false namespace codac2 { #if FOR_MATLAB - using size_t_type = double; + using Index_type = double; using int_type = double; #else - using size_t_type = size_t; + using Index_type = Index; using int_type = int; #endif @@ -40,7 +42,7 @@ namespace codac2 } template - size_t input_index(const I& x) + Index input_index(const I& x) { if constexpr(FOR_MATLAB) return x-1; diff --git a/python/src/core/actions/codac2_py_OctaSym.cpp b/python/src/core/actions/codac2_py_OctaSym.cpp index 152ea90c..192678c0 100644 --- a/python/src/core/actions/codac2_py_OctaSym.cpp +++ b/python/src/core/actions/codac2_py_OctaSym.cpp @@ -34,7 +34,7 @@ void export_OctaSym(py::module& m) { vector v(l.size()); - size_t i = 0; + Index i = 0; for(const auto& li : l) { matlab::test_integer(li); diff --git a/python/src/core/contractors/codac2_py_Ctc.cpp b/python/src/core/contractors/codac2_py_Ctc.cpp index fc44d53a..cc9aa9a9 100644 --- a/python/src/core/contractors/codac2_py_Ctc.cpp +++ b/python/src/core/contractors/codac2_py_Ctc.cpp @@ -36,11 +36,11 @@ py::class_,pyCtcIntervalVector> export_CtcIntervalVector py::class_,pyCtcIntervalVector> py_ctc_iv(m, "CtcIntervalVector"/*, py_ctc*/); py_ctc_iv - .def(py::init(), - CTCBASE_X_CTCBASE_SIZET) + .def(py::init(), + CTCBASE_X_CTCBASE_INDEX) .def("size", &CtcBase::size, - SIZET_CTCBASE_X_SIZE_CONST) + INDEX_CTCBASE_X_SIZE_CONST) .def("copy", [](const CtcBase& c) { diff --git a/python/src/core/contractors/codac2_py_Ctc.h b/python/src/core/contractors/codac2_py_Ctc.h index a26e4ea3..a3617565 100644 --- a/python/src/core/contractors/codac2_py_Ctc.h +++ b/python/src/core/contractors/codac2_py_Ctc.h @@ -29,7 +29,7 @@ class pyCtcIntervalVector : public CtcBase { public: - pyCtcIntervalVector(size_t_type n) + pyCtcIntervalVector(Index_type n) : CtcBase(n) { matlab::test_integer(n); diff --git a/python/src/core/contractors/codac2_py_CtcEmpty.cpp b/python/src/core/contractors/codac2_py_CtcEmpty.cpp index cb07b849..832ddd86 100644 --- a/python/src/core/contractors/codac2_py_CtcEmpty.cpp +++ b/python/src/core/contractors/codac2_py_CtcEmpty.cpp @@ -24,8 +24,8 @@ void export_CtcEmpty(py::module& m, py::class_,pyCtcInte py::class_ exported(m, "CtcEmpty", pyctc, CTCEMPTY_MAIN); exported - .def(py::init(), - CTCEMPTY_CTCEMPTY_SIZET + .def(py::init(), + CTCEMPTY_CTCEMPTY_INDEX "n"_a) .def(CONTRACT_BOX_METHOD(CtcEmpty, diff --git a/python/src/core/contractors/codac2_py_CtcIdentity.cpp b/python/src/core/contractors/codac2_py_CtcIdentity.cpp index c39cd587..57e2f327 100644 --- a/python/src/core/contractors/codac2_py_CtcIdentity.cpp +++ b/python/src/core/contractors/codac2_py_CtcIdentity.cpp @@ -24,8 +24,8 @@ void export_CtcIdentity(py::module& m, py::class_,pyCtcI py::class_ exported(m, "CtcIdentity", pyctc, CTCIDENTITY_MAIN); exported - .def(py::init(), - CTCIDENTITY_CTCIDENTITY_SIZET + .def(py::init(), + CTCIDENTITY_CTCIDENTITY_INDEX "n"_a) .def(CONTRACT_BOX_METHOD(CtcIdentity, diff --git a/python/src/core/contractors/codac2_py_CtcInter.cpp b/python/src/core/contractors/codac2_py_CtcInter.cpp index a8211a26..d3ea61d8 100644 --- a/python/src/core/contractors/codac2_py_CtcInter.cpp +++ b/python/src/core/contractors/codac2_py_CtcInter.cpp @@ -24,8 +24,8 @@ void export_CtcInter(py::module& m, py::class_,pyCtcInte py::class_> exported(m, "CtcInter", pyctc, CTCINTER_MAIN); exported - .def(py::init(), - CTCINTER_X_CTCINTER_SIZET, + .def(py::init(), + CTCINTER_X_CTCINTER_INDEX, "n"_a) .def(py::init( diff --git a/python/src/core/contractors/codac2_py_CtcProj.cpp b/python/src/core/contractors/codac2_py_CtcProj.cpp index d115bf51..2630aff6 100644 --- a/python/src/core/contractors/codac2_py_CtcProj.cpp +++ b/python/src/core/contractors/codac2_py_CtcProj.cpp @@ -25,10 +25,10 @@ void export_CtcProj(py::module& m, py::class_,pyCtcInter exported .def(py::init( - [](const CtcBase& c, std::vector proj_indices, double default_eps) + [](const CtcBase& c, std::vector proj_indices, double default_eps) { std::transform(std::begin(proj_indices),std::end(proj_indices),std::begin(proj_indices), - [](size_t_type x) + [](Index_type x) { matlab::test_integer(x); return matlab::input_index(x); @@ -36,14 +36,14 @@ void export_CtcProj(py::module& m, py::class_,pyCtcInter return std::make_unique(c.copy(), proj_indices, default_eps); }), - CTCPROJ_CTCPROJ_CONST_C_REF_CONST_VECTOR_SIZET_REF_DOUBLE, + CTCPROJ_CTCPROJ_CONST_C_REF_CONST_VECTOR_INDEX_REF_DOUBLE, "c"_a, "proj_indices"_a, "default_eps"_a=0.01) .def(py::init( - [](const CtcBase& c, std::vector proj_indices, const IntervalVector& y, double default_eps) + [](const CtcBase& c, std::vector proj_indices, const IntervalVector& y, double default_eps) { std::transform(std::begin(proj_indices),std::end(proj_indices),std::begin(proj_indices), - [](size_t_type x) + [](Index_type x) { matlab::test_integer(x); return matlab::input_index(x); @@ -51,7 +51,7 @@ void export_CtcProj(py::module& m, py::class_,pyCtcInter return std::make_unique(c.copy(), proj_indices, y, default_eps); }), - CTCPROJ_CTCPROJ_CONST_C_REF_CONST_VECTOR_SIZET_REF_CONST_INTERVALVECTOR_REF_DOUBLE, + CTCPROJ_CTCPROJ_CONST_C_REF_CONST_VECTOR_INDEX_REF_CONST_INTERVALVECTOR_REF_DOUBLE, "c"_a, "proj_indices"_a, "y"_a, "default_eps"_a=0.01) .def("contract", (void(CtcProj::*)(IntervalVector&,double) const) &CtcProj::contract, diff --git a/python/src/core/contractors/codac2_py_CtcUnion.cpp b/python/src/core/contractors/codac2_py_CtcUnion.cpp index fcb1e4a8..2505b2ed 100644 --- a/python/src/core/contractors/codac2_py_CtcUnion.cpp +++ b/python/src/core/contractors/codac2_py_CtcUnion.cpp @@ -24,8 +24,8 @@ void export_CtcUnion(py::module& m, py::class_,pyCtcInte py::class_> exported(m, "CtcUnion", pyctc, CTCUNION_MAIN); exported - .def(py::init(), - CTCUNION_X_CTCUNION_SIZET, + .def(py::init(), + CTCUNION_X_CTCUNION_INDEX, "n"_a) .def(py::init( diff --git a/python/src/core/contractors/codac2_py_directed_ctc.cpp b/python/src/core/contractors/codac2_py_directed_ctc.cpp index 5190a954..bfc07beb 100644 --- a/python/src/core/contractors/codac2_py_directed_ctc.cpp +++ b/python/src/core/contractors/codac2_py_directed_ctc.cpp @@ -335,11 +335,11 @@ void export_directed_ctc(py::module& m) py::class_(m, "ComponentOp") - .def_static("fwd", (Interval(*)(const IntervalVector&,size_t)) &ComponentOp::fwd, - STATIC_INTERVAL_COMPONENTOP_FWD_CONST_INTERVALVECTOR_REF_SIZET, + .def_static("fwd", (Interval(*)(const IntervalVector&,Index)) &ComponentOp::fwd, + STATIC_INTERVAL_COMPONENTOP_FWD_CONST_INTERVALVECTOR_REF_INDEX, "x1"_a, "i"_a) - .def_static("bwd", (void(*)(const Interval&,IntervalVector&,size_t)) &ComponentOp::bwd, - STATIC_VOID_COMPONENTOP_BWD_CONST_INTERVAL_REF_INTERVALVECTOR_REF_SIZET, + .def_static("bwd", (void(*)(const Interval&,IntervalVector&,Index)) &ComponentOp::bwd, + STATIC_VOID_COMPONENTOP_BWD_CONST_INTERVAL_REF_INTERVALVECTOR_REF_INDEX, "y"_a, "x1"_a, "i"_a) ; diff --git a/python/src/core/domains/interval/codac2_py_Interval.cpp b/python/src/core/domains/interval/codac2_py_Interval.cpp index 41d7dbe6..f2d5cd70 100644 --- a/python/src/core/domains/interval/codac2_py_Interval.cpp +++ b/python/src/core/domains/interval/codac2_py_Interval.cpp @@ -96,7 +96,7 @@ py::class_ export_Interval(py::module& m) DOUBLE_INTERVAL_VOLUME_CONST) .def("size", &Interval::size, - SIZET_INTERVAL_SIZE_CONST) + INDEX_INTERVAL_SIZE_CONST) .def("set_empty", &Interval::set_empty, VOID_INTERVAL_SET_EMPTY) diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp index 61057546..6575b6be 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp @@ -40,7 +40,7 @@ py::class_ export_IntervalMatrix(py::module& m) exported_intervalmatrix_class .def(py::init( - [](size_t_type r, size_t_type c) + [](Index_type r, Index_type c) { matlab::test_integer(r,c); return std::make_unique(r,c); @@ -49,7 +49,7 @@ py::class_ export_IntervalMatrix(py::module& m) "r"_a, "c"_a) .def(py::init( - [](size_t_type r, size_t_type c, const Interval& x) + [](Index_type r, Index_type c, const Interval& x) { matlab::test_integer(r,c); return std::make_unique(r,c,x); @@ -107,12 +107,12 @@ py::class_ export_IntervalMatrix(py::module& m) DOC_TO_BE_DEFINED, "v"_a) - .def_static("empty", [](size_t_type r, size_t_type c) + .def_static("empty", [](Index_type r, Index_type c) { matlab::test_integer(r,c); return IntervalMatrix::empty(r,c); }, - INTERVALMATRIXBASE_EIGENADDONS_STATIC_AUTO_EMPTY_SIZET_SIZET, + INTERVALMATRIXBASE_EIGENADDONS_STATIC_AUTO_EMPTY_INDEX_INDEX, "r"_a, "c"_a) .def("__repr__", [](const IntervalMatrix& x) diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h index cdd0b87d..ef3821a7 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h @@ -71,19 +71,19 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) { return matlab::output_index(x.min_diam_index()); }, - INTERVALMATRIXBASE_EIGENADDONS_SIZET_MIN_DIAM_INDEX_CONST) + INTERVALMATRIXBASE_EIGENADDONS_INDEX_MIN_DIAM_INDEX_CONST) .def("max_diam_index", [](const S& x) { return matlab::output_index(x.max_diam_index()); }, - INTERVALMATRIXBASE_EIGENADDONS_SIZET_MAX_DIAM_INDEX_CONST) + INTERVALMATRIXBASE_EIGENADDONS_INDEX_MAX_DIAM_INDEX_CONST) .def("extr_diam_index", [](const S& x, bool min) { return matlab::output_index(x.extr_diam_index(min)); }, - INTERVALMATRIXBASE_EIGENADDONS_SIZET_EXTR_DIAM_INDEX_BOOL_CONST, + INTERVALMATRIXBASE_EIGENADDONS_INDEX_EXTR_DIAM_INDEX_BOOL_CONST, "min"_a) .def("__contains__", &S::contains, @@ -142,12 +142,12 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) INTERVALMATRIXBASE_EIGENADDONS_AUTO_REF_INFLATE_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "r"_a) - .def("bisect", [](const S& x, size_t_type i, double ratio) + .def("bisect", [](const S& x, Index_type i, double ratio) { matlab::test_integer(i); return x.bisect(matlab::input_index(i),ratio); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_BISECT_SIZET_FLOAT_CONST, + INTERVALMATRIXBASE_EIGENADDONS_AUTO_BISECT_INDEX_FLOAT_CONST, "i"_a, "ratio"_a = 0.49) .def("bisect_largest", [](const S& x, double ratio = 0.49) { return x.bisect_largest(); }, diff --git a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp index b45faf64..30c199e1 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp @@ -42,7 +42,7 @@ py::class_ export_IntervalVector(py::module& m) exported_intervalvector_class .def(py::init( - [](size_t_type n) + [](Index_type n) { matlab::test_integer(n); return std::make_unique(n); @@ -51,7 +51,7 @@ py::class_ export_IntervalVector(py::module& m) "n"_a) .def(py::init( - [](size_t_type n, const Interval& x) + [](Index_type n, const Interval& x) { matlab::test_integer(n); return std::make_unique((int)n,x); @@ -88,12 +88,12 @@ py::class_ export_IntervalVector(py::module& m) INTERVALVECTOR_EIGENADDONS_LIST_MATRIX_INTERVALRC_DIFF_CONST_MATRIX_INTERVALRC_REF_BOOL_CONST, "y"_a, "compactness"_a = true) - .def_static("empty", [](size_t_type n) + .def_static("empty", [](Index_type n) { matlab::test_integer(n); return IntervalVector::empty(n); }, - INTERVALVECTOR_EIGENADDONS_STATIC_AUTO_EMPTY_SIZET, + INTERVALVECTOR_EIGENADDONS_STATIC_AUTO_EMPTY_INDEX, "n"_a) .def("__repr__", [](const IntervalVector& x) diff --git a/python/src/core/domains/paving/codac2_py_Paving.cpp b/python/src/core/domains/paving/codac2_py_Paving.cpp index f5692f6f..55be29b5 100644 --- a/python/src/core/domains/paving/codac2_py_Paving.cpp +++ b/python/src/core/domains/paving/codac2_py_Paving.cpp @@ -28,7 +28,7 @@ void export_paving_base(py::class_

& c) c .def("size", &Paving::size, - SIZET_PAVING_PX_SIZE_CONST) + INDEX_PAVING_PX_SIZE_CONST) .def("tree", (std::shared_ptr>(Paving::*)()) &Paving::tree, SHARED_PTR_PAVINGNODE_P_PAVING_PX_TREE) @@ -46,8 +46,8 @@ void export_Paving(py::module& m) export_paving_base(exported_paving_out); exported_paving_out - .def(py::init(), - PAVINGOUT_PAVINGOUT_SIZET) + .def(py::init(), + PAVINGOUT_PAVINGOUT_INDEX) .def(py::init(), PAVINGOUT_PAVINGOUT_CONST_INTERVALVECTOR_REF) @@ -71,8 +71,8 @@ void export_Paving(py::module& m) export_paving_base(exported_paving_inout); exported_paving_inout - .def(py::init(), - PAVINGINOUT_PAVINGINOUT_SIZET) + .def(py::init(), + PAVINGINOUT_PAVINGINOUT_INDEX) .def(py::init(), PAVINGINOUT_PAVINGINOUT_CONST_INTERVALVECTOR_REF) diff --git a/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h b/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h index 368369b9..5c006001 100644 --- a/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h +++ b/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h @@ -68,7 +68,7 @@ void export_AnalyticFunction(py::module& m, const std::string& export_name) [](const std::vector& l, const ExprWrapper& expr) { FunctionArgsList args {}; - size_t i = 0; + Index i = 0; for(const auto& li : l) { @@ -89,7 +89,7 @@ void export_AnalyticFunction(py::module& m, const std::string& export_name) ), ANALYTICFUNCTION_T_ANALYTICFUNCTION_CONST_FUNCTIONARGSLIST_REF_CONST_SHARED_PTR_ANALYTICEXPR_T_REF) .def("input_size", &AnalyticFunction::input_size, - SIZET_FUNCTIONBASE_E_INPUT_SIZE_CONST) + INDEX_FUNCTIONBASE_E_INPUT_SIZE_CONST) .def("__call__", [](const AnalyticFunction& f, const std::vector& x) { diff --git a/python/src/core/functions/analytic/codac2_py_analytic_variables.cpp b/python/src/core/functions/analytic/codac2_py_analytic_variables.cpp index 58e6c73e..ba7f2c7f 100644 --- a/python/src/core/functions/analytic/codac2_py_analytic_variables.cpp +++ b/python/src/core/functions/analytic/codac2_py_analytic_variables.cpp @@ -32,7 +32,7 @@ void export_ScalarVar(py::module& m) SCALARVAR_SCALARVAR) .def("size", &ScalarVar::size, - SIZET_SCALARVAR_SIZE_CONST) + INDEX_SCALARVAR_SIZE_CONST) .def("__pos__", [](const ScalarVar& e1) { return ScalarExpr(ScalarExpr(e1)); }, py::is_operator()) .def("__add__", [](const ScalarVar& e1, const ScalarVar& e2) { return ScalarExpr(ScalarExpr(e1) + ScalarExpr(e2)); }, py::is_operator()) @@ -60,12 +60,12 @@ void export_ScalarVar(py::module& m) py::implicitly_convertible(); } -ScalarExpr get_item(const VectorVar& v, size_t_type i) +ScalarExpr get_item(const VectorVar& v, Index_type i) { matlab::test_integer(i); i = matlab::input_index(i); - if(i < 0 || i >= static_cast(v.size())) + if(i < 0 || i >= static_cast(v.size())) throw py::index_error("index is out of range"); return ScalarExpr(std::dynamic_pointer_cast>(v[static_cast(i)]->copy())); @@ -79,37 +79,37 @@ void export_VectorVar(py::module& m) exported .def(py::init( - [](size_t_type n) + [](Index_type n) { matlab::test_integer(n); return std::make_unique(n); }), - VECTORVAR_VECTORVAR_SIZET, + VECTORVAR_VECTORVAR_INDEX, "n"_a) .def("size", &VectorVar::size, - SIZET_VECTORVAR_SIZE_CONST); + INDEX_VECTORVAR_SIZE_CONST); if(FOR_MATLAB) - exported.def("__call__", [](const VectorVar& v, size_t_type i) -> ScalarExpr + exported.def("__call__", [](const VectorVar& v, Index_type i) -> ScalarExpr { return get_item(v, i); - }, SHARED_PTR_ANALYTICEXPR_SCALAROPVALUE_VECTORVAR_OPERATORCOMPO_SIZET_CONST); + }, SHARED_PTR_ANALYTICEXPR_SCALAROPVALUE_VECTORVAR_OPERATORCOMPO_INDEX_CONST); else - exported.def("__getitem__", [](const VectorVar& v, size_t_type i) -> ScalarExpr + exported.def("__getitem__", [](const VectorVar& v, Index_type i) -> ScalarExpr { return get_item(v, i); - }, SHARED_PTR_ANALYTICEXPR_SCALAROPVALUE_VECTORVAR_OPERATORCOMPO_SIZET_CONST); + }, SHARED_PTR_ANALYTICEXPR_SCALAROPVALUE_VECTORVAR_OPERATORCOMPO_INDEX_CONST); exported - .def("subvector", [](const VectorVar& v, size_t_type i, size_t_type j) -> VectorExpr + .def("subvector", [](const VectorVar& v, Index_type i, Index_type j) -> VectorExpr { matlab::test_integer(i, j); return VectorExpr(std::dynamic_pointer_cast>( v.subvector(matlab::input_index(i),matlab::input_index(j))->copy())); - }, SHARED_PTR_ANALYTICEXPR_VECTOROPVALUE_VECTORVAR_SUBVECTOR_SIZET_SIZET_CONST) + }, SHARED_PTR_ANALYTICEXPR_VECTOROPVALUE_VECTORVAR_SUBVECTOR_INDEX_INDEX_CONST) .def("__pos__", [](const VectorVar& e1) { return VectorExpr(VectorExpr(e1)); }, py::is_operator()) .def("__add__", [](const VectorVar& e1, const VectorVar& e2) { return VectorExpr(VectorExpr(e1) + VectorExpr(e2)); }, py::is_operator()) diff --git a/python/src/core/matrices/codac2_py_Matrix.cpp b/python/src/core/matrices/codac2_py_Matrix.cpp index bc21190b..8a08b717 100644 --- a/python/src/core/matrices/codac2_py_Matrix.cpp +++ b/python/src/core/matrices/codac2_py_Matrix.cpp @@ -36,7 +36,7 @@ py::class_ export_Matrix(py::module& m) exported_matrix_class .def(py::init( - [](size_t_type r, size_t_type c) + [](Index_type r, Index_type c) { matlab::test_integer(r,c); return std::make_unique(r,c); @@ -45,7 +45,7 @@ py::class_ export_Matrix(py::module& m) "r"_a, "c"_a) .def(py::init( - [](size_t_type r, size_t_type c, double x) + [](Index_type r, Index_type c, double x) { matlab::test_integer(r,c); return std::make_unique((int)r,(int)c,x); diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index ec8b0d02..2fd913ae 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -87,7 +87,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) return x(matlab::input_index(i), matlab::input_index(j)); }, py::return_value_policy::reference_internal, - BASE_EIGENADDONS_CONST_SCALAR_REF_OPERATORCALL_SIZET_SIZET_CONST) + BASE_EIGENADDONS_CONST_SCALAR_REF_OPERATORCALL_INDEX_INDEX_CONST) .def("__setitem__", [](S& x, const py::tuple& ij, const T& a) { @@ -99,7 +99,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) x(matlab::input_index(i), matlab::input_index(j)) = a; }, - BASE_EIGENADDONS_SCALAR_REF_OPERATORCALL_SIZET_SIZET) + BASE_EIGENADDONS_SCALAR_REF_OPERATORCALL_INDEX_INDEX) ; } @@ -148,7 +148,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) pyclass - .def("block", [](S& x, size_t_type i, size_t_type j, size_t_type p, size_t_type q) -> Eigen::Block + .def("block", [](S& x, Index_type i, Index_type j, Index_type p, Index_type q) -> Eigen::Block { matlab::test_integer(i,j); matlab::test_integer(p,q); @@ -157,28 +157,28 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) py::keep_alive<0,1>(), DOC_TO_BE_DEFINED) - .def("col", [](S& x, size_t_type i) -> Eigen::Matrix + .def("col", [](S& x, Index_type i) -> Eigen::Matrix { matlab::test_integer(i); return x.col(matlab::input_index(i)).eval(); }, DOC_TO_BE_DEFINED) - .def("row", [](S& x, size_t_type i) -> Eigen::Matrix + .def("row", [](S& x, Index_type i) -> Eigen::Matrix { matlab::test_integer(i); return x.row(matlab::input_index(i)).eval(); }, DOC_TO_BE_DEFINED) - .def("__call__", [](S& x, size_t_type i, size_t_type j) -> T& + .def("__call__", [](S& x, Index_type i, Index_type j) -> T& { matlab::test_integer(i,j); return x(matlab::input_index(i),matlab::input_index(j)); }, py::return_value_policy::reference_internal, - BASE_EIGENADDONS_SCALAR_REF_OPERATORCALL_SIZET_SIZET) + BASE_EIGENADDONS_SCALAR_REF_OPERATORCALL_INDEX_INDEX) - .def("resize", [](S& x, size_t_type nb_rows, size_t_type nb_cols) + .def("resize", [](S& x, Index_type nb_rows, Index_type nb_cols) { matlab::test_integer(nb_rows, nb_cols); x.resize(nb_rows, nb_cols); @@ -186,36 +186,36 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) DOC_TO_BE_DEFINED, "nb_rows"_a, "nb_cols"_a) - .def("resize_save_values", [](S& x, size_t_type nb_rows, size_t_type nb_cols) + .def("resize_save_values", [](S& x, Index_type nb_rows, Index_type nb_cols) { matlab::test_integer(nb_rows, nb_cols); x.resize_save_values(nb_rows, nb_cols); }, - MATRIXBASE_EIGENADDONS_VOID_RESIZE_SAVE_VALUES_SIZET_SIZET, + MATRIXBASE_EIGENADDONS_VOID_RESIZE_SAVE_VALUES_INDEX_INDEX, "nb_rows"_a, "nb_cols"_a) - .def_static("zeros", [](size_t_type r, size_t_type c) + .def_static("zeros", [](Index_type r, Index_type c) { matlab::test_integer(r,c); return S::zeros(r,c); }, - MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ZEROS_SIZET_SIZET, + MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ZEROS_INDEX_INDEX, "r"_a, "c"_a) - .def_static("ones", [](size_t_type r, size_t_type c) + .def_static("ones", [](Index_type r, Index_type c) { matlab::test_integer(r,c); return S::ones(r,c); }, - MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ONES_SIZET_SIZET, + MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ONES_INDEX_INDEX, "r"_a, "c"_a) - .def_static("eye", [](size_t_type r, size_t_type c) + .def_static("eye", [](Index_type r, Index_type c) { matlab::test_integer(r,c); return S::ones(r,c); }, - MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_EYE_SIZET_SIZET, + MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_EYE_INDEX_INDEX, "r"_a, "c"_a) ; diff --git a/python/src/core/matrices/codac2_py_Vector.cpp b/python/src/core/matrices/codac2_py_Vector.cpp index d47f1530..d305e755 100644 --- a/python/src/core/matrices/codac2_py_Vector.cpp +++ b/python/src/core/matrices/codac2_py_Vector.cpp @@ -39,7 +39,7 @@ py::class_ export_Vector(py::module& m) exported_vector_class .def(py::init( - [](size_t_type n) + [](Index_type n) { matlab::test_integer(n); return std::make_unique(n); @@ -65,13 +65,13 @@ py::class_ export_Vector(py::module& m) { return matlab::output_index(x.min_coeff_index()); }, - VECTOR_EIGENADDONS_SIZET_MIN_COEFF_INDEX_CONST) + VECTOR_EIGENADDONS_INDEX_MIN_COEFF_INDEX_CONST) .def("max_coeff_index", [](const Vector& x) { return matlab::output_index(x.max_coeff_index()); }, - VECTOR_EIGENADDONS_SIZET_MAX_COEFF_INDEX_CONST) + VECTOR_EIGENADDONS_INDEX_MAX_COEFF_INDEX_CONST) .def("__repr__", [](const Vector& x) { diff --git a/python/src/core/matrices/codac2_py_VectorBase.h b/python/src/core/matrices/codac2_py_VectorBase.h index 92972d70..1763e498 100644 --- a/python/src/core/matrices/codac2_py_VectorBase.h +++ b/python/src/core/matrices/codac2_py_VectorBase.h @@ -31,29 +31,29 @@ void export_VectorBase(py::module& m, py::class_& pyclass) pyclass - .def("__getitem__", [](const S& x, size_t_type index) -> const T& + .def("__getitem__", [](const S& x, Index_type index) -> const T& { matlab::test_integer(index); return x[matlab::input_index(index)]; }, py::return_value_policy::reference_internal, - VECTORBASE_EIGENADDONS_CONST_SCALAR_REF_OPERATORCOMPO_SIZET_CONST) + VECTORBASE_EIGENADDONS_CONST_SCALAR_REF_OPERATORCOMPO_INDEX_CONST) - .def("__setitem__", [](S& x, size_t_type index, const T& a) + .def("__setitem__", [](S& x, Index_type index, const T& a) { matlab::test_integer(index); x[matlab::input_index(index)] = a; }, - VECTORBASE_EIGENADDONS_SCALAR_REF_OPERATORCOMPO_SIZET) + VECTORBASE_EIGENADDONS_SCALAR_REF_OPERATORCOMPO_INDEX) - .def("subvector", [](const S& x, size_t_type start_id, size_t_type end_id) -> S + .def("subvector", [](const S& x, Index_type start_id, Index_type end_id) -> S { matlab::test_integer(start_id, end_id); return x.subvector(matlab::input_index(start_id), matlab::input_index(end_id)); }, - VECTORBASE_EIGENADDONS_AUTO_SUBVECTOR_SIZET_SIZET_CONST, + VECTORBASE_EIGENADDONS_AUTO_SUBVECTOR_INDEX_INDEX_CONST, "start_id"_a, "end_id"_a) - .def("resize", [](S& x, size_t_type n) + .def("resize", [](S& x, Index_type n) { matlab::test_integer(n); x.resize(n); @@ -61,36 +61,36 @@ void export_VectorBase(py::module& m, py::class_& pyclass) DOC_TO_BE_DEFINED, "n"_a) - .def("resize_save_values", [](S& x, size_t_type n) + .def("resize_save_values", [](S& x, Index_type n) { matlab::test_integer(n); x.resize_save_values(n); }, - VECTORBASE_EIGENADDONS_VOID_RESIZE_SAVE_VALUES_SIZET, + VECTORBASE_EIGENADDONS_VOID_RESIZE_SAVE_VALUES_INDEX, "n"_a) - .def("put", [](S& x, size_t_type start_id, const S& x1) + .def("put", [](S& x, Index_type start_id, const S& x1) { matlab::test_integer(start_id); x.put(matlab::input_index(start_id), x1); }, - VECTORBASE_EIGENADDONS_VOID_PUT_SIZET_CONST_MATRIX_SCALARRC_REF, + VECTORBASE_EIGENADDONS_VOID_PUT_INDEX_CONST_MATRIX_SCALARRC_REF, "start_id"_a, "x"_a) - .def_static("zeros", [](size_t_type n) + .def_static("zeros", [](Index_type n) { matlab::test_integer(n); return S::zeros(n); }, - VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ZEROS_SIZET, + VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ZEROS_INDEX, "n"_a) - .def_static("ones", [](size_t_type n) + .def_static("ones", [](Index_type n) { matlab::test_integer(n); return S::ones(n); }, - VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ONES_SIZET, + VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ONES_INDEX, "n"_a) .def("__repr__", [](const S& x) diff --git a/python/src/core/separators/codac2_py_Sep.cpp b/python/src/core/separators/codac2_py_Sep.cpp index 9cc7a75d..81eefac6 100644 --- a/python/src/core/separators/codac2_py_Sep.cpp +++ b/python/src/core/separators/codac2_py_Sep.cpp @@ -55,11 +55,11 @@ py::class_ export_Sep(py::module& m) py::class_ py_sep(m, "SepBase"); py_sep - .def(py::init(), - SEPBASE_SEPBASE_SIZET) + .def(py::init(), + SEPBASE_SEPBASE_INDEX) .def("size", &SepBase::size, - SIZET_SEPBASE_SIZE_CONST) + INDEX_SEPBASE_SIZE_CONST) .def("copy", [](SepBase& s) { diff --git a/python/src/core/separators/codac2_py_Sep.h b/python/src/core/separators/codac2_py_Sep.h index 51cf4a23..b89a3670 100644 --- a/python/src/core/separators/codac2_py_Sep.h +++ b/python/src/core/separators/codac2_py_Sep.h @@ -26,7 +26,7 @@ class pySep : public SepBase { public: - pySep(size_t_type n) + pySep(Index_type n) : SepBase(n) { matlab::test_integer(n); diff --git a/python/src/core/separators/codac2_py_SepProj.cpp b/python/src/core/separators/codac2_py_SepProj.cpp index 313d5a09..bfee8d87 100644 --- a/python/src/core/separators/codac2_py_SepProj.cpp +++ b/python/src/core/separators/codac2_py_SepProj.cpp @@ -19,19 +19,19 @@ using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -vector test_and_convert(const vector& indices) +vector test_and_convert(const vector& indices) { #if FOR_MATLAB - vector indices_size_t(indices.size()); + vector indices_Index(indices.size()); - for(size_t i = 0 ; i < indices.size() ; i++) + for(Index i = 0 ; i < indices.size() ; i++) { matlab::test_integer(indices[i]); - indices_size_t[i] = matlab::input_index(indices[i]); + indices_Index[i] = matlab::input_index(indices[i]); } - #else // same types: size_t_type == size_t + #else // same types: Index_type == Index return indices; @@ -44,19 +44,19 @@ void export_SepProj(py::module& m, py::class_& pysep) exported .def(py::init( - [](const SepBase& s, vector proj_indices, double default_eps) + [](const SepBase& s, vector proj_indices, double default_eps) { return make_unique(s.copy(), test_and_convert(proj_indices), default_eps); }), - SEPPROJ_SEPPROJ_CONST_S_REF_CONST_VECTOR_SIZET_REF_DOUBLE, + SEPPROJ_SEPPROJ_CONST_S_REF_CONST_VECTOR_INDEX_REF_DOUBLE, "s"_a, "proj_indices"_a, "default_eps"_a=0.01) .def(py::init( - [](const SepBase& s, vector proj_indices, const IntervalVector& y, double default_eps) + [](const SepBase& s, vector proj_indices, const IntervalVector& y, double default_eps) { return make_unique(s.copy(), test_and_convert(proj_indices), y, default_eps); }), - SEPPROJ_SEPPROJ_CONST_S_REF_CONST_VECTOR_SIZET_REF_CONST_INTERVALVECTOR_REF_DOUBLE, + SEPPROJ_SEPPROJ_CONST_S_REF_CONST_VECTOR_INDEX_REF_CONST_INTERVALVECTOR_REF_DOUBLE, "s"_a, "proj_indices"_a, "y"_a, "default_eps"_a=0.01) .def("separate", (BoxPair(SepProj::*)(const IntervalVector&) const) &SepProj::separate, diff --git a/python/src/graphics/figures/codac2_py_Figure2D.cpp b/python/src/graphics/figures/codac2_py_Figure2D.cpp index d06f588e..d72d33c1 100644 --- a/python/src/graphics/figures/codac2_py_Figure2D.cpp +++ b/python/src/graphics/figures/codac2_py_Figure2D.cpp @@ -36,12 +36,12 @@ void export_Figure2D(py::module& m) .def_readwrite("label", &FigureAxis::label) ; - m.def("axis", [](size_t_type n, const Interval& limits, const std::string& label) + m.def("axis", [](Index_type n, const Interval& limits, const std::string& label) { matlab::test_integer(n); return axis(matlab::input_index(n), limits, label); }, - FIGUREAXIS_AXIS_SIZET_CONST_INTERVAL_REF_CONST_STRING_REF, + FIGUREAXIS_AXIS_INDEX_CONST_INTERVAL_REF_CONST_STRING_REF, "dim_id"_a, "limits"_a, "label"_a=""); py::class_ /* due to enable_shared_from_this */> @@ -56,7 +56,7 @@ void export_Figure2D(py::module& m) CONST_STRING_REF_FIGURE2D_NAME_CONST) .def("size", &Figure2D::size, - SIZET_FIGURE2D_SIZE_CONST) + INDEX_FIGURE2D_SIZE_CONST) .def("axes", &Figure2D::axes, CONST_VECTOR_FIGUREAXIS_REF_FIGURE2D_AXES_CONST) diff --git a/src/core/3rd/codac2_ibex.cpp b/src/core/3rd/codac2_ibex.cpp index 6261f9d4..338b5fa5 100644 --- a/src/core/3rd/codac2_ibex.cpp +++ b/src/core/3rd/codac2_ibex.cpp @@ -32,7 +32,7 @@ namespace codac2 #define cast_vector(OutputType,convert) \ \ OutputType x_(x.size()); \ - for(size_t i = 0 ; i < (size_t)x.size() ; i++) \ + for(Index i = 0 ; i < (Index)x.size() ; i++) \ x_[i] = convert(x[i]); \ return x_; \ @@ -59,8 +59,8 @@ namespace codac2 #define cast_matrix(OutputType,convert_f,output_ij,input_ij,rows_,cols_) \ \ OutputType x_(x.rows_(), x.cols_()); \ - for(size_t i = 0 ; i < (size_t)x.rows_() ; i++) \ - for(size_t j = 0 ; j < (size_t)x.cols_() ; j++) \ + for(Index i = 0 ; i < (Index)x.rows_() ; i++) \ + for(Index j = 0 ; j < (Index)x.cols_() ; j++) \ output_ij = convert_f(input_ij); \ return x_; \ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index cc43a918..69ffe13d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -139,6 +139,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/tools/codac2_Approx.h ${CMAKE_CURRENT_SOURCE_DIR}/tools/codac2_assert.h ${CMAKE_CURRENT_SOURCE_DIR}/tools/codac2_Collection.h + ${CMAKE_CURRENT_SOURCE_DIR}/tools/codac2_Index.h ${CMAKE_CURRENT_SOURCE_DIR}/tools/codac2_math.h ${CMAKE_CURRENT_SOURCE_DIR}/tools/codac2_object_file_format.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tools/codac2_object_file_format.h diff --git a/src/core/actions/codac2_OctaSym.cpp b/src/core/actions/codac2_OctaSym.cpp index b37ab370..f1e6c6f9 100644 --- a/src/core/actions/codac2_OctaSym.cpp +++ b/src/core/actions/codac2_OctaSym.cpp @@ -20,7 +20,7 @@ OctaSym::OctaSym(const vector& s) { for(const auto& i : s) { - assert_release((size_t)std::abs(i) > 0 && (size_t)std::abs(i) <= size()); + assert_release(std::abs(i) > 0 && std::abs(i) <= size()); } } diff --git a/src/core/actions/codac2_OctaSym.h b/src/core/actions/codac2_OctaSym.h index da2618be..a649a909 100644 --- a/src/core/actions/codac2_OctaSym.h +++ b/src/core/actions/codac2_OctaSym.h @@ -50,7 +50,7 @@ namespace codac2 template Mat operator()(const Mat& x) const { - assert_release((size_t)x.size() == size()); + assert_release(x.size() == (Index)size()); Mat x_(size()); for(size_t i = 0 ; i < size() ; i++) x_[i] = _sign((*this)[i])*x[std::abs((*this)[i])-1]; diff --git a/src/core/contractors/codac2_Ctc.h b/src/core/contractors/codac2_Ctc.h index 4ca801a5..d34e8552 100644 --- a/src/core/contractors/codac2_Ctc.h +++ b/src/core/contractors/codac2_Ctc.h @@ -11,6 +11,7 @@ #include #include +#include "codac2_Index.h" #include "codac2_assert.h" namespace codac2 @@ -41,13 +42,13 @@ namespace codac2 using ContractedType = X; - CtcBase(size_t n) + CtcBase(Index n) : _n(n) { assert(n > 0); } - size_t size() const + Index size() const { return _n; } @@ -58,7 +59,7 @@ namespace codac2 protected: - const size_t _n; + const Index _n; }; template @@ -66,7 +67,7 @@ namespace codac2 { public: - Ctc(size_t n) + Ctc(Index n) : CtcBase(n) { } diff --git a/src/core/contractors/codac2_CtcAction.h b/src/core/contractors/codac2_CtcAction.h index 64905c69..96658a25 100644 --- a/src/core/contractors/codac2_CtcAction.h +++ b/src/core/contractors/codac2_CtcAction.h @@ -26,7 +26,7 @@ namespace codac2 CtcAction(const C& c, const OctaSym& a) : Ctc(a.size()), _ctc(c), _s(a), __s(a.invert()) { - assert_release(size_of(c) == a.size()); + assert_release(size_of(c) == (Index)a.size()); } void contract(IntervalVector& x) const; diff --git a/src/core/contractors/codac2_CtcCartProd.h b/src/core/contractors/codac2_CtcCartProd.h index 49ffe62a..f88e3323 100644 --- a/src/core/contractors/codac2_CtcCartProd.h +++ b/src/core/contractors/codac2_CtcCartProd.h @@ -23,7 +23,7 @@ namespace codac2 CtcCartProd(const Collection>& ctcs) : Ctc([ctcs] { - size_t n = 0; + Index n = 0; for(const auto& ci : ctcs) n += ci->size(); return n; @@ -46,7 +46,7 @@ namespace codac2 { assert_release(x.size() == this->size()); - size_t i = 0; + Index i = 0; for(const auto& ci : _ctcs) { IntervalVector xi = x.subvector(i,i+ci->size()-1); diff --git a/src/core/contractors/codac2_CtcCtcBoundary.cpp b/src/core/contractors/codac2_CtcCtcBoundary.cpp index ae8fba92..a291b813 100644 --- a/src/core/contractors/codac2_CtcCtcBoundary.cpp +++ b/src/core/contractors/codac2_CtcCtcBoundary.cpp @@ -16,7 +16,7 @@ void CtcCtcBoundary::contract(IntervalVector& x) const { assert_release(x.size() == this->size()); - size_t attempt_nb = 5; + Index attempt_nb = 5; IntervalVector prev_x(x); _ctc_boundary.front().contract(x); @@ -27,7 +27,7 @@ void CtcCtcBoundary::contract(IntervalVector& x) const Vector m = b.mid(); // first try: midpoint of the box BoolInterval d; - size_t k = 0; + Index k = 0; do { diff --git a/src/core/contractors/codac2_CtcEmpty.cpp b/src/core/contractors/codac2_CtcEmpty.cpp index 3ed1e9c9..57718952 100644 --- a/src/core/contractors/codac2_CtcEmpty.cpp +++ b/src/core/contractors/codac2_CtcEmpty.cpp @@ -12,7 +12,7 @@ using namespace std; using namespace codac2; -CtcEmpty::CtcEmpty(size_t n) +CtcEmpty::CtcEmpty(Index n) : Ctc(n) { } diff --git a/src/core/contractors/codac2_CtcEmpty.h b/src/core/contractors/codac2_CtcEmpty.h index 11212f88..7f1484da 100644 --- a/src/core/contractors/codac2_CtcEmpty.h +++ b/src/core/contractors/codac2_CtcEmpty.h @@ -18,7 +18,7 @@ namespace codac2 { public: - CtcEmpty(size_t n); + CtcEmpty(Index n); void contract(IntervalVector& x) const; }; diff --git a/src/core/contractors/codac2_CtcIdentity.cpp b/src/core/contractors/codac2_CtcIdentity.cpp index e506819a..90a901f2 100644 --- a/src/core/contractors/codac2_CtcIdentity.cpp +++ b/src/core/contractors/codac2_CtcIdentity.cpp @@ -12,7 +12,7 @@ using namespace std; using namespace codac2; -CtcIdentity::CtcIdentity(size_t n) +CtcIdentity::CtcIdentity(Index n) : Ctc(n) { } diff --git a/src/core/contractors/codac2_CtcIdentity.h b/src/core/contractors/codac2_CtcIdentity.h index cdb18973..f08d1616 100644 --- a/src/core/contractors/codac2_CtcIdentity.h +++ b/src/core/contractors/codac2_CtcIdentity.h @@ -18,7 +18,7 @@ namespace codac2 { public: - CtcIdentity(size_t n); + CtcIdentity(Index n); void contract(IntervalVector& x) const; }; diff --git a/src/core/contractors/codac2_CtcInter.h b/src/core/contractors/codac2_CtcInter.h index a8718698..28fc0f95 100644 --- a/src/core/contractors/codac2_CtcInter.h +++ b/src/core/contractors/codac2_CtcInter.h @@ -21,7 +21,7 @@ namespace codac2 { public: - explicit CtcInter(size_t n) + explicit CtcInter(Index n) : Ctc,X>(n) { if constexpr(std::is_same_v) diff --git a/src/core/contractors/codac2_CtcProj.h b/src/core/contractors/codac2_CtcProj.h index 8bca8538..00dff8a3 100644 --- a/src/core/contractors/codac2_CtcProj.h +++ b/src/core/contractors/codac2_CtcProj.h @@ -22,19 +22,19 @@ namespace codac2 template requires IsCtcBaseOrPtr - CtcProj(const C& c, const std::vector& proj_indices, double default_eps = 0.01) + CtcProj(const C& c, const std::vector& proj_indices, double default_eps = 0.01) : CtcProj(c, proj_indices, IntervalVector(size_of(c)-proj_indices.size()), default_eps) { } template requires IsCtcBaseOrPtr - CtcProj(const C& c, const std::vector& proj_indices, const IntervalVector& y, double default_eps = 0.01) + CtcProj(const C& c, const std::vector& proj_indices, const IntervalVector& y, double default_eps = 0.01) : Ctc(proj_indices.size()), ProjBase(proj_indices,y,default_eps), _ctc(c) { - assert_release(_y.size() == size_of(c)-_xi.size()); + assert_release(_y.size() == size_of(c)-(Index)_xi.size()); assert_release(*min_element(_xi.begin(),_xi.end()) >= 0); assert_release(*max_element(_xi.begin(),_xi.end()) < size_of(c)); - assert_release(size_of(c) >= _xi.size() && "cannot compute a projection of a set into a superset"); + assert_release(size_of(c) >= (Index)_xi.size() && "cannot compute a projection of a set into a superset"); assert_release(default_eps > 0.); } diff --git a/src/core/contractors/codac2_CtcUnion.h b/src/core/contractors/codac2_CtcUnion.h index 2deff192..91dfdacc 100644 --- a/src/core/contractors/codac2_CtcUnion.h +++ b/src/core/contractors/codac2_CtcUnion.h @@ -21,7 +21,7 @@ namespace codac2 { public: - explicit CtcUnion(size_t n) + explicit CtcUnion(Index n) : Ctc,X>(n) { if constexpr(std::is_same_v) diff --git a/src/core/contractors/codac2_directed_ctc.cpp b/src/core/contractors/codac2_directed_ctc.cpp index e65af924..87d68b98 100644 --- a/src/core/contractors/codac2_directed_ctc.cpp +++ b/src/core/contractors/codac2_directed_ctc.cpp @@ -119,7 +119,7 @@ using namespace codac2; void AddOp::bwd(const IntervalVector& y, IntervalVector& x1, IntervalVector& x2) { assert(y.size() == x1.size() && y.size() == x2.size()); - for(size_t i = 0 ; i < y.size() ; i++) + for(Index i = 0 ; i < y.size() ; i++) AddOp::bwd(y[i], x1[i], x2[i]); } @@ -142,7 +142,7 @@ using namespace codac2; void AddOp::bwd(const IntervalMatrix& y, IntervalMatrix& x1, IntervalMatrix& x2) { assert(y.size() == x1.size() && y.size() == x2.size()); - for(size_t i = 0 ; i < y.size() ; i++) + for(Index i = 0 ; i < y.size() ; i++) AddOp::bwd(*(y.data()+i), *(x1.data()+i), *(x2.data()+i)); } @@ -188,7 +188,7 @@ using namespace codac2; void SubOp::bwd(const IntervalVector& y, IntervalVector& x1) { assert(y.size() == x1.size()); - for(size_t i = 0 ; i < y.size() ; i++) + for(Index i = 0 ; i < y.size() ; i++) bwd(y[i], x1[i]); } @@ -210,7 +210,7 @@ using namespace codac2; void SubOp::bwd(const IntervalMatrix& y, IntervalMatrix& x1) { assert(y.size() == x1.size()); - for(size_t i = 0 ; i < y.size() ; i++) + for(Index i = 0 ; i < y.size() ; i++) SubOp::bwd(*(y.data()+i), *(x1.data()+i)); } @@ -258,7 +258,7 @@ using namespace codac2; void SubOp::bwd(const IntervalVector& y, IntervalVector& x1, IntervalVector& x2) { assert(y.size() == x1.size() && y.size() == x2.size()); - for(size_t i = 0 ; i < y.size() ; i++) + for(Index i = 0 ; i < y.size() ; i++) bwd(y[i], x1[i], x2[i]); } @@ -282,7 +282,7 @@ using namespace codac2; void SubOp::bwd(const IntervalMatrix& y, IntervalMatrix& x1, IntervalMatrix& x2) { assert(y.size() == x1.size() && y.size() == x2.size()); - for(size_t i = 0 ; i < y.size() ; i++) + for(Index i = 0 ; i < y.size() ; i++) SubOp::bwd(*(y.data()+i), *(x1.data()+i), *(x2.data()+i)); } @@ -300,7 +300,7 @@ using namespace codac2; assert(x1.da.rows() == x2.da.rows() && x1.da.cols() == x2.da.cols()); IntervalMatrix d(1,x1.da.cols()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = x1.da(0,i)*x2.a + x1.a*x2.da(0,i); return { @@ -328,8 +328,8 @@ using namespace codac2; assert(x2.a.size() == x2.da.rows()); IntervalMatrix d(x2.da.rows(),x2.da.cols()); - for(size_t i = 0 ; i < d.rows() ; i++) - for(size_t j = 0 ; j < d.cols() ; j++) + for(Index i = 0 ; i < d.rows() ; i++) + for(Index j = 0 ; j < d.cols() ; j++) d(i,j) = x1.da(0,j)*x2.a[i]+x1.a*x2.da(i,j); return { @@ -343,7 +343,7 @@ using namespace codac2; void MulOp::bwd(const IntervalVector& y, Interval& x1, IntervalVector& x2) { assert(y.size() == x2.size()); - for(size_t i = 0 ; i < x2.size() ; i++) + for(Index i = 0 ; i < x2.size() ; i++) bwd_mul(y[i], x1, x2[i]); } @@ -397,18 +397,18 @@ using namespace codac2; else*/ { IntervalMatrix Q = gauss_jordan(x1.mid()); - IntervalVector b_tilde = Q*y; - IntervalMatrix A_tilde = Q*x1; // should be a tree matrix + auto b_tilde = Q*y; + auto A_tilde = Q*x1; // should be a tree matrix for(int a = 0 ; a < 1 ; a++) { - for(size_t i = 0 ; i < x2.size() ; i++) + for(Index i = 0 ; i < x2.size() ; i++) { - for(size_t k = 0 ; k < b_tilde.size() ; k++) + for(Index k = 0 ; k < b_tilde.size() ; k++) { Interval u = b_tilde[k]; - for(size_t j = 0 ; j < x2.size() ; j++) + for(Index j = 0 ; j < x2.size() ; j++) if(i != j) u -= x2[j]*A_tilde(k,j); @@ -435,7 +435,7 @@ using namespace codac2; assert(x1.da.size() == x2.da.size()); IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = (x1.da(0,i)*x2.a-x1.a*x2.da(0,i))/sqr(x2.a); return { @@ -474,7 +474,7 @@ using namespace codac2; void DivOp::bwd(const IntervalVector& y, IntervalVector& x1, Interval& x2) { assert(x1.size() == y.size()); - for(size_t i = 0 ; i < x1.size() ; i++) + for(Index i = 0 ; i < x1.size() ; i++) bwd_div(y[i], x1[i], x2); } @@ -489,7 +489,7 @@ using namespace codac2; ScalarOpValue PowOp::fwd(const ScalarOpValue& x1, const ScalarOpValue& x2) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = x2.a*x1.da(0,i)*pow(x1.a,x2.a-1.); return { @@ -518,7 +518,7 @@ using namespace codac2; assert(x1.da.rows() == 1); IntervalMatrix d(1,x1.da.cols()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = 2.*x1.a*x1.da(0,i); return { @@ -545,7 +545,7 @@ using namespace codac2; ScalarOpValue SqrtOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = x1.da(0,i)/(2.*sqrt(x1.a)); return { @@ -574,7 +574,7 @@ using namespace codac2; ScalarOpValue ExpOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = x1.da(0,i)*exp(x1.a); return { @@ -601,7 +601,7 @@ using namespace codac2; ScalarOpValue LogOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = x1.da(0,i)/x1.a; return { @@ -630,7 +630,7 @@ using namespace codac2; ScalarOpValue CosOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = -sin(x1.a)*x1.da(0,i); return { @@ -657,7 +657,7 @@ using namespace codac2; ScalarOpValue SinOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = cos(x1.a)*x1.da(0,i); return { @@ -684,7 +684,7 @@ using namespace codac2; ScalarOpValue TanOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = x1.da(0,i)/sqr(cos(x1.a)); return { @@ -711,7 +711,7 @@ using namespace codac2; ScalarOpValue AcosOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = -x1.da(0,i)/sqrt(1.-sqr(x1.a)); return { @@ -740,7 +740,7 @@ using namespace codac2; ScalarOpValue AsinOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = x1.da(0,i)/sqrt(1.-sqr(x1.a)); return { @@ -769,7 +769,7 @@ using namespace codac2; ScalarOpValue AtanOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = x1.da(0,i)/(1.+sqr(x1.a)); return { @@ -799,7 +799,7 @@ using namespace codac2; assert(x1.da.rows() == x2.da.rows() && x1.da.cols() == x2.da.cols()); IntervalMatrix d(1,x1.da.cols()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = (-x1.a*x2.da(0,i)/(sqr(x2.a)+sqr(x1.a)))+(x2.a*x1.da(0,i)/(sqr(x2.a)+sqr(x1.a))); return { @@ -827,7 +827,7 @@ using namespace codac2; ScalarOpValue CoshOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = sinh(x1.a)*x1.da(0,i); return { @@ -854,7 +854,7 @@ using namespace codac2; ScalarOpValue SinhOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = cosh(x1.a)*x1.da(0,i); return { @@ -881,7 +881,7 @@ using namespace codac2; ScalarOpValue TanhOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = x1.da(0,i)/sqr(cosh(x1.a)); return { @@ -908,7 +908,7 @@ using namespace codac2; ScalarOpValue AbsOp::fwd(const ScalarOpValue& x1) { IntervalMatrix d(1,x1.da.size()); - for(size_t i = 0 ; i < d.size() ; i++) + for(Index i = 0 ; i < d.size() ; i++) d(0,i) = (x1.a/abs(x1.a))*x1.da(0,i); return { @@ -927,13 +927,13 @@ using namespace codac2; // ComponentOp - Interval ComponentOp::fwd(const IntervalVector& x1, size_t i) + Interval ComponentOp::fwd(const IntervalVector& x1, Index i) { assert(i >= 0 && i < x1.size()); return x1[i]; } - ScalarOpValue ComponentOp::fwd(const VectorOpValue& x1, size_t i) + ScalarOpValue ComponentOp::fwd(const VectorOpValue& x1, Index i) { assert(i >= 0 && i < x1.a.rows()); return { @@ -944,7 +944,7 @@ using namespace codac2; }; } - void ComponentOp::bwd(const Interval& y, IntervalVector& x1, size_t i) + void ComponentOp::bwd(const Interval& y, IntervalVector& x1, Index i) { assert(i >= 0 && i < x1.size()); x1[i] &= y; @@ -953,13 +953,13 @@ using namespace codac2; // SubvectorOp - IntervalVector SubvectorOp::fwd(const IntervalVector& x1, size_t i, size_t j) + IntervalVector SubvectorOp::fwd(const IntervalVector& x1, Index i, Index j) { assert(i >= 0 && i < x1.size() && j >= i && j < x1.size()); return x1.subvector(i,j); } - VectorOpValue SubvectorOp::fwd(const VectorOpValue& x1, size_t i, size_t j) + VectorOpValue SubvectorOp::fwd(const VectorOpValue& x1, Index i, Index j) { assert(i >= 0 && i < x1.a.rows() && j >= i && j < x1.a.rows()); return { @@ -970,18 +970,18 @@ using namespace codac2; }; } - void SubvectorOp::bwd(const IntervalVector& y, IntervalVector& x1, size_t i, size_t j) + void SubvectorOp::bwd(const IntervalVector& y, IntervalVector& x1, Index i, Index j) { assert(i >= 0 && i < x1.size() && j >= i && j < x1.size()); assert(j-i < y.size()); - for(size_t k = 0 ; k < j-i+1 ; k++) + for(Index k = 0 ; k < j-i+1 ; k++) x1[i+k] &= y[k]; } // MatrixOp - void MatrixOp::fwd_i(IntervalMatrix& m, const IntervalVector& x, size_t i) + void MatrixOp::fwd_i(IntervalMatrix& m, const IntervalVector& x, Index i) { assert(i >= 0 && i < m.cols()); m.resize(x.size(),m.cols()); diff --git a/src/core/contractors/codac2_directed_ctc.h b/src/core/contractors/codac2_directed_ctc.h index 1d6ec7b6..66c65ac7 100644 --- a/src/core/contractors/codac2_directed_ctc.h +++ b/src/core/contractors/codac2_directed_ctc.h @@ -217,16 +217,16 @@ namespace codac2 struct ComponentOp { - static Interval fwd(const IntervalVector& x1, size_t i); - static ScalarOpValue fwd(const VectorOpValue& x1, size_t i); - static void bwd(const Interval& y, IntervalVector& x1, size_t i); + static Interval fwd(const IntervalVector& x1, Index i); + static ScalarOpValue fwd(const VectorOpValue& x1, Index i); + static void bwd(const Interval& y, IntervalVector& x1, Index i); }; struct SubvectorOp { - static IntervalVector fwd(const IntervalVector& x1, size_t i, size_t j); - static VectorOpValue fwd(const VectorOpValue& x1, size_t i, size_t j); - static void bwd(const IntervalVector& y, IntervalVector& x1, size_t i, size_t j); + static IntervalVector fwd(const IntervalVector& x1, Index i, Index j); + static VectorOpValue fwd(const VectorOpValue& x1, Index i, Index j); + static void bwd(const IntervalVector& y, IntervalVector& x1, Index i, Index j); }; struct VectorOp @@ -243,7 +243,7 @@ namespace codac2 static VectorOpValue fwd(const X&... x) { IntervalMatrix d(sizeof...(X),std::get<0>(std::tie(x...)).da.cols()); - size_t i = 0; + Index i = 0; ((d.row(i++) = x.da), ...); bool def_domain = true; @@ -261,14 +261,14 @@ namespace codac2 requires (std::is_base_of_v && ...) static void bwd(const IntervalVector& y, X&... x) { - size_t i = 0; + Index i = 0; ((x &= y[i++]), ...); } }; struct MatrixOp { - static void fwd_i(IntervalMatrix& m, const IntervalVector& x, size_t i); + static void fwd_i(IntervalMatrix& m, const IntervalVector& x, Index i); template requires (std::is_base_of_v && ...) @@ -276,7 +276,7 @@ namespace codac2 { throw std::runtime_error("MatrixOp not fully implemented yet"); IntervalMatrix m(1, sizeof...(X)); - size_t i = 0; + Index i = 0; (MatrixOp::fwd_i(m, x, i++), ...); return m; } @@ -299,7 +299,7 @@ namespace codac2 static void bwd(const IntervalMatrix& y, X&... x) { throw std::runtime_error("MatrixOp not fully implemented yet"); - size_t i = 0; + Index i = 0; ((x &= y.col(i++)), ...); } }; diff --git a/src/core/contractors/codac2_linear_ctc.cpp b/src/core/contractors/codac2_linear_ctc.cpp index fee447d9..30415f1c 100644 --- a/src/core/contractors/codac2_linear_ctc.cpp +++ b/src/core/contractors/codac2_linear_ctc.cpp @@ -20,24 +20,24 @@ void CtcGaussElim::contract(IntervalMatrix& A, IntervalVector& x, IntervalVector IntervalMatrix A_ = A; IntervalVector b_ = b; - size_t n = A_.rows(); - for(size_t i = 0 ; i < n ; i++) + Index n = A_.rows(); + for(Index i = 0 ; i < n ; i++) if(A_(i,i).contains(0.)) return; - for(size_t i = 0 ; i < n-1 ; i++) - for(size_t j = i+1 ; j < n ; j++) + for(Index i = 0 ; i < n-1 ; i++) + for(Index j = i+1 ; j < n ; j++) { Interval aj = A_(j,i)/A_(i,i); b_[j] -= aj*b_[i]; - for(size_t k = i+1 ; k < n ; k++) + for(Index k = i+1 ; k < n ; k++) A_(j,k) -= aj*A_(i,k); } for(int i = n-1 ; i >= 0 ; i--) { Interval sum = 0.; - for(size_t j = i+1 ; j < n ; j++) + for(Index j = i+1 ; j < n ; j++) sum += A_(i,j)*x[j]; x[i] &= (b_[i]-sum)/A_(i,i); } @@ -48,7 +48,7 @@ void CtcGaussSeidel::contract(IntervalMatrix& A, IntervalVector& x, IntervalVect assert_release(A.is_squared() && A.rows() == x.size() && A.rows() == b.size()); auto ext_diag = A; - for(size_t i = 0 ; i < A.rows() ; i++) + for(Index i = 0 ; i < A.rows() ; i++) ext_diag(i,i) = 0.; x &= IntervalVector(A.diagonal().asDiagonal().inverse()*(b-ext_diag*x)); } \ No newline at end of file diff --git a/src/core/domains/interval/codac2_Interval.cpp b/src/core/domains/interval/codac2_Interval.cpp index 1d24e693..b0bc9e2d 100644 --- a/src/core/domains/interval/codac2_Interval.cpp +++ b/src/core/domains/interval/codac2_Interval.cpp @@ -133,7 +133,7 @@ namespace codac2 return ibex::Interval::diam(); } - size_t Interval::size() const + Index Interval::size() const { return 1; } diff --git a/src/core/domains/interval/codac2_Interval.h b/src/core/domains/interval/codac2_Interval.h index b439a32f..275ee097 100644 --- a/src/core/domains/interval/codac2_Interval.h +++ b/src/core/domains/interval/codac2_Interval.h @@ -19,6 +19,7 @@ #include #include #include +#include "codac2_Index.h" #include "codac2_Domain.h" namespace codac2 @@ -225,7 +226,7 @@ namespace codac2 * * \return 1 */ - size_t size() const; + Index size() const; /** * \brief Sets this interval to the empty set diff --git a/src/core/domains/interval/codac2_IntervalMatrix.h b/src/core/domains/interval/codac2_IntervalMatrix.h index 90af210c..5b232ea8 100644 --- a/src/core/domains/interval/codac2_IntervalMatrix.h +++ b/src/core/domains/interval/codac2_IntervalMatrix.h @@ -27,10 +27,10 @@ namespace codac2 #if 0 // IBEX style os << "("; - for(size_t i = 0 ; i < x.rows() ; i++) + for(Index i = 0 ; i < x.rows() ; i++) { os << (i!=0 ? " " : "") << "("; - for(size_t j = 0 ; j < x.cols() ; j++) + for(Index j = 0 ; j < x.cols() ; j++) os << x(i,j) << (j v_x; ((v_x.push_back(to_IntervalVector(x))), ...); - size_t n = 0; + Index n = 0; for(const auto& xi : v_x) n += xi.size(); IntervalVector x_(n); - size_t i = 0; + Index i = 0; for(const auto& xi : v_x) { x_.put(i, xi); @@ -66,7 +66,7 @@ namespace codac2 #if 0 // IBEX style os << "("; - for(size_t i = 0 ; i < x.size() ; i++) + for(Index i = 0 ; i < x.size() ; i++) os << x[i] << (i& lb, const Matrix& ub) { assert_release(lb.size() == ub.size()); - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) { auto& lbi = *(this->data()+i); const auto& ubi = *(ub.data()+i); @@ -54,9 +54,9 @@ Matrix(int r, int c, const double bounds[][2]) { assert_release(r > 0 && c > 0); - size_t k = 0; - for(size_t i = 0 ; i < this->rows() ; i++) - for(size_t j = 0 ; j < this->cols() ; j++) + Index k = 0; + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) { (*this)(i,j) = codac2::Interval(bounds[k][0],bounds[k][1]); k++; @@ -85,7 +85,7 @@ inline double volume() const return 0.; double v = 0.; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) { if((this->data()+i)->is_unbounded()) return codac2::oo; if((this->data()+i)->is_degenerated()) return 0.; @@ -102,7 +102,7 @@ inline double volume() const \ else \ { \ - for(size_t i = 0 ; i < this->size() ; i++) \ + for(Index i = 0 ; i < this->size() ; i++) \ *(op.data()+i) = (this->data()+i)->op(); \ } \ \ @@ -181,21 +181,21 @@ inline double max_diam() const template requires IsIntervalDomain -inline size_t min_diam_index() const +inline Index min_diam_index() const { return extr_diam_index(true); } template requires IsIntervalDomain -inline size_t max_diam_index() const +inline Index max_diam_index() const { return extr_diam_index(false); } template requires IsIntervalDomain -inline size_t extr_diam_index(bool min) const +inline Index extr_diam_index(bool min) const { // This code originates from the ibex-lib // See: ibex_TemplateVector.h @@ -206,7 +206,7 @@ inline size_t extr_diam_index(bool min) const bool unbounded = false; assert_release(!this->is_empty() && "Diameter of an empty IntervalVector is undefined"); - size_t i; + Index i; for(i = 0 ; i < this->size() ; i++) { @@ -274,7 +274,7 @@ inline size_t extr_diam_index(bool min) const // to MatrixBase requires IsIntervalDomain // to MatrixBase inline bool is_empty() const // to MatrixBase { -// to MatrixBase for(size_t i = 0 ; i < this->size() ; i++) +// to MatrixBase for(Index i = 0 ; i < this->size() ; i++) // to MatrixBase if((this->data()+i)->is_empty()) // to MatrixBase return true; // to MatrixBase return false; @@ -296,7 +296,7 @@ inline bool contains(const Matrix& x if(this->is_empty()) return false; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(!(this->data()+i)->contains(*(x.data()+i))) return false; @@ -312,7 +312,7 @@ inline bool interior_contains(const Matrixis_empty()) return false; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(!(this->data()+i)->interior_contains(*(x.data()+i))) return false; @@ -324,7 +324,7 @@ template inline bool is_unbounded() const { if(this->is_empty()) return false; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if((this->data()+i)->is_unbounded()) return true; return false; @@ -334,7 +334,7 @@ template requires IsIntervalDomain inline bool is_degenerated() const { - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(!(this->data()+i)->is_degenerated()) return false; return true; @@ -345,7 +345,7 @@ template inline bool is_flat() const { if(this->is_empty()) return true; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if((this->data()+i)->is_degenerated()) // don't use diam() because of roundoff return true; return false; @@ -360,7 +360,7 @@ inline bool intersects(const Matrixis_empty()) return false; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(!(this->data()+i)->intersects(*(x.data()+i))) return false; @@ -376,7 +376,7 @@ inline bool is_disjoint(const Matrixis_empty()) return true; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if((this->data()+i)->is_disjoint(*(x.data()+i))) return true; @@ -392,7 +392,7 @@ inline bool overlaps(const Matrixis_empty()) return false; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(!(this->data()+i)->overlaps(*(x.data()+i))) return false; @@ -408,7 +408,7 @@ inline bool is_subset(const Matrixis_empty()) return true; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(!(this->data()+i)->is_subset(*(x.data()+i))) return false; @@ -427,7 +427,7 @@ inline bool is_strict_subset(const Matrixsize() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if((this->data()+i)->is_strict_subset(*(x.data()+i))) return true; @@ -443,7 +443,7 @@ inline bool is_interior_subset(const Matrixis_empty()) return true; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(!(this->data()+i)->is_interior_subset(*(x.data()+i))) return false; @@ -459,7 +459,7 @@ inline bool is_strict_interior_subset(const Matrixis_empty()) return true; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(!(this->data()+i)->is_strict_interior_subset(*(x.data()+i))) return false; @@ -475,7 +475,7 @@ inline bool is_superset(const Matrixis_empty()) return false; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(!(x.data()+i)->is_subset(*(this->data()+i))) return false; @@ -494,7 +494,7 @@ inline bool is_strict_superset(const Matrixsize() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if((x.data()+i)->is_strict_subset(*(this->data()+i))) return true; @@ -505,7 +505,7 @@ template requires IsIntervalDomain inline bool is_bisectable() const { - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if((this->data()+i)->is_bisectable()) return true; return false; @@ -517,7 +517,7 @@ inline auto& inflate(double r) { assert_release(r >= 0.); - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) (this->data()+i)->inflate(r); return *this; } @@ -529,7 +529,7 @@ inline auto& inflate(const Matrix& r assert_release(this->size() == r.size()); assert_release(r.min_coeff() >= 0.); - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) (this->data()+i)->inflate(*(r.data()+i)); return *this; } @@ -549,7 +549,7 @@ inline auto& operator&=(const Matrix& x) } } - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) *(this->data()+i) &= *(x.data()+i); return *this; } @@ -560,8 +560,8 @@ inline auto& operator&=(const MatrixBase& x) { assert_release(this->size() == x.size()); - for(size_t i = 0 ; i < this->rows() ; i++) - for(size_t j = 0 ; j < this->cols() ; j++) + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) (*this)(i,j) &= x(i,j); return *this; } @@ -578,7 +578,7 @@ inline auto& operator|=(const Matrix& x) return *this; } - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) *(this->data()+i) |= *(x.data()+i); return *this; } @@ -601,7 +601,7 @@ inline auto operator|(const Matrix requires IsIntervalDomain -inline static auto empty(size_t r, size_t c) +inline static auto empty(Index r, Index c) { assert_release(r >= 0 && c >= 0); Matrix e(r,c); @@ -610,7 +610,7 @@ inline static auto empty(size_t r, size_t c) template requires IsIntervalDomain -inline auto bisect(size_t i, float ratio = 0.49) const +inline auto bisect(Index i, float ratio = 0.49) const { assert_release(i >= 0 && i < this->size()); assert_release((this->data()+i)->is_bisectable()); diff --git a/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h b/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h index 5007c523..1077dba3 100644 --- a/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h +++ b/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h @@ -19,7 +19,7 @@ //Matrix(const IV&... x) // : Matrix(sizeof...(IV), std::get<0>(std::tie(x...)).size()) //{ -// size_t i = 0; +// Index i = 0; // ((this->row(i++) = x), ...); // assert_release(i == rows() && "invalid input size"); //} \ No newline at end of file diff --git a/src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h b/src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h index 0a18ff6d..3da9e38c 100644 --- a/src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h +++ b/src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h @@ -27,7 +27,7 @@ Matrix(const std::initializer_list& l) ) { assert_release(!std::empty(l)); - size_t i = 0; + Index i = 0; for(const auto& li : l) (*this)[i++] = codac2::Interval(li); } @@ -41,7 +41,7 @@ Matrix(const std::initializer_list>& l) ) { assert_release(!std::empty(l)); - size_t i = 0; + Index i = 0; for(const auto& li : l) (*this)[i++] = codac2::Interval(li); } @@ -55,7 +55,7 @@ Matrix(const std::initializer_list& l) ) { assert_release(!std::empty(l)); - size_t i = 0; + Index i = 0; for(const auto& li : l) (*this)[i++] = li; } @@ -93,7 +93,7 @@ Matrix(int n, const double bounds[][2]) // ) //{ // assert_release(!std::empty(l)); -// size_t i = 0; +// Index i = 0; // for(const auto& li : l) // { // assert_release(!std::empty(li)); @@ -103,7 +103,7 @@ Matrix(int n, const double bounds[][2]) template requires IsIntervalDomain && IsVectorOrRow -inline static auto empty(size_t n) +inline static auto empty(Index n) { assert_release(n >= 0); if constexpr(R == 1) @@ -128,7 +128,7 @@ inline std::list> diff(const Matrixsize(); + const Index n = this->size(); assert_release(y.size() == n); if(y == *this) @@ -148,7 +148,7 @@ inline std::list> diff(const Matrix> diff(const Matrix> l; - for(size_t var = 0 ; var < n ; var++) + for(Index var = 0 ; var < n ; var++) { codac2::Interval c1, c2; @@ -167,10 +167,10 @@ inline std::list> diff(const Matrix v(n); - for(size_t i = 0 ; i < var ; i++) + for(Index i = 0 ; i < var ; i++) v[i] = x[i]; v[var] = ci; - for(size_t i = var+1 ; i < n ; i++) + for(Index i = var+1 ; i < n ; i++) v[i] = x[i]; if(!v.is_empty()) l.push_back(v); diff --git a/src/core/domains/paving/codac2_Paving.cpp b/src/core/domains/paving/codac2_Paving.cpp index 4b810b0c..f7eb538d 100644 --- a/src/core/domains/paving/codac2_Paving.cpp +++ b/src/core/domains/paving/codac2_Paving.cpp @@ -17,7 +17,7 @@ namespace codac2 { // PavingOut class - PavingOut::PavingOut(size_t n) + PavingOut::PavingOut(Index n) : Paving(n) { assert_release(n > 0); @@ -77,7 +77,7 @@ namespace codac2 // PavingInOut class - PavingInOut::PavingInOut(size_t n) + PavingInOut::PavingInOut(Index n) : Paving(n) { assert_release(n > 0); diff --git a/src/core/domains/paving/codac2_Paving.h b/src/core/domains/paving/codac2_Paving.h index 210bcedd..75cf7263 100644 --- a/src/core/domains/paving/codac2_Paving.h +++ b/src/core/domains/paving/codac2_Paving.h @@ -32,7 +32,7 @@ namespace codac2 using NodeValue_ = std::function(Node_)>; using ConnectedSubset_ = Subpaving

; - Paving(size_t n) + Paving(Index n) : Paving(IntervalVector(n)) { assert_release(n > 0); @@ -42,7 +42,7 @@ namespace codac2 : _tree(std::make_shared>(*static_cast(this), x)) { } - size_t size() const + Index size() const { return std::get<0>(_tree->boxes()).size(); } @@ -85,7 +85,7 @@ namespace codac2 std::list connected_subsets(const IntervalVector& x0, const NodeValue_& node_value) const { std::list l_boxes = intersecting_boxes(x0, node_value); - size_t nb_boxes = l_boxes.size(); + Index nb_boxes = l_boxes.size(); std::list l_subsets; while(!l_boxes.empty()) @@ -115,7 +115,7 @@ namespace codac2 } assert(l_boxes.empty() && "all the nodes should have been visited"); - assert([&]() -> bool { size_t s = 0; for(const auto& si : l_subsets) s += si.size(); return s == nb_boxes; } () + assert([&]() -> bool { Index s = 0; for(const auto& si : l_subsets) s += si.size(); return s == nb_boxes; } () && "the total number of boxes should match the sum of number of boxes of each subset"); return l_subsets; @@ -141,7 +141,7 @@ namespace codac2 { public: - PavingOut(size_t n); + PavingOut(Index n); PavingOut(const IntervalVector& x); std::list connected_subsets(const PavingOut::NodeValue_& node_value = PavingOut::outer) const; @@ -158,7 +158,7 @@ namespace codac2 { public: - PavingInOut(size_t n); + PavingInOut(Index n); PavingInOut(const IntervalVector& x); std::list connected_subsets(const PavingInOut::NodeValue_& node_value = PavingInOut::outer) const; diff --git a/src/core/domains/paving/codac2_Subpaving.h b/src/core/domains/paving/codac2_Subpaving.h index 9fd794d6..1aeedcf6 100644 --- a/src/core/domains/paving/codac2_Subpaving.h +++ b/src/core/domains/paving/codac2_Subpaving.h @@ -114,7 +114,7 @@ namespace codac2 assert_release(!l.empty()); assert_release(l.front().size() == 2 && "only 2d contours can be sorted"); - const size_t nl = l.size(); + const Index nl = l.size(); Vector current_pt = l.front().ub(), first_pt = current_pt; std::list s { l.front() }; diff --git a/src/core/functions/analytic/codac2_AnalyticExpr.h b/src/core/functions/analytic/codac2_AnalyticExpr.h index b1187ffc..134d62a2 100644 --- a/src/core/functions/analytic/codac2_AnalyticExpr.h +++ b/src/core/functions/analytic/codac2_AnalyticExpr.h @@ -28,7 +28,7 @@ namespace codac2 AnalyticExpr& operator=(const AnalyticExpr& x) = delete; - virtual T fwd_eval(ValuesMap& v, size_t total_input_size) const = 0; + virtual T fwd_eval(ValuesMap& v, Index total_input_size) const = 0; virtual void bwd_eval(ValuesMap& v) const = 0; T init_value(ValuesMap& v, const T& x) const @@ -77,7 +77,7 @@ namespace codac2 return OperationExprBase...>::replace_expr(old_expr_id, new_expr); } - Y fwd_eval(ValuesMap& v, size_t total_input_size) const + Y fwd_eval(ValuesMap& v, Index total_input_size) const { return std::apply( [this,&v,total_input_size](auto &&... x) @@ -120,7 +120,7 @@ namespace codac2 { public: - AnalyticOperationExpr(const std::shared_ptr>& x1, size_t i) + AnalyticOperationExpr(const std::shared_ptr>& x1, Index i) : OperationExprBase>(x1), _i(i) { } @@ -138,7 +138,7 @@ namespace codac2 return OperationExprBase>::replace_expr(old_expr_id, new_expr); } - ScalarOpValue fwd_eval(ValuesMap& v, size_t total_input_size) const + ScalarOpValue fwd_eval(ValuesMap& v, Index total_input_size) const { return AnalyticExpr::init_value( v, ComponentOp::fwd(std::get<0>(this->_x)->fwd_eval(v, total_input_size), _i)); @@ -157,7 +157,7 @@ namespace codac2 protected: - const size_t _i; + const Index _i; }; template<> @@ -165,7 +165,7 @@ namespace codac2 { public: - AnalyticOperationExpr(const std::shared_ptr>& x1, size_t i, size_t j) + AnalyticOperationExpr(const std::shared_ptr>& x1, Index i, Index j) : OperationExprBase>(x1), _i(i), _j(j) { } @@ -183,7 +183,7 @@ namespace codac2 return OperationExprBase>::replace_expr(old_expr_id, new_expr); } - VectorOpValue fwd_eval(ValuesMap& v, size_t total_input_size) const + VectorOpValue fwd_eval(ValuesMap& v, Index total_input_size) const { return AnalyticExpr::init_value( v, SubvectorOp::fwd(std::get<0>(this->_x)->fwd_eval(v, total_input_size), _i, _j)); @@ -202,6 +202,6 @@ namespace codac2 protected: - const size_t _i, _j; + const Index _i, _j; }; } \ No newline at end of file diff --git a/src/core/functions/analytic/codac2_AnalyticFunction.h b/src/core/functions/analytic/codac2_AnalyticFunction.h index 0ec6f37e..e56b3e4d 100644 --- a/src/core/functions/analytic/codac2_AnalyticFunction.h +++ b/src/core/functions/analytic/codac2_AnalyticFunction.h @@ -127,18 +127,18 @@ namespace codac2 friend class CtcInverse; template - void add_value_to_arg_map(ValuesMap& v, const D& x, size_t i) const + void add_value_to_arg_map(ValuesMap& v, const D& x, Index i) const { - assert(i >= 0 && i < this->args().size()); + assert(i >= 0 && i < (Index)this->args().size()); assert_release(size_of(x) == this->args()[i]->size() && "provided arguments do not match function inputs"); IntervalMatrix d = IntervalMatrix::zeros(size_of(x), this->args().total_size()); - size_t p = 0, j = 0; + Index p = 0, j = 0; for( ; j < i ; j++) p += this->args()[j]->size(); - for(size_t k = p ; k < p+size_of(x) ; k++) + for(Index k = p ; k < p+size_of(x) ; k++) d(k-p,k) = 1.; using D_DOMAIN = typename Wrapper::Domain; @@ -150,12 +150,12 @@ namespace codac2 template void fill_from_args(ValuesMap& v, const Args&... x) const { - size_t i = 0; + Index i = 0; (add_value_to_arg_map(v, x, i++), ...); } template - void intersect_value_from_arg_map(const ValuesMap& v, D& x, size_t i) const + void intersect_value_from_arg_map(const ValuesMap& v, D& x, Index i) const { assert(v.find(this->args()[i]->unique_id()) != v.end() && "argument cannot be found"); x &= std::dynamic_pointer_cast::Domain>(v.at(this->args()[i]->unique_id()))->a; @@ -164,7 +164,7 @@ namespace codac2 template void intersect_from_args(const ValuesMap& v, Args&... x) const { - size_t i = 0; + Index i = 0; (intersect_value_from_arg_map(v, x, i++), ...); } @@ -186,7 +186,7 @@ namespace codac2 template void check_valid_inputs(const Args&... x) const { - size_t n = 0; + Index n = 0; ((n += size_of(x)), ...); assert_release(this->_args.total_size() == n && diff --git a/src/core/functions/analytic/codac2_analytic_constants.h b/src/core/functions/analytic/codac2_analytic_constants.h index 08b143d1..633956bc 100644 --- a/src/core/functions/analytic/codac2_analytic_constants.h +++ b/src/core/functions/analytic/codac2_analytic_constants.h @@ -9,6 +9,8 @@ #pragma once +#include "codac2_Index.h" + namespace codac2 { template @@ -27,7 +29,7 @@ namespace codac2 return std::make_shared>(*this); } - T fwd_eval(ValuesMap& v, size_t total_input_size) const + T fwd_eval(ValuesMap& v, Index total_input_size) const { return AnalyticExpr::init_value(v, T( // the mid is not considered for const values in centered form expression: diff --git a/src/core/functions/analytic/codac2_analytic_values.h b/src/core/functions/analytic/codac2_analytic_values.h index 899252eb..98c09504 100644 --- a/src/core/functions/analytic/codac2_analytic_values.h +++ b/src/core/functions/analytic/codac2_analytic_values.h @@ -61,7 +61,7 @@ namespace codac2 }; template<> - struct Wrapper { + struct Wrapper { using Domain = ScalarOpValue; }; diff --git a/src/core/functions/analytic/codac2_analytic_variables.h b/src/core/functions/analytic/codac2_analytic_variables.h index 7897629d..657c5b78 100644 --- a/src/core/functions/analytic/codac2_analytic_variables.h +++ b/src/core/functions/analytic/codac2_analytic_variables.h @@ -28,7 +28,7 @@ namespace codac2 return AnalyticExpr::unique_id(); } - T fwd_eval(ValuesMap& v, size_t total_input_size) const + T fwd_eval(ValuesMap& v, Index total_input_size) const { return AnalyticExpr::value(v); } @@ -74,7 +74,7 @@ namespace codac2 return std::make_shared(*this); } - size_t size() const + Index size() const { return 1; } @@ -89,7 +89,7 @@ namespace codac2 { public: - explicit VectorVar(size_t n) + explicit VectorVar(Index n) : _n(n) { assert_release(n > 0); @@ -109,19 +109,19 @@ namespace codac2 return std::make_shared(*this); } - size_t size() const + Index size() const { return _n; } - std::shared_ptr> operator[](size_t i) const + std::shared_ptr> operator[](Index i) const { assert_release(i >= 0 && i < _n); return std::make_shared>( std::dynamic_pointer_cast>(this->copy()), i); } - std::shared_ptr> subvector(size_t i, size_t j) const + std::shared_ptr> subvector(Index i, Index j) const { assert_release(i >= 0 && i < _n && j >= i && j < _n); return std::make_shared>( @@ -130,6 +130,6 @@ namespace codac2 protected: - size_t _n; + Index _n; }; } \ No newline at end of file diff --git a/src/core/functions/codac2_ExprBase.cpp b/src/core/functions/codac2_ExprBase.cpp index 2a9a2997..a4ecbbb6 100644 --- a/src/core/functions/codac2_ExprBase.cpp +++ b/src/core/functions/codac2_ExprBase.cpp @@ -12,7 +12,7 @@ using namespace std; using namespace codac2; -size_t ExprID::_id_counter = 0; +Index ExprID::_id_counter = 0; ExprID::ExprID() : _id(ExprID::_id_counter) @@ -20,7 +20,7 @@ ExprID::ExprID() ExprID::_id_counter ++; } -size_t ExprID::id() const +Index ExprID::id() const { return _id; } diff --git a/src/core/functions/codac2_ExprBase.h b/src/core/functions/codac2_ExprBase.h index e3c82df1..8ae3045d 100644 --- a/src/core/functions/codac2_ExprBase.h +++ b/src/core/functions/codac2_ExprBase.h @@ -26,14 +26,14 @@ namespace codac2 ExprID(); ExprID(const ExprID& i) = default; - size_t id() const; + Index id() const; bool operator==(const ExprID& i) const; bool operator<(const ExprID& i) const; protected: - const size_t _id; - static size_t _id_counter; + const Index _id; + static Index _id_counter; }; class ExprBase : public std::enable_shared_from_this diff --git a/src/core/functions/codac2_FunctionArgsList.h b/src/core/functions/codac2_FunctionArgsList.h index cb6a2262..e91f3bc2 100644 --- a/src/core/functions/codac2_FunctionArgsList.h +++ b/src/core/functions/codac2_FunctionArgsList.h @@ -39,9 +39,9 @@ namespace codac2 push_back(arg.get().arg_copy()); } - size_t total_size() const + Index total_size() const { - size_t n = 0; + Index n = 0; for(const auto& ai : *this) n += ai->size(); return n; diff --git a/src/core/functions/codac2_FunctionBase.h b/src/core/functions/codac2_FunctionBase.h index dfd22800..f3d4fd42 100644 --- a/src/core/functions/codac2_FunctionBase.h +++ b/src/core/functions/codac2_FunctionBase.h @@ -70,7 +70,7 @@ namespace codac2 return std::dynamic_pointer_cast(expr_copy); } - size_t input_size() const + Index input_size() const { return this->_args.total_size(); } diff --git a/src/core/functions/codac2_VarBase.h b/src/core/functions/codac2_VarBase.h index 42eb06cd..c39b3931 100644 --- a/src/core/functions/codac2_VarBase.h +++ b/src/core/functions/codac2_VarBase.h @@ -20,6 +20,6 @@ namespace codac2 virtual const ExprID& unique_id() const = 0; virtual std::shared_ptr arg_copy() const = 0; virtual ~VarBase() = default; - virtual size_t size() const = 0; + virtual Index size() const = 0; }; } \ No newline at end of file diff --git a/src/core/functions/set/codac2_SetExpr.h b/src/core/functions/set/codac2_SetExpr.h index 71625b7f..3f0e548f 100644 --- a/src/core/functions/set/codac2_SetExpr.h +++ b/src/core/functions/set/codac2_SetExpr.h @@ -94,11 +94,11 @@ namespace codac2 { public: - SetOperationExpr(std::shared_ptr x, const std::vector& proj_indices, double eps) + SetOperationExpr(std::shared_ptr x, const std::vector& proj_indices, double eps) : OperationExprBase(x), _proj_indices(proj_indices), _y(nullptr), _eps(eps) { } - SetOperationExpr(std::shared_ptr x, const std::vector& proj_indices, const IntervalVector& y, double eps) + SetOperationExpr(std::shared_ptr x, const std::vector& proj_indices, const IntervalVector& y, double eps) : OperationExprBase(x), _proj_indices(proj_indices), _y(std::make_shared(y)), _eps(eps) { } @@ -137,7 +137,7 @@ namespace codac2 protected: - const std::vector _proj_indices; + const std::vector _proj_indices; const std::shared_ptr _y; const double _eps; }; diff --git a/src/core/functions/set/codac2_SetFunction.h b/src/core/functions/set/codac2_SetFunction.h index b3de1819..d01167a3 100644 --- a/src/core/functions/set/codac2_SetFunction.h +++ b/src/core/functions/set/codac2_SetFunction.h @@ -37,7 +37,7 @@ namespace codac2 auto create_ctc(const Args&... x) { std::vector>> ref_x(sizeof...(Args)); - size_t i = 0; + Index i = 0; ((ref_x[i++] = create_arg_ctc_copy(x)), ...); assert_release(args().size() == ref_x.size() && "Invalid arguments: wrong number of input arguments"); @@ -48,7 +48,7 @@ namespace codac2 auto create_sep(const Args&... x) { std::vector> ref_x(sizeof...(Args)); - size_t i = 0; + Index i = 0; ((ref_x[i++] = create_arg_sep_copy(x)), ...); assert_release(args().size() == ref_x.size() && "Invalid arguments: wrong number of input arguments"); @@ -59,7 +59,7 @@ namespace codac2 std::shared_ptr operator()(const X&... x) const { auto expr_copy = expr()->copy(); - size_t i = 0; + Index i = 0; (expr_copy->replace_expr(_args[i++]->unique_id(), this->__get_copy(x)), ...); assert_release(i == this->args().size() && "Invalid arguments: wrong number of input arguments"); diff --git a/src/core/functions/set/codac2_set_operations.h b/src/core/functions/set/codac2_set_operations.h index bb9b9308..e8dc14f6 100644 --- a/src/core/functions/set/codac2_set_operations.h +++ b/src/core/functions/set/codac2_set_operations.h @@ -55,13 +55,13 @@ namespace codac2 } inline SetExpr_ptr - proj(const SetExpr_ptr& x1, const std::vector& proj_indices, double eps = 0.01) + proj(const SetExpr_ptr& x1, const std::vector& proj_indices, double eps = 0.01) { return std::make_shared>(x1,proj_indices,eps); } inline SetExpr_ptr - proj(const SetExpr_ptr& x1, const std::vector& proj_indices, const IntervalVector& y, double eps = 0.01) + proj(const SetExpr_ptr& x1, const std::vector& proj_indices, const IntervalVector& y, double eps = 0.01) { return std::make_shared>(x1,proj_indices,y,eps); } diff --git a/src/core/functions/set/codac2_set_operators.h b/src/core/functions/set/codac2_set_operators.h index d5f964f4..8a400b4c 100644 --- a/src/core/functions/set/codac2_set_operators.h +++ b/src/core/functions/set/codac2_set_operators.h @@ -56,24 +56,24 @@ namespace codac2 struct ProjSetOp { - static std::shared_ptr> create_ctc(const std::shared_ptr>& s1, const std::vector& proj_indices, double eps) + static std::shared_ptr> create_ctc(const std::shared_ptr>& s1, const std::vector& proj_indices, double eps) { throw std::logic_error("CtcProj not yet available"); return nullptr; } - static std::shared_ptr> create_ctc(const std::shared_ptr>& s1, const std::vector& proj_indices, const IntervalVector& y, double eps) + static std::shared_ptr> create_ctc(const std::shared_ptr>& s1, const std::vector& proj_indices, const IntervalVector& y, double eps) { throw std::logic_error("CtcProj not yet available"); return nullptr; } - static std::shared_ptr create_sep(const std::shared_ptr& s1, const std::vector& proj_indices, double eps) + static std::shared_ptr create_sep(const std::shared_ptr& s1, const std::vector& proj_indices, double eps) { return std::make_shared(s1,proj_indices,eps); } - static std::shared_ptr create_sep(const std::shared_ptr& s1, const std::vector& proj_indices, const IntervalVector& y, double eps) + static std::shared_ptr create_sep(const std::shared_ptr& s1, const std::vector& proj_indices, const IntervalVector& y, double eps) { return std::make_shared(s1,proj_indices,y,eps); } diff --git a/src/core/functions/set/codac2_set_variables.h b/src/core/functions/set/codac2_set_variables.h index d978a3a3..c630b14c 100644 --- a/src/core/functions/set/codac2_set_variables.h +++ b/src/core/functions/set/codac2_set_variables.h @@ -19,7 +19,7 @@ namespace codac2 { public: - explicit SetVar(size_t n) + explicit SetVar(Index n) : _n(n) { } @@ -38,7 +38,7 @@ namespace codac2 return std::make_shared(*this); } - size_t size() const + Index size() const { return _n; } @@ -61,7 +61,7 @@ namespace codac2 std::shared_ptr> create_ctc(const FunctionArgsList& args, const std::vector>>& x) const { - for(size_t i = 0 ; i < args.size() ; i++) + for(Index i = 0 ; i < args.size() ; i++) if(args[i]->unique_id() == unique_id()) return x[i]; assert(false); @@ -70,7 +70,7 @@ namespace codac2 std::shared_ptr create_sep(const FunctionArgsList& args, const std::vector>& x) const { - for(size_t i = 0 ; i < args.size() ; i++) + for(Index i = 0 ; i < args.size() ; i++) if(args[i]->unique_id() == unique_id()) return x[i]; assert(false); @@ -79,6 +79,6 @@ namespace codac2 protected: - size_t _n; + Index _n; }; } \ No newline at end of file diff --git a/src/core/geometry/codac2_Polygon.cpp b/src/core/geometry/codac2_Polygon.cpp index 69927ef3..0892f1a4 100644 --- a/src/core/geometry/codac2_Polygon.cpp +++ b/src/core/geometry/codac2_Polygon.cpp @@ -27,7 +27,7 @@ namespace codac2 assert_release(vertices.size() > 1); vector edges; - size_t i = 0; + Index i = 0; for(const auto& vi : vertices) { assert_release(vi.size() == 2); @@ -63,7 +63,7 @@ namespace codac2 { assert_release(p.size() == 2); - size_t i = 0; + Index i = 0; Edge transect { Vector({next_float(-oo),p[1]}), p }; for(const auto& edge_k : _edges) diff --git a/src/core/matrices/codac2_GaussJordan.cpp b/src/core/matrices/codac2_GaussJordan.cpp index 60d9e5ae..67f3b9cd 100644 --- a/src/core/matrices/codac2_GaussJordan.cpp +++ b/src/core/matrices/codac2_GaussJordan.cpp @@ -16,10 +16,10 @@ namespace codac2 Matrix rising(const Matrix& R_, const Matrix& U_, const Matrix& A) { Matrix R = R_, U = U_; - size_t n = A.rows(), m = A.cols(); - size_t p = m-n; + Index n = A.rows(), m = A.cols(); + Index p = m-n; - for(int i = n-1 ; i > 0 ; i--) + for(Index i = n-1 ; i > 0 ; i--) { Matrix K = U(i,i+p)*Matrix::Identity(n,n); K.block(0,i,i,1) = -U.block(0,i+p,i,1); @@ -40,7 +40,7 @@ namespace codac2 Matrix gauss_jordan(const Matrix& A) { - size_t n = A.rows(), m = A.cols(); + Index n = A.rows(), m = A.cols(); Eigen::FullPivLU lu(A); Matrix L = Matrix::Identity(n,n); diff --git a/src/core/matrices/codac2_matrices.h b/src/core/matrices/codac2_matrices.h index 1ff59486..1b3963df 100644 --- a/src/core/matrices/codac2_matrices.h +++ b/src/core/matrices/codac2_matrices.h @@ -81,7 +81,6 @@ namespace Eigen namespace codac2 { using Eigen::Dynamic; - using Eigen::Index; inline const Interval& conj(const Interval& x) { return x; } inline const Interval& real(const Interval& x) { return x; } diff --git a/src/core/matrices/eigen/codac2_Base_eigenaddons.h b/src/core/matrices/eigen/codac2_Base_eigenaddons.h index 40d744f5..67a911bc 100644 --- a/src/core/matrices/eigen/codac2_Base_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_Base_eigenaddons.h @@ -22,13 +22,13 @@ Matrix(const Matrix& x) } template -inline Scalar& operator()(size_t i, size_t j) +inline Scalar& operator()(Index i, Index j) { return const_cast(const_cast*>(this)->operator()(i,j)); } template -inline const Scalar& operator()(size_t i, size_t j) const +inline const Scalar& operator()(Index i, Index j) const { assert_release(i >= 0 && i < this->rows() && j >= 0 && j < this->cols()); @@ -45,7 +45,7 @@ inline const Scalar& operator()(size_t i, size_t j) const inline auto& init(const Scalar& x) { - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) *(this->data()+i) = x; return *this; } @@ -63,7 +63,7 @@ inline bool is_squared() const #define minmax_item(op) \ Scalar m = *(this->data()); /* first element */ \ - for(size_t i = 1 ; i < this->size() ; i++) \ + for(Index i = 1 ; i < this->size() ; i++) \ { \ if constexpr(std::is_same_v) \ m = codac2::op(m,*(this->data()+i)); \ @@ -97,7 +97,7 @@ inline bool operator==(const Matrix& x) const if(this->rows() != x.rows() || this->cols() != x.cols()) return false; - for(size_t i = 0 ; i < this->size() ; i++) + for(Index i = 0 ; i < this->size() ; i++) if(*(this->data()+i) != *(x.data()+i)) return false; diff --git a/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h b/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h index 12bdb8cd..cf769a2c 100644 --- a/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h @@ -36,9 +36,9 @@ explicit Matrix(int r, int c, const Scalar values[]) else { - size_t k = 0; - for(size_t i = 0 ; i < this->rows() ; i++) - for(size_t j = 0 ; j < this->cols() ; j++) + Index k = 0; + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) (*this)(i,j) = values[k++]; assert(k == this->size()); } @@ -46,7 +46,7 @@ explicit Matrix(int r, int c, const Scalar values[]) template requires (!IsVectorOrRow) -inline auto block(size_t i, size_t j, size_t p, size_t q) +inline auto block(Index i, Index j, Index p, Index q) { assert_release(i >= 0 && p > 0 && i+p <= this->rows()); assert_release(j >= 0 && q > 0 && j+q <= this->cols()); @@ -55,7 +55,7 @@ inline auto block(size_t i, size_t j, size_t p, size_t q) template requires (!IsVectorOrRow) -inline auto block(size_t i, size_t j, size_t p, size_t q) const +inline auto block(Index i, Index j, Index p, Index q) const { assert_release(i >= 0 && p > 0 && i+p <= this->rows()); assert_release(j >= 0 && q > 0 && j+q <= this->cols()); @@ -64,7 +64,7 @@ inline auto block(size_t i, size_t j, size_t p, size_t q) const template requires (!IsVectorOrRow) -inline static Matrix zeros(size_t r, size_t c) +inline static Matrix zeros(Index r, Index c) { assert_release(r >= 0 && c >= 0); return Matrix::Zero(r,c); @@ -72,7 +72,7 @@ inline static Matrix zeros(size_t r, size_t c) template requires (!IsVectorOrRow) -inline static Matrix ones(size_t r, size_t c) +inline static Matrix ones(Index r, Index c) { assert_release(r >= 0 && c >= 0); return Matrix::Ones(r,c); @@ -80,7 +80,7 @@ inline static Matrix ones(size_t r, size_t c) template requires (!IsVectorOrRow) -inline static Matrix eye(size_t r, size_t c) +inline static Matrix eye(Index r, Index c) { assert_release(r >= 0 && c >= 0); return Matrix::Identity(r,c); @@ -88,12 +88,12 @@ inline static Matrix eye(size_t r, size_t c) template requires (!IsVectorOrRow) -inline void resize_save_values(size_t r, size_t c) +inline void resize_save_values(Index r, Index c) { // With resize() of Eigen, the data is reallocated and all previous values are lost. auto copy = *this; this->resize(r,c); - for(size_t i = 0 ; i < std::min((size_t)copy.rows(),r) ; i++) - for(size_t j = 0 ; j < std::min((size_t)copy.cols(),c) ; j++) + for(Index i = 0 ; i < std::min((Index)copy.rows(),r) ; i++) + for(Index j = 0 ; j < std::min((Index)copy.cols(),c) ; j++) (*this)(i,j) = copy(i,j); } \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h b/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h index 1fc14273..2495a4d6 100644 --- a/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h @@ -34,14 +34,14 @@ inline auto diag_matrix() const template requires IsVectorOrRow -inline Scalar& operator()(size_t i) +inline Scalar& operator()(Index i) { return const_cast(const_cast*>(this)->operator()(i)); } template requires IsVectorOrRow -inline const Scalar& operator()(size_t i) const +inline const Scalar& operator()(Index i) const { assert_release(i >= 0 && i < this->size()); return this->PlainObjectBase>::operator()(i); @@ -49,14 +49,14 @@ inline const Scalar& operator()(size_t i) const template requires IsVectorOrRow -inline Scalar& operator[](size_t i) +inline Scalar& operator[](Index i) { return const_cast(const_cast*>(this)->operator[](i)); } template requires IsVectorOrRow -inline const Scalar& operator[](size_t i) const +inline const Scalar& operator[](Index i) const { assert_release(i >= 0 && i < this->size()); return this->PlainObjectBase>::operator[](i); @@ -64,7 +64,7 @@ inline const Scalar& operator[](size_t i) const template requires IsVectorOrRow -inline static Matrix zeros(size_t n) +inline static Matrix zeros(Index n) { assert_release(n >= 0); if constexpr(R == 1) @@ -75,7 +75,7 @@ inline static Matrix zeros(size_t n) template requires IsVectorOrRow -inline static Matrix ones(size_t n) +inline static Matrix ones(Index n) { assert_release(n >= 0); if constexpr(R == 1) @@ -86,7 +86,7 @@ inline static Matrix ones(size_t n) template requires IsVectorOrRow -inline auto subvector(size_t start_id, size_t end_id) const +inline auto subvector(Index start_id, Index end_id) const { assert_release(end_id >= 0 && start_id >= 0); assert_release(end_id < this->size() && start_id <= end_id); @@ -95,7 +95,7 @@ inline auto subvector(size_t start_id, size_t end_id) const template requires IsVectorOrRow -inline void put(size_t start_id, const Matrix& x) +inline void put(Index start_id, const Matrix& x) { assert_release(start_id >= 0 && start_id < this->size()); assert_release(start_id+x.size() <= this->size()); @@ -105,11 +105,11 @@ inline void put(size_t start_id, const Matrix& x) template requires IsVectorOrRow -inline void resize_save_values(size_t n) +inline void resize_save_values(Index n) { // With resize() of Eigen, the data is reallocated and all previous values are lost. auto copy = *this; this->resize(n); - for(size_t i = 0 ; i < std::min((size_t)copy.size(),n) ; i++) + for(Index i = 0 ; i < std::min((Index)copy.size(),n) ; i++) (*this)[i] = copy[i]; } diff --git a/src/core/matrices/eigen/codac2_Vector_eigenaddons.h b/src/core/matrices/eigen/codac2_Vector_eigenaddons.h index f105c108..4ad8c346 100644 --- a/src/core/matrices/eigen/codac2_Vector_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_Vector_eigenaddons.h @@ -22,7 +22,7 @@ Matrix(std::initializer_list l) ) { assert_release(!std::empty(l)); - size_t i = 0; + Index i = 0; for(const auto& li : l) (*this)[i++] = li; } @@ -53,9 +53,9 @@ explicit Matrix(int n, double values[]) template requires (!IsIntervalDomain) && (IsVectorOrRow) -inline size_t min_coeff_index() const +inline Index min_coeff_index() const { - size_t r,c; + Index r,c; this->minCoeff(&r,&c); assert(c == 0); return r; @@ -63,9 +63,9 @@ inline size_t min_coeff_index() const template requires (!IsIntervalDomain) && (IsVectorOrRow) -inline size_t max_coeff_index() const +inline Index max_coeff_index() const { - size_t r,c; + Index r,c; this->maxCoeff(&r,&c); assert(c == 0); return r; diff --git a/src/core/matrices/eigen/codac2_eigenaddons_test.h b/src/core/matrices/eigen/codac2_eigenaddons_test.h index fd2faa4a..95ff6a38 100644 --- a/src/core/matrices/eigen/codac2_eigenaddons_test.h +++ b/src/core/matrices/eigen/codac2_eigenaddons_test.h @@ -17,8 +17,8 @@ inline bool is_empty() const { - for(size_t i = 0 ; i < rows() ; i++) - for(size_t j = 0 ; j < cols() ; j++) + for(Index i = 0 ; i < rows() ; i++) + for(Index j = 0 ; j < cols() ; j++) if((*this)(i,j).is_empty()) return true; return false; diff --git a/src/core/proj/codac2_ProjBase.cpp b/src/core/proj/codac2_ProjBase.cpp index d2fb5f94..62c769f4 100644 --- a/src/core/proj/codac2_ProjBase.cpp +++ b/src/core/proj/codac2_ProjBase.cpp @@ -13,7 +13,7 @@ using namespace std; namespace codac2 { - ProjBase::ProjBase(const std::vector& proj_indices, const IntervalVector& y, double default_eps) + ProjBase::ProjBase(const std::vector& proj_indices, const IntervalVector& y, double default_eps) : _n(proj_indices.size()+y.size()), _xi(proj_indices), _y(y), _default_eps(default_eps) { assert(default_eps > 0.); @@ -24,10 +24,10 @@ namespace codac2 assert(w.size() == _n); IntervalVector x(_xi.size()); - size_t k = 0; + Index k = 0; for(const auto& xi : _xi) x[k++] = w[xi]; - assert(k == _xi.size()); // all components have been reached + assert(k == (Index)_xi.size()); // all components have been reached return x; } @@ -36,8 +36,8 @@ namespace codac2 assert(w.size() == _n); IntervalVector y(_y.size()); - size_t k = 0; - for(size_t j = 0 ; j < w.size() ; j++) + Index k = 0; + for(Index j = 0 ; j < w.size() ; j++) { bool outside_proj = true; for(const auto& xi : _xi) @@ -57,13 +57,13 @@ namespace codac2 IntervalVector ProjBase::cart_prod_xy(const IntervalVector& x, const IntervalVector& y) const { - assert(x.size() == _xi.size()); + assert(x.size() == (Index)_xi.size()); assert(y.size() == _y.size()); - size_t ix = 0, iy = 0; + Index ix = 0, iy = 0; IntervalVector w(_n); - for(size_t j = 0 ; j < _n ; j++) + for(Index j = 0 ; j < _n ; j++) { bool outside_proj = true; for(const auto& xi : _xi) @@ -80,10 +80,10 @@ namespace codac2 return w; } - size_t ProjBase::y_max_diam_index(const IntervalVector& y) const + Index ProjBase::y_max_diam_index(const IntervalVector& y) const { - size_t k = 0, y_max = y.max_diam_index(); - for(size_t i = 0 ; i < _n ; i++) + Index k = 0, y_max = y.max_diam_index(); + for(Index i = 0 ; i < _n ; i++) { bool outside_proj = true; for(const auto& xi : _xi) diff --git a/src/core/proj/codac2_ProjBase.h b/src/core/proj/codac2_ProjBase.h index 7a52e390..7d629e03 100644 --- a/src/core/proj/codac2_ProjBase.h +++ b/src/core/proj/codac2_ProjBase.h @@ -18,16 +18,16 @@ namespace codac2 { protected: - ProjBase(const std::vector& proj_indices, const IntervalVector& y, double default_eps = 0.01); + ProjBase(const std::vector& proj_indices, const IntervalVector& y, double default_eps = 0.01); IntervalVector extract_x(const IntervalVector& w) const; IntervalVector extract_y(const IntervalVector& w) const; IntervalVector cart_prod_xy(const IntervalVector& x, const IntervalVector& y) const; - size_t y_max_diam_index(const IntervalVector& y) const; + Index y_max_diam_index(const IntervalVector& y) const; protected: - const size_t _n; - const std::vector _xi; + const Index _n; + const std::vector _xi; const IntervalVector _y; const double _default_eps; }; diff --git a/src/core/separators/codac2_Sep.h b/src/core/separators/codac2_Sep.h index 38b3f115..48c3f571 100644 --- a/src/core/separators/codac2_Sep.h +++ b/src/core/separators/codac2_Sep.h @@ -50,13 +50,13 @@ namespace codac2 { public: - SepBase(size_t n) + SepBase(Index n) : _n(n) { assert(n > 0); } - size_t size() const + Index size() const { return _n; } @@ -66,7 +66,7 @@ namespace codac2 protected: - const size_t _n; + const Index _n; }; template @@ -74,7 +74,7 @@ namespace codac2 { public: - Sep(size_t n) + Sep(Index n) : SepBase(n) { } diff --git a/src/core/separators/codac2_SepAction.h b/src/core/separators/codac2_SepAction.h index acc31a12..66d372e8 100644 --- a/src/core/separators/codac2_SepAction.h +++ b/src/core/separators/codac2_SepAction.h @@ -26,7 +26,7 @@ namespace codac2 SepAction(const S& s, const OctaSym& a) : Sep(a.size()), _sep(s), _s(a), __s(a.invert()) { - assert_release(size_of(s) == a.size()); + assert_release(size_of(s) == (Index)a.size()); } BoxPair separate(const IntervalVector& x) const; diff --git a/src/core/separators/codac2_SepCartProd.cpp b/src/core/separators/codac2_SepCartProd.cpp index 7ddd8b88..a0025406 100644 --- a/src/core/separators/codac2_SepCartProd.cpp +++ b/src/core/separators/codac2_SepCartProd.cpp @@ -17,7 +17,7 @@ BoxPair SepCartProd::separate(const IntervalVector& x) const assert_release(x.size() == this->size()); auto x_in = x, x_out = x; - size_t i = 0; + Index i = 0; for(const auto& si : _seps) { IntervalVector xi = x.subvector(i,i+si->size()-1); diff --git a/src/core/separators/codac2_SepCartProd.h b/src/core/separators/codac2_SepCartProd.h index 9b0ab408..e15aa1bb 100644 --- a/src/core/separators/codac2_SepCartProd.h +++ b/src/core/separators/codac2_SepCartProd.h @@ -23,7 +23,7 @@ namespace codac2 SepCartProd(const Collection& seps) : Sep([seps] { - size_t n = 0; + Index n = 0; for(const auto& si : seps) n += si->size(); return n; diff --git a/src/core/separators/codac2_SepCtcBoundary.cpp b/src/core/separators/codac2_SepCtcBoundary.cpp index 89866c79..77adafeb 100644 --- a/src/core/separators/codac2_SepCtcBoundary.cpp +++ b/src/core/separators/codac2_SepCtcBoundary.cpp @@ -16,7 +16,7 @@ BoxPair SepCtcBoundary::separate(const IntervalVector& x) const { assert_release(x.size() == this->size()); - size_t attempt_nb = 5; + Index attempt_nb = 5; IntervalVector x_boundary(x); _ctc_boundary.front().contract(x_boundary); @@ -29,7 +29,7 @@ BoxPair SepCtcBoundary::separate(const IntervalVector& x) const Vector m = b.mid(); // first try: midpoint of the box BoolInterval d; - size_t k = 0; + Index k = 0; do { diff --git a/src/core/separators/codac2_SepEllipse.cpp b/src/core/separators/codac2_SepEllipse.cpp index c77e1426..1c1ac2d6 100644 --- a/src/core/separators/codac2_SepEllipse.cpp +++ b/src/core/separators/codac2_SepEllipse.cpp @@ -45,7 +45,7 @@ BoxPair SepEllipse::separate(const IntervalVector& x) const return { x_in, IntervalVector::empty(2) }; } - size_t i = Vector(x_out.rad()-p.rad()).max_coeff_index(); + Index i = Vector(x_out.rad()-p.rad()).max_coeff_index(); double e1 = p[i].lb() - x_out[i].lb(); double e2 = x_out[i].ub() - p[i].ub(); diff --git a/src/core/separators/codac2_SepProj.h b/src/core/separators/codac2_SepProj.h index 8ac409c8..c7dfa359 100644 --- a/src/core/separators/codac2_SepProj.h +++ b/src/core/separators/codac2_SepProj.h @@ -23,19 +23,19 @@ namespace codac2 template requires IsSepBaseOrPtr - SepProj(const S& s, const std::vector& proj_indices, double default_eps = 0.01) + SepProj(const S& s, const std::vector& proj_indices, double default_eps = 0.01) : SepProj(s, proj_indices, IntervalVector(size_of(s)-proj_indices.size()), default_eps) { } template requires IsSepBaseOrPtr - SepProj(const S& s, const std::vector& proj_indices, const IntervalVector& y, double default_eps = 0.01) + SepProj(const S& s, const std::vector& proj_indices, const IntervalVector& y, double default_eps = 0.01) : Sep(proj_indices.size()), ProjBase(proj_indices,y,default_eps), _sep(s) { - assert_release(_y.size() == size_of(s)-_xi.size()); + assert_release(_y.size() == size_of(s)-(Index)_xi.size()); assert_release(*min_element(_xi.begin(),_xi.end()) >= 0); assert_release(*max_element(_xi.begin(),_xi.end()) < size_of(s)); - assert_release(size_of(s) >= _xi.size() && "cannot compute a projection of a set into a superset"); + assert_release(size_of(s) >= (Index)_xi.size() && "cannot compute a projection of a set into a superset"); assert_release(default_eps > 0.); } diff --git a/src/core/tools/codac2_Approx.h b/src/core/tools/codac2_Approx.h index f40c398d..46e3ccf1 100644 --- a/src/core/tools/codac2_Approx.h +++ b/src/core/tools/codac2_Approx.h @@ -53,7 +53,7 @@ namespace codac2 { if constexpr(std::is_same_v || std::is_same_v) { - for(size_t i = 0 ; i < x1.size() ; i++) + for(Index i = 0 ; i < x1.size() ; i++) if(!(((std::fabs(_lb(x1[i])-_lb(x2._x[i])) < x2._eps) && _ub(x1[i]) == _ub(x2._x[i])) || ((std::fabs(_ub(x1[i])-_ub(x2._x[i])) < x2._eps) && _lb(x1[i]) == _lb(x2._x[i])) || ((std::fabs(_lb(x1[i])-_lb(x2._x[i])) < x2._eps) && std::fabs(_ub(x1[i])-_ub(x2._x[i])) < x2._eps))) @@ -62,8 +62,8 @@ namespace codac2 else { - for(size_t i = 0 ; i < x1.rows() ; i++) - for(size_t j = 0 ; j < x1.cols() ; j++) + for(Index i = 0 ; i < x1.rows() ; i++) + for(Index j = 0 ; j < x1.cols() ; j++) if(!(((std::fabs(_lb(x1(i,j))-_lb(x2._x(i,j))) < x2._eps) && _ub(x1(i,j)) == _ub(x2._x(i,j))) || ((std::fabs(_ub(x1(i,j))-_ub(x2._x(i,j))) < x2._eps) && _lb(x1(i,j)) == _lb(x2._x(i,j))) || ((std::fabs(_lb(x1(i,j))-_lb(x2._x(i,j))) < x2._eps) && std::fabs(_ub(x1(i,j))-_ub(x2._x(i,j))) < x2._eps))) diff --git a/src/core/tools/codac2_Index.h b/src/core/tools/codac2_Index.h new file mode 100644 index 00000000..874b0818 --- /dev/null +++ b/src/core/tools/codac2_Index.h @@ -0,0 +1,16 @@ +/** + * \file codac2_Index.h + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +namespace codac2 +{ + // The Index type is the same as for Eigen + typedef long int Index; +} \ No newline at end of file diff --git a/src/core/tools/codac2_template_tools.h b/src/core/tools/codac2_template_tools.h index 000099ef..afdc5603 100644 --- a/src/core/tools/codac2_template_tools.h +++ b/src/core/tools/codac2_template_tools.h @@ -26,22 +26,22 @@ namespace codac2 concept IsSepBaseOrPtr = (std::is_base_of_v || std::is_base_of_v>); - inline size_t size_of(int x) + inline Index size_of(int x) { return 1; } - inline size_t size_of(double x) + inline Index size_of(double x) { return 1; } - inline size_t size_of(const std::shared_ptr>& x) + inline Index size_of(const std::shared_ptr>& x) { return x->size(); } - inline size_t size_of(const std::shared_ptr& x) + inline Index size_of(const std::shared_ptr& x) { return x->size(); } @@ -50,7 +50,7 @@ namespace codac2 requires (!std::is_base_of_v>,T> && !std::is_base_of_v,T> && !std::is_same_v && !std::is_same_v) - inline size_t size_of(const T& x) + inline Index size_of(const T& x) { return x.size(); } @@ -68,7 +68,7 @@ namespace codac2 } template - size_t size_first_item(const T&... x) + Index size_first_item(const T&... x) { return size_of(std::get<0>(std::make_tuple(x...))); } diff --git a/src/graphics/figures/codac2_Figure2D.cpp b/src/graphics/figures/codac2_Figure2D.cpp index c8bda3ee..d2c93a74 100644 --- a/src/graphics/figures/codac2_Figure2D.cpp +++ b/src/graphics/figures/codac2_Figure2D.cpp @@ -7,6 +7,7 @@ * \license GNU Lesser General Public License (LGPL) */ +#include "codac2_Index.h" #include "codac2_Figure2D.h" #include "codac2_Figure2D_VIBes.h" #include "codac2_Figure2D_IPE.h" @@ -35,7 +36,7 @@ const std::string& Figure2D::name() const return _name; } -size_t Figure2D::size() const +Index Figure2D::size() const { return _axes.size(); } diff --git a/src/graphics/figures/codac2_Figure2D.h b/src/graphics/figures/codac2_Figure2D.h index a068e1f9..f92384ee 100644 --- a/src/graphics/figures/codac2_Figure2D.h +++ b/src/graphics/figures/codac2_Figure2D.h @@ -12,6 +12,7 @@ #include #include #include +#include "codac2_Index.h" #include "codac2_Figure2DInterface.h" #include "codac2_OutputFigure2D.h" #include "codac2_Paving.h" @@ -34,12 +35,12 @@ namespace codac2 struct FigureAxis { - size_t dim_id; + Index dim_id; Interval limits; std::string label; }; - inline FigureAxis axis(size_t dim_id, const Interval& limits, const std::string& label = "") + inline FigureAxis axis(Index dim_id, const Interval& limits, const std::string& label = "") { assert_release(dim_id >= 0); //assert_release(!limits.is_empty()); @@ -64,7 +65,7 @@ namespace codac2 Figure2D(const std::string& name, GraphicOutput o, bool set_as_default = false); const std::string& name() const; - size_t size() const; + Index size() const; const std::vector& axes() const; void set_axes(const FigureAxis& axis1, const FigureAxis& axis2); diff --git a/src/graphics/figures/codac2_OutputFigure2D.cpp b/src/graphics/figures/codac2_OutputFigure2D.cpp index bfd81aaa..56d37b26 100644 --- a/src/graphics/figures/codac2_OutputFigure2D.cpp +++ b/src/graphics/figures/codac2_OutputFigure2D.cpp @@ -14,12 +14,12 @@ using namespace std; using namespace codac2; -const size_t& OutputFigure2D::i() const +const Index& OutputFigure2D::i() const { return _fig.axes()[0].dim_id; } -const size_t& OutputFigure2D::j() const +const Index& OutputFigure2D::j() const { return _fig.axes()[1].dim_id; } \ No newline at end of file diff --git a/src/graphics/figures/codac2_OutputFigure2D.h b/src/graphics/figures/codac2_OutputFigure2D.h index 1059029d..d222c927 100644 --- a/src/graphics/figures/codac2_OutputFigure2D.h +++ b/src/graphics/figures/codac2_OutputFigure2D.h @@ -27,8 +27,8 @@ namespace codac2 : _fig(fig) { } - const size_t& i() const; - const size_t& j() const; + const Index& i() const; + const Index& j() const; virtual void update_axes() = 0; virtual void update_window_properties() = 0; diff --git a/src/graphics/paver/codac2_drawwhilepaving.cpp b/src/graphics/paver/codac2_drawwhilepaving.cpp index c147b5a0..aeeb5bfd 100644 --- a/src/graphics/paver/codac2_drawwhilepaving.cpp +++ b/src/graphics/paver/codac2_drawwhilepaving.cpp @@ -54,7 +54,7 @@ namespace codac2 fig->draw_box(x0, StyleProperties::outside()); list l { x0 }; - size_t n = 0; + Index n = 0; while(!l.empty()) { @@ -103,7 +103,7 @@ namespace codac2 clock_t t_start = clock(); list l { x0 }; - size_t n_inner = 0, n_boundary = 0; + Index n_inner = 0, n_boundary = 0; while(!l.empty()) { diff --git a/tests/core/domains/interval/codac2_tests_IntervalVector.cpp b/tests/core/domains/interval/codac2_tests_IntervalVector.cpp index 850522e5..3e52d181 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalVector.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalVector.cpp @@ -33,7 +33,7 @@ void CHECK_diff(const IntervalVector& x, const IntervalVector& y, bool compactne for(const auto& ci : c) { bool found = false; - for(size_t i = 0 ; i < result.rows() ; i++) + for(Index i = 0 ; i < result.rows() ; i++) if(ci == IntervalMatrix(result.row(i)).transpose().col(0)) { found = true; From 62078ed35a8df454fe0731d0da862f44a6a4807c Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 21 Nov 2024 16:56:21 +0100 Subject: [PATCH 045/102] [ellips] updates with new matrices implementation --- .../domains/ellipsoid/codac2_Ellipsoid.cpp | 88 +++++++++---------- src/core/domains/ellipsoid/codac2_Ellipsoid.h | 4 +- src/graphics/figures/codac2_Figure2D.cpp | 12 +-- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp b/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp index 1cf11247..dc09379c 100644 --- a/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp +++ b/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp @@ -15,17 +15,17 @@ using namespace std; using namespace codac2; namespace codac2 { - Ellipsoid::Ellipsoid(size_t n) + Ellipsoid::Ellipsoid(Index n) : mu(Vector(n)), G(Matrix(n, n)) { assert_release(n > 0); } Ellipsoid::Ellipsoid(const Vector &mu_, const Matrix &G_) : mu(mu_), G(G_) { - assert_release(mu_.size() == G_.nb_cols() && G_.is_squared()); + assert_release(mu_.size() == G_.cols() && G_.is_squared()); } - size_t Ellipsoid::size() const { + Index Ellipsoid::size() const { return mu.size(); } @@ -33,14 +33,14 @@ namespace codac2 { { auto xi = Vector::random(this->size()); double rand_norm = ((double) std::rand() / (RAND_MAX)); - return this->mu._e + this->G._e * xi._e / xi._e.norm() * rand_norm; + return this->mu + this->G * xi / xi.norm() * rand_norm; } IntervalVector Ellipsoid::hull_box() const { IntervalVector hull(size()); - for(size_t i=0; i< size(); i++){ - double m = G._e.col(i).norm(); + for(Index i=0; i< size(); i++){ + double m = G.col(i).norm(); hull[i] = Interval(-m, m); } return hull; @@ -48,21 +48,21 @@ namespace codac2 { BoolInterval Ellipsoid::is_concentric_subset(const Ellipsoid& e) const { - size_t n = size(); + Index n = size(); assert_release(n == e.size()); - if((mu._e - e.mu._e).norm() > 1e-10) // check if the centers are the same + if((mu - e.mu).norm() > 1e-10) // check if the centers are the same return BoolInterval::FALSE; // not concentric auto I = Matrix::eye(n,n); - auto G2_inv = e.G._e.inverse(); - IntervalMatrix D(I._e - G._e.transpose() * G2_inv.transpose() * G2_inv * G._e); + auto G2_inv = e.G.inverse(); + IntervalMatrix D(I - G.transpose() * G2_inv.transpose() * G2_inv * G); // cholesky decomposition of D = L*L^T IntervalMatrix L(n,n); // matrix of the Cholesky decomposition - for (size_t j = 0; j < n; j++) // for every column + for (Index j = 0; j < n; j++) // for every column { // diagonal element Interval s = 0.; @@ -75,11 +75,11 @@ namespace codac2 { L(j,j) = sqrt(u); // then the rest of the column - for (size_t i = j + 1; i(); - auto e_res_mu_ = e_res.mu._e.template cast(); - auto e_res_G_ = e_res.G._e.template cast(); - auto e_G_ = e.G._e.template cast(); - auto A_ = A._e.template cast(); - auto b_ = b._e.template cast(); + auto e_mu_ = e.mu.template cast(); + auto e_res_mu_ = e_res.mu.template cast(); + auto e_res_G_ = e_res.G.template cast(); + auto e_G_ = e.G.template cast(); + auto A_ = A.template cast(); + auto b_ = b.template cast(); IntervalVector unit_box_(n, {-1,1}); // compute rounding error as a small box auto mu_res_guaranteed = A_ * e_mu_ + b_; auto G_res_guaranteed = A_ * e_G_; auto error_box_ = mu_res_guaranteed - e_res_mu_ + - (G_res_guaranteed - e_res_G_) * unit_box_._e; + (G_res_guaranteed - e_res_G_) * unit_box_; double rho = error_box_.norm().ub(); // max radius of error_box Ellipsoid elli_error(Vector::zeros(n), @@ -148,41 +148,41 @@ namespace codac2 { Matrix nonlinear_mapping_base(const Matrix &G, const Matrix &J, const IntervalMatrix &J_box, const Vector& trig, const Vector& q) { - size_t n = G.nb_cols(); + Index n = G.cols(); assert(G.is_squared() && J.is_squared() && J_box.is_squared()); - assert(n == J.nb_cols() && n == J_box.nb_cols() && n == q.size()); + assert(n == J.cols() && n == J_box.cols() && n == q.size()); Matrix JG = J * G; // note: reliability may be lost here! IntervalMatrix G_(G); IntervalMatrix JG_ = IntervalMatrix(JG); - IntervalVector unit_box(G.nb_rows(), Interval(-1, 1)); + IntervalVector unit_box(G.rows(), Interval(-1, 1)); // normal case - IntervalMatrix I_ = IntervalMatrix(Eigen::MatrixXd::Identity(G.nb_rows(),G.nb_cols())); - IntervalMatrix JG_inv_(JG._e.inverse()); // non rigourous inversion + IntervalMatrix I_ = IntervalMatrix(Eigen::MatrixXd::Identity(G.rows(),G.cols())); + IntervalMatrix JG_inv_(JG.inverse()); // non rigourous inversion Matrix M(JG); - auto W = JG_inv_._e; - auto Z = I_._e; + auto W = JG_inv_; + auto Z = I_; // check for singularities - if(std::abs(JG._e.determinant()) < trig[0]) + if(std::abs(JG.determinant()) < trig[0]) { /* degenerated case from * Louedec, M., Jaulin, L., & Viel, C. (2024). * "Outer enclosures of nonlinear mapping with degenerate ellipsoids." * IFAC ACNDC June 2024*/ assert(trig.size() == 2); - assert(q.size() == G.nb_rows()); + assert(q.size() == G.rows()); // SVD decomposition of JG = U*E*V.T - Eigen::BDCSVD bdcsvd(JG._e,Eigen::ComputeFullU); + Eigen::BDCSVD bdcsvd(JG,Eigen::ComputeFullU); IntervalMatrix U_(bdcsvd.matrixU()); // which is also the right part Vector Sv(bdcsvd.singularValues()); // vectors of singular values // select new singular values - int dim = G.nb_rows(); - IntervalVector s_box(U_._e.transpose()*J_box._e*G_._e*unit_box._e); + int dim = G.rows(); + IntervalVector s_box(U_.transpose()*J_box*G_*unit_box); IntervalMatrix S_(Eigen::MatrixXd::Zero(dim,dim)); // diagonal matrix of the new singular value IntervalMatrix S_pinv_(Eigen::MatrixXd::Zero(dim,dim)); // pseudo inverse of S for(int i=0;i 2) { // affine space of the projection - Vector d(Eigen::VectorXd::Zero(e.mu.nb_rows())); - Matrix T(Eigen::MatrixXd::Zero(e.G.nb_rows(), 2)); + Vector d(Eigen::VectorXd::Zero(e.mu.rows())); + Matrix T(Eigen::MatrixXd::Zero(e.G.rows(), 2)); T(output_fig->i(), 0) = 1; T(output_fig->j(), 1) = 1; @@ -214,19 +214,19 @@ void Figure2D::draw_ellipsoid(const Ellipsoid &e, const StyleProperties &s) { // on the affine plan A = {x|x=d+Tt} [Pope -2008] // reduce the dimensions of mu and Q - auto TTG = T._e.transpose() * e.G._e; + auto TTG = T.transpose() * e.G; Eigen::BDCSVD bdcsvd(TTG, Eigen::ComputeFullU); Matrix U(bdcsvd.matrixU()); Matrix E((Eigen::MatrixXd) bdcsvd.singularValues().asDiagonal()); - G_draw = U._e * E._e; - mu_draw = T._e.transpose() * (d._e + T._e * T._e.transpose() * (e.mu._e - d._e)); + G_draw = U * E; + mu_draw = T.transpose() * (d + T * T.transpose() * (e.mu - d)); } else { G_draw = e.G; mu_draw = e.mu; } // draw the 2d ellipsoid - Eigen::JacobiSVD jsvd(G_draw._e, Eigen::ComputeThinU); + Eigen::JacobiSVD jsvd(G_draw, Eigen::ComputeThinU); Matrix U(jsvd.matrixU()); Vector ab(jsvd.singularValues()); From 5921d4ca07c8a5defebd085ba16e5a5ce80abc72 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 21 Nov 2024 18:38:57 +0100 Subject: [PATCH 046/102] [mat] updates (block,random,mid..) --- .../src/core/matrices/codac2_py_MatrixBase.h | 22 ++++++++++++++- .../src/core/matrices/codac2_py_VectorBase.h | 8 ++++++ .../matrices/eigen/codac2_Base_eigenaddons.h | 7 ++++- .../eigen/codac2_MatrixBase_eigenaddons.h | 28 +++++++------------ .../eigen/codac2_VectorBase_eigenaddons.h | 10 +++++++ .../matrices/eigen/codac2_eigenaddons_test.h | 21 ++++++++++++++ 6 files changed, 76 insertions(+), 20 deletions(-) diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index 2fd913ae..d29a1ee6 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -65,6 +65,18 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) }, BASE_EIGENADDONS_SCALAR_MAX_COEFF_CONST) + .def("norm", [](const S& x) + { + return x.norm(); + }, + DOC_TO_BE_DEFINED) + + .def("squared_norm", [](const S& x) + { + return x.squared_norm(); + }, + BASE_EIGENADDONS_AUTO_SQUARED_NORM_CONST) + ; if constexpr(!VECTOR_INHERITANCE) @@ -213,10 +225,18 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) .def_static("eye", [](Index_type r, Index_type c) { matlab::test_integer(r,c); - return S::ones(r,c); + return S::eye(r,c); }, MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_EYE_INDEX_INDEX, "r"_a, "c"_a) + + .def_static("random", [](Index_type r, Index_type c) + { + matlab::test_integer(r,c); + return S::random(r,c); + }, + MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_RANDOM_INDEX_INDEX, + "r"_a, "c"_a) ; } diff --git a/python/src/core/matrices/codac2_py_VectorBase.h b/python/src/core/matrices/codac2_py_VectorBase.h index 1763e498..edd06286 100644 --- a/python/src/core/matrices/codac2_py_VectorBase.h +++ b/python/src/core/matrices/codac2_py_VectorBase.h @@ -92,6 +92,14 @@ void export_VectorBase(py::module& m, py::class_& pyclass) }, VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ONES_INDEX, "n"_a) + + .def_static("random", [](Index_type n) + { + matlab::test_integer(n); + return S::random(n); + }, + VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_RANDOM_INDEX, + "n"_a) .def("__repr__", [](const S& x) { diff --git a/src/core/matrices/eigen/codac2_Base_eigenaddons.h b/src/core/matrices/eigen/codac2_Base_eigenaddons.h index 67a911bc..1a7bc504 100644 --- a/src/core/matrices/eigen/codac2_Base_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_Base_eigenaddons.h @@ -24,7 +24,7 @@ Matrix(const Matrix& x) template inline Scalar& operator()(Index i, Index j) { - return const_cast(const_cast*>(this)->operator()(i,j)); + return const_cast(static_cast&>(*this).operator()(i,j)); } template @@ -61,6 +61,11 @@ inline bool is_squared() const return this->rows() == this->cols(); } +inline auto squared_norm() const +{ + return this->squaredNorm(); +} + #define minmax_item(op) \ Scalar m = *(this->data()); /* first element */ \ for(Index i = 1 ; i < this->size() ; i++) \ diff --git a/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h b/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h index cf769a2c..7d68049d 100644 --- a/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h @@ -44,24 +44,6 @@ explicit Matrix(int r, int c, const Scalar values[]) } } -template - requires (!IsVectorOrRow) -inline auto block(Index i, Index j, Index p, Index q) -{ - assert_release(i >= 0 && p > 0 && i+p <= this->rows()); - assert_release(j >= 0 && q > 0 && j+q <= this->cols()); - return this->PlainObjectBase>::block(i,j,p,q); -} - -template - requires (!IsVectorOrRow) -inline auto block(Index i, Index j, Index p, Index q) const -{ - assert_release(i >= 0 && p > 0 && i+p <= this->rows()); - assert_release(j >= 0 && q > 0 && j+q <= this->cols()); - return this->PlainObjectBase>::block(i,j,p,q); -} - template requires (!IsVectorOrRow) inline static Matrix zeros(Index r, Index c) @@ -86,6 +68,16 @@ inline static Matrix eye(Index r, Index c) return Matrix::Identity(r,c); } +// Note that this static function is not called "rand" +// because of ambiguity with the member function "rand" +template + requires (!IsVectorOrRow) +inline static Matrix random(Index r, Index c) +{ + assert_release(r >= 0 && c >= 0); + return Matrix::Random(r,c); +} + template requires (!IsVectorOrRow) inline void resize_save_values(Index r, Index c) diff --git a/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h b/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h index 2495a4d6..2f0aa75f 100644 --- a/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h @@ -84,6 +84,16 @@ inline static Matrix ones(Index n) return Matrix::Ones(n,1); } +// Note that this static function is not called "rand" +// because of ambiguity with the member function "rand" +template + requires IsVectorOrRow +inline static Matrix random(Index n) +{ + assert_release(n >= 0); + return Matrix::Random(n); +} + template requires IsVectorOrRow inline auto subvector(Index start_id, Index end_id) const diff --git a/src/core/matrices/eigen/codac2_eigenaddons_test.h b/src/core/matrices/eigen/codac2_eigenaddons_test.h index 95ff6a38..1b431877 100644 --- a/src/core/matrices/eigen/codac2_eigenaddons_test.h +++ b/src/core/matrices/eigen/codac2_eigenaddons_test.h @@ -22,4 +22,25 @@ inline bool is_empty() const if((*this)(i,j).is_empty()) return true; return false; +} + + +#define degenerate_matt(op) \ + Matrix op(this->rows(),this->cols()); \ + \ + if(this->is_empty()) \ + op.init(std::numeric_limits::quiet_NaN()); \ + \ + else \ + { \ + for(Index i = 0 ; i < this->rows() ; i++) \ + for(Index j = 0 ; j < this->cols() ; j++) \ + op(i,j) = (*this)(i,j).mid(); \ + } \ + \ + return op; \ + +inline auto mid() const +{ + degenerate_matt(mid); } \ No newline at end of file From 33ce2e9842a032fd01766416bb18b661253b1d4b Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 21 Nov 2024 19:10:21 +0100 Subject: [PATCH 047/102] [cmake] now using Eigen as git submodule --- .gitmodules | 3 +++ CMakeLists.txt | 3 ++- src/core/matrices/eigen/codac2_Base_eigenaddons.h | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 4dbf077b..6bb00244 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "python/pybind11"] path = python/pybind11 url = https://github.com/pybind/pybind11 +[submodule "3rd/eigen"] + path = 3rd/eigen + url = https://github.com/codac-team/eigen diff --git a/CMakeLists.txt b/CMakeLists.txt index 4faabbb1..3bc5581e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,7 +88,8 @@ # Looking for Eigen3 ################################################################################ - find_package(Eigen3 3.4 REQUIRED NO_MODULE) + add_subdirectory(3rd/eigen) + #find_package(Eigen3 3.4 REQUIRED NO_MODULE) message(STATUS "Found Eigen3 version ${Eigen3_VERSION}") add_definitions(${EIGEN3_DEFINITIONS}) diff --git a/src/core/matrices/eigen/codac2_Base_eigenaddons.h b/src/core/matrices/eigen/codac2_Base_eigenaddons.h index 1a7bc504..d7af3d9b 100644 --- a/src/core/matrices/eigen/codac2_Base_eigenaddons.h +++ b/src/core/matrices/eigen/codac2_Base_eigenaddons.h @@ -13,9 +13,9 @@ * \license GNU Lesser General Public License (LGPL) */ -template +template requires (R_ != RowsAtCompileTime || C_ != ColsAtCompileTime) -Matrix(const Matrix& x) +Matrix(const Matrix& x) : Matrix(x.rows(),x.cols()) { *this = x.template cast(); From b352bc691da6e3c7492ddcefbeabb9ffdc4d41f2 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 21 Nov 2024 19:19:30 +0100 Subject: [PATCH 048/102] [actions] updates: local Eigen as submodule --- .github/workflows/tests.yml | 4 ++-- .github/workflows/unixmatrix.yml | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 931ef953..0efbe9c8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -43,7 +43,7 @@ jobs: sudo sh -c 'echo "deb [trusted=yes] https://packages.ensta-bretagne.fr/$(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 update - sudo apt-get -y install flex bison libeigen3-dev + sudo apt-get -y install flex bison # libeigen3-dev # For documentation pip install sphinx breathe sphinx-issues sphinx-tabs sphinx_rtd_theme @@ -80,7 +80,7 @@ jobs: cd $ORIGIN_DIR pwd ls - git submodule init ; git submodule update # for pybind11 submodule + git submodule init ; git submodule update # for pybind11/eigen submodules mkdir build -p cd build diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index 5a65a3bc..c5a37b52 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -119,7 +119,7 @@ jobs: echo export BASHMINGWPATH=/c/ProgramData/mingw64/mingw${{ matrix.cfg.bitness }}/bin>>%USERPROFILE%\.bashrc if: (matrix.cfg.runtime=='mingw13') - run: | - choco install -y -r --no-progress eigen --version=3.4.0.20240224 ${{ matrix.cfg.choco_flags }} + #choco install -y -r --no-progress eigen --version=3.4.0.20240224 ${{ matrix.cfg.choco_flags }} wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex.2.8.9.20241117.nupkg --no-check-certificate -nv choco install -y -r --no-progress --ignore-dependencies -s . ibex --version=2.8.9.20241117 ${{ matrix.cfg.choco_flags }} --params "'/url:https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip'" del /f /q ibex.2.8.9.20241117.nupkg @@ -127,15 +127,15 @@ jobs: - run: | sudo sh -c 'echo "deb [trusted=yes] https://packages.ensta-bretagne.fr/$(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' # Replace this line by the next ones to test a specific binary package of IBEX. - #sudo apt-get -q update ; sudo apt-get -y install libibex-dev libeigen3-dev dpkg-dev || true - sudo apt-get -q update ; sudo apt-get -y install libeigen3-dev dpkg-dev || true + #sudo apt-get -q update ; sudo apt-get -y install libibex-dev dpkg-dev || true + sudo apt-get -q update ; sudo apt-get -y install dpkg-dev || true wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb --no-check-certificate -nv sudo dpkg -i libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb rm -Rf libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_$(dpkg --print-architecture).deb shell: bash if: matrix.cfg.deb==true - run: | - brew install eigen + #brew install eigen wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip --no-check-certificate -nv unzip -q ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip rm -Rf ibex_${{ matrix.cfg.arch }}_${{ matrix.cfg.runtime }}.zip @@ -145,6 +145,7 @@ jobs: # shell: bash - run: | if [ ${{ runner.os }} = Windows ]; then source ~/refreshenv.bashrc ; refreshenv ; export PATH=$BASHMINGWPATH:$PATH ; fi + git submodule init ; git submodule update mkdir build ; cd build cmake -E env CXXFLAGS="${{ matrix.cfg.cmake_flags }}" CFLAGS="${{ matrix.cfg.cmake_flags }}" cmake ${{ matrix.cfg.cmake_params }} -D CMAKE_INSTALL_PREFIX="../codac" .. cmake --build . -j 4 --config Debug --target install @@ -156,7 +157,7 @@ jobs: - run: | if [ ${{ runner.os }} = Windows ]; then source ~/refreshenv.bashrc ; refreshenv ; export PATH=$BASHMINGWPATH:$PATH ; fi mkdir -p codac_standalone/example ; cd codac_standalone - wget https://community.chocolatey.org/api/v2/package/eigen/3.4.0.20240224 --no-check-certificate -nv ; unzip -q 3.4.0.20240224 -d eigen ; rm -Rf 3.4.0.20240224 eigen/*.xml eigen/*.nuspec eigen/_* eigen/package eigen/tools + #wget https://community.chocolatey.org/api/v2/package/eigen/3.4.0.20240224 --no-check-certificate -nv ; unzip -q 3.4.0.20240224 -d eigen ; rm -Rf 3.4.0.20240224 eigen/*.xml eigen/*.nuspec eigen/_* eigen/package eigen/tools if [ ${{ runner.os }} = Windows ]; then cp -Rf /C/ProgramData/chocolatey/lib/ibex . ; rm -Rf ibex/tools ibex/ibex.* elif [ ${{ matrix.cfg.deb }} = true ]; then mkdir -p ibex/include ; mkdir -p ibex/lib ; mkdir -p ibex/share ; mkdir -p ibex/bin ; cp -Rf /usr/include/ibex* ibex/include/ ; cp -Rf /usr/lib/*ibex* ibex/lib/ ; cp -Rf /usr/share/*ibex* ibex/share/ ; cp -Rf /usr/share/pkgconfig ibex/share/ ; cp -Rf /usr/bin/ibex* ibex/bin/ else cp -Rf ../ibex . From 4fa461725e6f2ec7754e5889cce6e002d5a1987f Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 21 Nov 2024 19:23:02 +0100 Subject: [PATCH 049/102] [cmake] now using Eigen as git submodule --- 3rd/eigen | 1 + 1 file changed, 1 insertion(+) create mode 160000 3rd/eigen diff --git a/3rd/eigen b/3rd/eigen new file mode 160000 index 00000000..f0955eec --- /dev/null +++ b/3rd/eigen @@ -0,0 +1 @@ +Subproject commit f0955eec9c80f8ff7c074266ca53000e6a2e91c3 From ae2f9aeb4c5f427873ea5dd6633898ff12cfff86 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 21 Nov 2024 19:49:32 +0100 Subject: [PATCH 050/102] [cmake] updates for Eigen --- examples/01_batman/CMakeLists.txt | 11 +---------- examples/02_centered_form/CMakeLists.txt | 11 +---------- src/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/examples/01_batman/CMakeLists.txt b/examples/01_batman/CMakeLists.txt index 3c62a678..314b49ff 100644 --- a/examples/01_batman/CMakeLists.txt +++ b/examples/01_batman/CMakeLists.txt @@ -18,15 +18,6 @@ ibex_init_common() # IBEX should have installed this function message(STATUS "Found IBEX version ${IBEX_VERSION}") -# Adding Eigen3 - - # In case you installed Eigen3 in a local directory, you need - # to specify its path with the CMAKE_PREFIX_PATH option, e.g. - # set(CMAKE_PREFIX_PATH "~/eigen/build_install") - - find_package(Eigen3 3.4 REQUIRED NO_MODULE) - message(STATUS "Found Eigen3 version ${Eigen3_VERSION}") - # Adding Codac # In case you installed Codac in a local directory, you need @@ -46,4 +37,4 @@ add_executable(${PROJECT_NAME} main.cpp) target_compile_options(${PROJECT_NAME} PUBLIC ${CODAC_CXX_FLAGS}) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CODAC_INCLUDE_DIRS}) - target_link_libraries(${PROJECT_NAME} PUBLIC ${CODAC_LIBRARIES} Ibex::ibex Eigen3::Eigen) \ No newline at end of file + target_link_libraries(${PROJECT_NAME} PUBLIC ${CODAC_LIBRARIES} Ibex::ibex) \ No newline at end of file diff --git a/examples/02_centered_form/CMakeLists.txt b/examples/02_centered_form/CMakeLists.txt index 3c62a678..314b49ff 100644 --- a/examples/02_centered_form/CMakeLists.txt +++ b/examples/02_centered_form/CMakeLists.txt @@ -18,15 +18,6 @@ ibex_init_common() # IBEX should have installed this function message(STATUS "Found IBEX version ${IBEX_VERSION}") -# Adding Eigen3 - - # In case you installed Eigen3 in a local directory, you need - # to specify its path with the CMAKE_PREFIX_PATH option, e.g. - # set(CMAKE_PREFIX_PATH "~/eigen/build_install") - - find_package(Eigen3 3.4 REQUIRED NO_MODULE) - message(STATUS "Found Eigen3 version ${Eigen3_VERSION}") - # Adding Codac # In case you installed Codac in a local directory, you need @@ -46,4 +37,4 @@ add_executable(${PROJECT_NAME} main.cpp) target_compile_options(${PROJECT_NAME} PUBLIC ${CODAC_CXX_FLAGS}) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CODAC_INCLUDE_DIRS}) - target_link_libraries(${PROJECT_NAME} PUBLIC ${CODAC_LIBRARIES} Ibex::ibex Eigen3::Eigen) \ No newline at end of file + target_link_libraries(${PROJECT_NAME} PUBLIC ${CODAC_LIBRARIES} Ibex::ibex) \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f146faa7..2a3f79a4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,7 +65,7 @@ set(CODAC_VERSION ${PROJECT_VERSION}) set(CODAC_LIBRARIES \${CODAC_CORE_LIBRARY} \${CODAC_GRAPHICS_LIBRARY} \${CODAC_UNSUPPORTED_LIBRARY} \${CODAC_CORE_LIBRARY}) - set(CODAC_INCLUDE_DIRS \${CODAC_CORE_INCLUDE_DIR}/../ \${CODAC_CORE_INCLUDE_DIR} \${CODAC_GRAPHICS_INCLUDE_DIR} \${CODAC_UNSUPPORTED_INCLUDE_DIR}) + 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_C_FLAGS \"\") set(CODAC_CXX_FLAGS \"\") From 44313b1439cfdf098fe6f0e9a5183d7b3ca4fbaf Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Fri, 22 Nov 2024 17:45:22 +0100 Subject: [PATCH 051/102] [mat] moving features from Eigen::Matrix to Eigen::MatrixBase --- python/codac/core/__init__.py | 2 +- .../interval/codac2_py_IntervalMatrix.cpp | 32 +- .../interval/codac2_py_IntervalMatrixBase.h | 112 +++--- .../interval/codac2_py_IntervalVector.cpp | 47 +-- python/src/core/matrices/codac2_py_Matrix.cpp | 30 +- .../src/core/matrices/codac2_py_MatrixBase.h | 28 +- python/src/core/matrices/codac2_py_Vector.cpp | 31 +- .../src/core/matrices/codac2_py_VectorBase.h | 16 +- src/core/CMakeLists.txt | 35 +- .../eigen/codac2_IntervalMatrix_eigenaddons.h | 25 -- src/core/matrices/codac2_matrices.h | 4 +- .../codac2_MatrixBase_addons_Base.h | 46 +++ .../codac2_MatrixBase_addons_IntervalMatrix.h | 14 + ...ac2_MatrixBase_addons_IntervalMatrixBase.h | 338 ++++++++++++++++++ .../codac2_MatrixBase_addons_IntervalVector.h | 89 +++++ .../codac2_MatrixBase_addons_Matrix.h | 19 + .../codac2_MatrixBase_addons_MatrixBase.h | 14 + .../codac2_MatrixBase_addons_Vector.h | 34 ++ .../codac2_MatrixBase_addons_VectorBase.h | 30 ++ .../codac2_MatrixBase_addons_include.h | 23 ++ .../codac2_Matrix_addons_Base.h} | 38 +- .../codac2_Matrix_addons_IntervalMatrix.h} | 11 +- ...codac2_Matrix_addons_IntervalMatrixBase.h} | 324 +---------------- .../codac2_Matrix_addons_IntervalVector.h} | 89 +---- .../codac2_Matrix_addons_Matrix.h} | 2 +- .../codac2_Matrix_addons_MatrixBase.h} | 2 +- .../codac2_Matrix_addons_Vector.h} | 22 +- .../codac2_Matrix_addons_VectorBase.h} | 18 +- .../codac2_Matrix_addons_include.h | 23 ++ .../matrices/eigen/codac2_eigenaddons_test.h | 46 --- .../interval/codac2_tests_IntervalMatrix.cpp | 21 ++ .../interval/codac2_tests_IntervalVector.py | 6 +- .../analytic/codac2_tests_AnalyticFunction.py | 2 +- 33 files changed, 857 insertions(+), 716 deletions(-) delete mode 100644 src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h create mode 100644 src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Base.h create mode 100644 src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrix.h create mode 100644 src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrixBase.h create mode 100644 src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalVector.h create mode 100644 src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Matrix.h create mode 100644 src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_MatrixBase.h create mode 100644 src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Vector.h create mode 100644 src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_VectorBase.h create mode 100644 src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_include.h rename src/core/matrices/eigen/{codac2_Base_eigenaddons.h => Matrix_addons/codac2_Matrix_addons_Base.h} (77%) rename src/core/matrices/eigen/{codac2_eigenaddons.h => Matrix_addons/codac2_Matrix_addons_IntervalMatrix.h} (55%) rename src/core/{domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h => matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h} (52%) rename src/core/{domains/interval/eigen/codac2_IntervalVector_eigenaddons.h => matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalVector.h} (58%) rename src/core/matrices/eigen/{codac2_Matrix_eigenaddons.h => Matrix_addons/codac2_Matrix_addons_Matrix.h} (95%) rename src/core/matrices/eigen/{codac2_MatrixBase_eigenaddons.h => Matrix_addons/codac2_Matrix_addons_MatrixBase.h} (98%) rename src/core/matrices/eigen/{codac2_Vector_eigenaddons.h => Matrix_addons/codac2_Matrix_addons_Vector.h} (75%) rename src/core/matrices/eigen/{codac2_VectorBase_eigenaddons.h => Matrix_addons/codac2_Matrix_addons_VectorBase.h} (86%) create mode 100644 src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_include.h delete mode 100644 src/core/matrices/eigen/codac2_eigenaddons_test.h diff --git a/python/codac/core/__init__.py b/python/codac/core/__init__.py index 33f38f01..3ba61870 100644 --- a/python/codac/core/__init__.py +++ b/python/codac/core/__init__.py @@ -178,7 +178,7 @@ def cart_prod(*args): if mode != -1 and mode != 0: codac_error("cart_prod: invalid input arguments, was expecting a " + mode_str[mode] + ", got a scalar domain") mode = 0 - lst.append(IntervalVector(1,Interval(arg))) + lst.append(IntervalVector([Interval(arg)])) elif isinstance(arg, (list,Vector,IntervalVector)): if mode != -1 and mode != 0: diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp index 6575b6be..92c78bc9 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp @@ -13,17 +13,31 @@ #include #include #include +#include #include #include #include #include "codac2_py_doc.h" -#include "codac2_py_MatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_IntervalMatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_Base_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_eigenaddons_test_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_IntervalMatrix_docs.h" #include "codac2_py_IntervalMatrixBase.h" @@ -54,18 +68,18 @@ py::class_ export_IntervalMatrix(py::module& m) matlab::test_integer(r,c); return std::make_unique(r,c,x); }), - MATRIXBASE_EIGENADDONS_MATRIX_INT_INT_CONST_SCALAR_REF, + MATRIX_ADDONS_MATRIXBASE_MATRIX_INT_INT_CONST_SCALAR_REF, "r"_a, "c"_a, "x"_a) .def(py::init(), "x"_a) .def(py::init(), - INTERVALMATRIXBASE_EIGENADDONS_MATRIX_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, + MATRIX_ADDONS_INTERVALMATRIXBASE_MATRIX_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "x"_a) .def(py::init(), - INTERVALMATRIXBASE_EIGENADDONS_MATRIX_CONST_MATRIX_DOUBLERC_REF_CONST_MATRIX_DOUBLERC_REF, + MATRIX_ADDONS_INTERVALMATRIXBASE_MATRIX_CONST_MATRIX_DOUBLERC_REF_CONST_MATRIX_DOUBLERC_REF, "lb"_a, "ub"_a) .def(py::init(), @@ -112,7 +126,7 @@ py::class_ export_IntervalMatrix(py::module& m) matlab::test_integer(r,c); return IntervalMatrix::empty(r,c); }, - INTERVALMATRIXBASE_EIGENADDONS_STATIC_AUTO_EMPTY_INDEX_INDEX, + MATRIX_ADDONS_INTERVALMATRIXBASE_STATIC_AUTO_EMPTY_INDEX_INDEX, "r"_a, "c"_a) .def("__repr__", [](const IntervalMatrix& x) diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h index ef3821a7..2b3b2639 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h @@ -29,117 +29,117 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) pyclass .def("volume", &S::volume, - INTERVALMATRIXBASE_EIGENADDONS_DOUBLE_VOLUME_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_DOUBLE_VOLUME_CONST) .def("is_empty", &S::is_empty, - EIGENADDONS_TEST_BOOL_IS_EMPTY_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_EMPTY_CONST) .def("set_empty", &S::set_empty, - INTERVALMATRIXBASE_EIGENADDONS_VOID_SET_EMPTY) + MATRIX_ADDONS_INTERVALMATRIXBASE_VOID_SET_EMPTY) .def("lb", [](const S& x) { return x.lb(); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_LB_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_AUTO_LB_CONST) .def("ub", [](const S& x) { return x.ub(); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_UB_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_AUTO_UB_CONST) .def("mid", [](const S& x) { return x.mid(); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_MID_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_AUTO_MID_CONST) .def("mag", [](const S& x) { return x.mag(); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_MAG_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_AUTO_MAG_CONST) .def("mig", [](const S& x) { return x.mig(); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_MIG_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_AUTO_MIG_CONST) .def("rand", [](const S& x) { return x.rand(); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_RAND_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_AUTO_RAND_CONST) .def("rad", [](const S& x) { return x.rad(); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_RAD_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_AUTO_RAD_CONST) .def("diam", [](const S& x) { return x.diam(); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_DIAM_CONST) + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_AUTO_DIAM_CONST) .def("min_diam", [](const S& x) { return x.min_diam(); }, - INTERVALMATRIXBASE_EIGENADDONS_DOUBLE_MIN_DIAM_CONST) + MATRIX_ADDONS_INTERVALMATRIXBASE_DOUBLE_MIN_DIAM_CONST) .def("max_diam", [](const S& x) { return x.max_diam(); }, - INTERVALMATRIXBASE_EIGENADDONS_DOUBLE_MAX_DIAM_CONST) + MATRIX_ADDONS_INTERVALMATRIXBASE_DOUBLE_MAX_DIAM_CONST) .def("min_diam_index", [](const S& x) { return matlab::output_index(x.min_diam_index()); }, - INTERVALMATRIXBASE_EIGENADDONS_INDEX_MIN_DIAM_INDEX_CONST) + MATRIX_ADDONS_INTERVALMATRIXBASE_INDEX_MIN_DIAM_INDEX_CONST) .def("max_diam_index", [](const S& x) { return matlab::output_index(x.max_diam_index()); }, - INTERVALMATRIXBASE_EIGENADDONS_INDEX_MAX_DIAM_INDEX_CONST) + MATRIX_ADDONS_INTERVALMATRIXBASE_INDEX_MAX_DIAM_INDEX_CONST) .def("extr_diam_index", [](const S& x, bool min) { return matlab::output_index(x.extr_diam_index(min)); }, - INTERVALMATRIXBASE_EIGENADDONS_INDEX_EXTR_DIAM_INDEX_BOOL_CONST, + MATRIX_ADDONS_INTERVALMATRIXBASE_INDEX_EXTR_DIAM_INDEX_BOOL_CONST, "min"_a) - .def("__contains__", &S::contains, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_CONTAINS_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("__contains__", [](const S& x, const V& y) { return x.contains(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_CONTAINS_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("contains", &S::contains, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_CONTAINS_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("contains", [](const S& x, const V& y) { return x.contains(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_CONTAINS_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("interior_contains", &S::interior_contains, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_INTERIOR_CONTAINS_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("interior_contains", [](const S& x, const V& y) { return x.interior_contains(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_INTERIOR_CONTAINS_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("is_unbounded", &S::is_unbounded, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_UNBOUNDED_CONST) + .def("is_unbounded", [](const S& x) { return x.is_unbounded(); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_UNBOUNDED_CONST) - .def("is_degenerated", &S::is_degenerated, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_DEGENERATED_CONST) + .def("is_degenerated", [](const S& x) { return x.is_degenerated(); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_DEGENERATED_CONST) - .def("is_flat", &S::is_flat, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_FLAT_CONST) + .def("is_flat", [](const S& x) { return x.is_flat(); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_FLAT_CONST) - .def("intersects", &S::intersects, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_INTERSECTS_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("intersects", [](const S& x, const S& y) { return x.intersects(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_INTERSECTS_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("is_disjoint", &S::is_disjoint, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_DISJOINT_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("is_disjoint", [](const S& x, const S& y) { return x.is_disjoint(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_DISJOINT_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("overlaps", &S::overlaps, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_OVERLAPS_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("overlaps", [](const S& x, const S& y) { return x.overlaps(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_OVERLAPS_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("is_subset", &S::is_subset, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_SUBSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("is_subset", [](const S& x, const S& y) { return x.is_subset(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_SUBSET_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("is_strict_subset", &S::is_strict_subset, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_STRICT_SUBSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("is_strict_subset", [](const S& x, const S& y) { return x.is_strict_subset(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_STRICT_SUBSET_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("is_interior_subset", &S::is_interior_subset, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_INTERIOR_SUBSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("is_interior_subset", [](const S& x, const S& y) { return x.is_interior_subset(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_INTERIOR_SUBSET_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("is_strict_interior_subset", &S::is_strict_interior_subset, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_STRICT_INTERIOR_SUBSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("is_strict_interior_subset", [](const S& x, const S& y) { return x.is_strict_interior_subset(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_STRICT_INTERIOR_SUBSET_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("is_superset", &S::is_superset, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_SUPERSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("is_superset", [](const S& x, const S& y) { return x.is_superset(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_SUPERSET_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("is_strict_superset", &S::is_strict_superset, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_STRICT_SUPERSET_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST) + .def("is_strict_superset", [](const S& x, const S& y) { return x.is_strict_superset(y); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_STRICT_SUPERSET_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST) - .def("is_bisectable", &S::is_bisectable, - INTERVALMATRIXBASE_EIGENADDONS_BOOL_IS_BISECTABLE_CONST) + .def("is_bisectable", [](const S& x) { return x.is_bisectable(); }, + MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_BISECTABLE_CONST) .def("inflate", (S&(S::*)(double))&S::inflate, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_REF_INFLATE_DOUBLE, + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_INFLATE_DOUBLE, "r"_a) .def("inflate", (S&(S::*)(const V&))&S::inflate, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_REF_INFLATE_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_INFLATE_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "r"_a) .def("bisect", [](const S& x, Index_type i, double ratio) @@ -147,27 +147,27 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(i); return x.bisect(matlab::input_index(i),ratio); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_BISECT_INDEX_FLOAT_CONST, + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_BISECT_INDEX_FLOAT_CONST, "i"_a, "ratio"_a = 0.49) .def("bisect_largest", [](const S& x, double ratio = 0.49) { return x.bisect_largest(); }, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_BISECT_LARGEST_FLOAT_CONST, + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_BISECT_LARGEST_FLOAT_CONST, "ratio"_a = 0.49) .def(py::self &= py::self, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_REF_OPERATORANDEQ_CONST_MATRIX_U_ROWSATCOMPILETIMECOLSATCOMPILETIME_REF + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_OPERATORANDEQ_CONST_MATRIX_U_ROWSATCOMPILETIMECOLSATCOMPILETIME_REF "x"_a) .def(py::self |= py::self, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_REF_OPERATOROREQ_CONST_MATRIX_U_ROWSATCOMPILETIMECOLSATCOMPILETIME_REF + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_OPERATOROREQ_CONST_MATRIX_U_ROWSATCOMPILETIMECOLSATCOMPILETIME_REF "x"_a) .def(py::self & py::self, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_OPERATORAND_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_OPERATORAND_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST "x"_a) .def(py::self | py::self, - INTERVALMATRIXBASE_EIGENADDONS_AUTO_OPERATOROR_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST, + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_OPERATOROR_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST, "x"_a) ; diff --git a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp index 30c199e1..b68c0d6e 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp @@ -16,14 +16,24 @@ #include #include "codac2_py_doc.h" -#include "codac2_py_MatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_VectorBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_IntervalMatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_IntervalVector_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_Base_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_eigenaddons_test_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_IntervalVector_docs.h" #include "codac2_py_VectorBase.h" #include "codac2_py_IntervalMatrixBase.h" @@ -47,27 +57,18 @@ py::class_ export_IntervalVector(py::module& m) matlab::test_integer(n); return std::make_unique(n); }), - INTERVALVECTOR_EIGENADDONS_MATRIX_INT, + MATRIX_ADDONS_INTERVALVECTOR_MATRIX_INT, "n"_a) - .def(py::init( - [](Index_type n, const Interval& x) - { - matlab::test_integer(n); - return std::make_unique((int)n,x); - }), - VECTORBASE_EIGENADDONS_MATRIX_INT_CONST_SCALAR_REF, - "n"_a, "x"_a) - .def(py::init(), "x"_a) .def(py::init(), - INTERVALMATRIXBASE_EIGENADDONS_MATRIX_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, + MATRIX_ADDONS_INTERVALMATRIXBASE_MATRIX_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "x"_a) .def(py::init(), - INTERVALMATRIXBASE_EIGENADDONS_MATRIX_CONST_MATRIX_DOUBLERC_REF_CONST_MATRIX_DOUBLERC_REF, + MATRIX_ADDONS_INTERVALMATRIXBASE_MATRIX_CONST_MATRIX_DOUBLERC_REF_CONST_MATRIX_DOUBLERC_REF, "lb"_a, "ub"_a) .def(py::init( // this constructor must be the last one to be declared @@ -78,14 +79,14 @@ py::class_ export_IntervalVector(py::module& m) (*iv)[i] = v[i]; return iv; }), - INTERVALVECTOR_EIGENADDONS_MATRIX_CONST_INITIALIZER_LIST_INTERVAL_REF, + MATRIX_ADDONS_INTERVALVECTOR_MATRIX_CONST_INITIALIZER_LIST_INTERVAL_REF, "v"_a) .def("complementary", [](const IntervalVector& x) { return x.complementary(); }, - INTERVALVECTOR_EIGENADDONS_AUTO_COMPLEMENTARY_CONST) + MATRIXBASE_ADDONS_INTERVALVECTOR_AUTO_COMPLEMENTARY_CONST) .def("diff", [](const IntervalVector& x, const IntervalVector& y, bool compactness = true) { return x.diff(y,compactness); }, - INTERVALVECTOR_EIGENADDONS_LIST_MATRIX_INTERVALRC_DIFF_CONST_MATRIX_INTERVALRC_REF_BOOL_CONST, + MATRIXBASE_ADDONS_INTERVALVECTOR_LIST_MATRIX_INTERVALRC_DIFF_CONST_MATRIXBASE_OTHERDERIVED_REF_BOOL_CONST, "y"_a, "compactness"_a = true) .def_static("empty", [](Index_type n) @@ -93,7 +94,7 @@ py::class_ export_IntervalVector(py::module& m) matlab::test_integer(n); return IntervalVector::empty(n); }, - INTERVALVECTOR_EIGENADDONS_STATIC_AUTO_EMPTY_INDEX, + MATRIX_ADDONS_INTERVALVECTOR_STATIC_AUTO_EMPTY_INDEX, "n"_a) .def("__repr__", [](const IntervalVector& x) diff --git a/python/src/core/matrices/codac2_py_Matrix.cpp b/python/src/core/matrices/codac2_py_Matrix.cpp index 8a08b717..31ec6ce2 100644 --- a/python/src/core/matrices/codac2_py_Matrix.cpp +++ b/python/src/core/matrices/codac2_py_Matrix.cpp @@ -15,11 +15,24 @@ #include #include "codac2_py_doc.h" -#include "codac2_py_MatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_Base_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_eigenaddons_test_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_docs.h" #include "codac2_py_MatrixBase.h" @@ -44,15 +57,6 @@ py::class_ export_Matrix(py::module& m) DOC_TO_BE_DEFINED, "r"_a, "c"_a) - .def(py::init( - [](Index_type r, Index_type c, double x) - { - matlab::test_integer(r,c); - return std::make_unique((int)r,(int)c,x); - }), - MATRIXBASE_EIGENADDONS_MATRIX_INT_INT_CONST_SCALAR_REF, - "r"_a, "c"_a, "x"_a) - .def(py::init(), DOC_TO_BE_DEFINED, "x"_a) diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index d29a1ee6..3a1dec66 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -57,13 +57,13 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { return x.min_coeff(); }, - BASE_EIGENADDONS_SCALAR_MIN_COEFF_CONST) + MATRIXBASE_ADDONS_BASE_SCALAR_MIN_COEFF_CONST) .def("max_coeff", [](const S& x) { return x.max_coeff(); }, - BASE_EIGENADDONS_SCALAR_MAX_COEFF_CONST) + MATRIXBASE_ADDONS_BASE_SCALAR_MAX_COEFF_CONST) .def("norm", [](const S& x) { @@ -75,7 +75,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { return x.squared_norm(); }, - BASE_EIGENADDONS_AUTO_SQUARED_NORM_CONST) + MATRIXBASE_ADDONS_BASE_AUTO_SQUARED_NORM_CONST) ; @@ -87,7 +87,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { return x.is_squared(); }, - BASE_EIGENADDONS_BOOL_IS_SQUARED_CONST) + MATRIXBASE_ADDONS_BASE_BOOL_IS_SQUARED_CONST) .def("__getitem__", [](const S& x, const py::tuple& ij) -> const T& { @@ -99,7 +99,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) return x(matlab::input_index(i), matlab::input_index(j)); }, py::return_value_policy::reference_internal, - BASE_EIGENADDONS_CONST_SCALAR_REF_OPERATORCALL_INDEX_INDEX_CONST) + MATRIX_ADDONS_BASE_CONST_SCALAR_REF_OPERATORCALL_INDEX_INDEX_CONST) .def("__setitem__", [](S& x, const py::tuple& ij, const T& a) { @@ -111,7 +111,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) x(matlab::input_index(i), matlab::input_index(j)) = a; }, - BASE_EIGENADDONS_SCALAR_REF_OPERATORCALL_INDEX_INDEX) + MATRIX_ADDONS_BASE_SCALAR_REF_OPERATORCALL_INDEX_INDEX) ; } @@ -122,14 +122,14 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) { x.init(a); }, - BASE_EIGENADDONS_AUTO_REF_INIT_CONST_SCALAR_REF, + MATRIX_ADDONS_BASE_AUTO_REF_INIT_CONST_SCALAR_REF, "x"_a) .def("init", [](S& x, const S& a) { x.init(a); }, - BASE_EIGENADDONS_AUTO_REF_INIT_CONST_MATRIX_SCALARROWSATCOMPILETIMECOLSATCOMPILETIME_REF, + MATRIX_ADDONS_BASE_AUTO_REF_INIT_CONST_MATRIX_SCALARROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "x"_a) .def("__repr__", [](const S& x) @@ -188,7 +188,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(i,j); return x(matlab::input_index(i),matlab::input_index(j)); }, py::return_value_policy::reference_internal, - BASE_EIGENADDONS_SCALAR_REF_OPERATORCALL_INDEX_INDEX) + MATRIX_ADDONS_BASE_SCALAR_REF_OPERATORCALL_INDEX_INDEX) .def("resize", [](S& x, Index_type nb_rows, Index_type nb_cols) { @@ -203,7 +203,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(nb_rows, nb_cols); x.resize_save_values(nb_rows, nb_cols); }, - MATRIXBASE_EIGENADDONS_VOID_RESIZE_SAVE_VALUES_INDEX_INDEX, + MATRIX_ADDONS_MATRIXBASE_VOID_RESIZE_SAVE_VALUES_INDEX_INDEX, "nb_rows"_a, "nb_cols"_a) .def_static("zeros", [](Index_type r, Index_type c) @@ -211,7 +211,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::zeros(r,c); }, - MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ZEROS_INDEX_INDEX, + MATRIX_ADDONS_MATRIXBASE_STATIC_MATRIX_SCALARRC_ZEROS_INDEX_INDEX, "r"_a, "c"_a) .def_static("ones", [](Index_type r, Index_type c) @@ -219,7 +219,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::ones(r,c); }, - MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ONES_INDEX_INDEX, + MATRIX_ADDONS_MATRIXBASE_STATIC_MATRIX_SCALARRC_ONES_INDEX_INDEX, "r"_a, "c"_a) .def_static("eye", [](Index_type r, Index_type c) @@ -227,7 +227,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::eye(r,c); }, - MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_EYE_INDEX_INDEX, + MATRIX_ADDONS_MATRIXBASE_STATIC_MATRIX_SCALARRC_EYE_INDEX_INDEX, "r"_a, "c"_a) .def_static("random", [](Index_type r, Index_type c) @@ -235,7 +235,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) matlab::test_integer(r,c); return S::random(r,c); }, - MATRIXBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_RANDOM_INDEX_INDEX, + MATRIX_ADDONS_MATRIXBASE_STATIC_MATRIX_SCALARRC_RANDOM_INDEX_INDEX, "r"_a, "c"_a) ; diff --git a/python/src/core/matrices/codac2_py_Vector.cpp b/python/src/core/matrices/codac2_py_Vector.cpp index d305e755..9bf3a1ea 100644 --- a/python/src/core/matrices/codac2_py_Vector.cpp +++ b/python/src/core/matrices/codac2_py_Vector.cpp @@ -15,13 +15,24 @@ #include #include "codac2_py_doc.h" -#include "codac2_py_MatrixBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_Vector_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_VectorBase_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_Base_eigenaddons_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) -#include "codac2_py_eigenaddons_test_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Vector_docs.h" #include "codac2_py_VectorBase.h" @@ -44,7 +55,7 @@ py::class_ export_Vector(py::module& m) matlab::test_integer(n); return std::make_unique(n); }), - VECTOR_EIGENADDONS_MATRIX_INT, + MATRIX_ADDONS_VECTOR_MATRIX_INT, "n"_a) .def(py::init(), @@ -58,20 +69,20 @@ py::class_ export_Vector(py::module& m) (*v)[i] = v_[i]; return v; }), - VECTOR_EIGENADDONS_MATRIX_INITIALIZER_LIST_DOUBLE, + MATRIX_ADDONS_VECTOR_MATRIX_INITIALIZER_LIST_DOUBLE, "v"_a) .def("min_coeff_index", [](const Vector& x) { return matlab::output_index(x.min_coeff_index()); }, - VECTOR_EIGENADDONS_INDEX_MIN_COEFF_INDEX_CONST) + MATRIXBASE_ADDONS_VECTOR_INDEX_MIN_COEFF_INDEX_CONST) .def("max_coeff_index", [](const Vector& x) { return matlab::output_index(x.max_coeff_index()); }, - VECTOR_EIGENADDONS_INDEX_MAX_COEFF_INDEX_CONST) + MATRIXBASE_ADDONS_VECTOR_INDEX_MAX_COEFF_INDEX_CONST) .def("__repr__", [](const Vector& x) { diff --git a/python/src/core/matrices/codac2_py_VectorBase.h b/python/src/core/matrices/codac2_py_VectorBase.h index edd06286..e396bca0 100644 --- a/python/src/core/matrices/codac2_py_VectorBase.h +++ b/python/src/core/matrices/codac2_py_VectorBase.h @@ -36,21 +36,21 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(index); return x[matlab::input_index(index)]; }, py::return_value_policy::reference_internal, - VECTORBASE_EIGENADDONS_CONST_SCALAR_REF_OPERATORCOMPO_INDEX_CONST) + MATRIX_ADDONS_VECTORBASE_CONST_SCALAR_REF_OPERATORCOMPO_INDEX_CONST) .def("__setitem__", [](S& x, Index_type index, const T& a) { matlab::test_integer(index); x[matlab::input_index(index)] = a; }, - VECTORBASE_EIGENADDONS_SCALAR_REF_OPERATORCOMPO_INDEX) + MATRIX_ADDONS_VECTORBASE_SCALAR_REF_OPERATORCOMPO_INDEX) .def("subvector", [](const S& x, Index_type start_id, Index_type end_id) -> S { matlab::test_integer(start_id, end_id); return x.subvector(matlab::input_index(start_id), matlab::input_index(end_id)); }, - VECTORBASE_EIGENADDONS_AUTO_SUBVECTOR_INDEX_INDEX_CONST, + MATRIXBASE_ADDONS_VECTORBASE_AUTO_SUBVECTOR_INDEX_INDEX_CONST, "start_id"_a, "end_id"_a) .def("resize", [](S& x, Index_type n) @@ -66,7 +66,7 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(n); x.resize_save_values(n); }, - VECTORBASE_EIGENADDONS_VOID_RESIZE_SAVE_VALUES_INDEX, + MATRIX_ADDONS_VECTORBASE_VOID_RESIZE_SAVE_VALUES_INDEX, "n"_a) .def("put", [](S& x, Index_type start_id, const S& x1) @@ -74,7 +74,7 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(start_id); x.put(matlab::input_index(start_id), x1); }, - VECTORBASE_EIGENADDONS_VOID_PUT_INDEX_CONST_MATRIX_SCALARRC_REF, + MATRIX_ADDONS_VECTORBASE_VOID_PUT_INDEX_CONST_MATRIX_SCALARRC_REF, "start_id"_a, "x"_a) .def_static("zeros", [](Index_type n) @@ -82,7 +82,7 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(n); return S::zeros(n); }, - VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ZEROS_INDEX, + MATRIX_ADDONS_VECTORBASE_STATIC_MATRIX_SCALARRC_ZEROS_INDEX, "n"_a) .def_static("ones", [](Index_type n) @@ -90,7 +90,7 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(n); return S::ones(n); }, - VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_ONES_INDEX, + MATRIX_ADDONS_VECTORBASE_STATIC_MATRIX_SCALARRC_ONES_INDEX, "n"_a) .def_static("random", [](Index_type n) @@ -98,7 +98,7 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(n); return S::random(n); }, - VECTORBASE_EIGENADDONS_STATIC_MATRIX_SCALARRC_RANDOM_INDEX, + MATRIX_ADDONS_VECTORBASE_STATIC_MATRIX_SCALARRC_RANDOM_INDEX, "n"_a) .def("__repr__", [](const S& x) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 69ffe13d..56c2808d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -57,9 +57,6 @@ ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_IntervalMatrix.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_IntervalRow.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_IntervalVector.h - ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h - ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h - ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/paving/codac2_Paving.cpp ${CMAKE_CURRENT_SOURCE_DIR}/domains/paving/codac2_Paving.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/paving/codac2_PavingNode.h @@ -89,6 +86,26 @@ ${CMAKE_CURRENT_SOURCE_DIR}/geometry/codac2_geometry.h ${CMAKE_CURRENT_SOURCE_DIR}/geometry/codac2_Polygon.cpp ${CMAKE_CURRENT_SOURCE_DIR}/geometry/codac2_Polygon.h + + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Base.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons/codac2_Matrix_addons_include.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrix.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalVector.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Matrix.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons/codac2_Matrix_addons_MatrixBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Vector.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h + + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Base.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_include.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrix.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrixBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalVector.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Matrix.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_MatrixBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Vector.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_VectorBase.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_GaussJordan.cpp ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_GaussJordan.h @@ -96,13 +113,6 @@ ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Matrix.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Row.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Vector.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_Base_eigenaddons.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_eigenaddons.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_eigenaddons_test.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_Matrix_eigenaddons.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_MatrixBase_eigenaddons.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_Vector_eigenaddons.h - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/codac2_VectorBase_eigenaddons.h ${CMAKE_CURRENT_SOURCE_DIR}/paver/codac2_pave.cpp ${CMAKE_CURRENT_SOURCE_DIR}/paver/codac2_pave.h @@ -172,7 +182,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/graphics/ipe ${CMAKE_CURRENT_SOURCE_DIR}/graphics/vibes ${CMAKE_CURRENT_SOURCE_DIR}/matrices - ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/Matrix_addons + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/eigen/MatrixBase_addons ${CMAKE_CURRENT_SOURCE_DIR}/paver ${CMAKE_CURRENT_SOURCE_DIR}/proj ${CMAKE_CURRENT_SOURCE_DIR}/separators @@ -210,7 +221,7 @@ file(APPEND ${CODAC_CORE_MAIN_HEADER} "#pragma once\n\n") foreach(header_path ${CODAC_CORE_HDR}) get_filename_component(header_name ${header_path} NAME) - if(NOT header_name MATCHES "^.*eigenaddons.*$") + if(NOT header_name MATCHES "^.*_addons.*$") file(APPEND ${CODAC_CORE_MAIN_HEADER} "#include <${header_name}>\n") endif() endforeach() diff --git a/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h b/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h deleted file mode 100644 index 1077dba3..00000000 --- a/src/core/domains/interval/eigen/codac2_IntervalMatrix_eigenaddons.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * \file codac2_IntervalMatrix_eigenaddons.h - * - * This file is included in the declaration of Eigen::MatrixBase, - * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. - * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html - * and the file codac2_matrices.h - * - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2023 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -//template -// requires (IsIntervalDomain && (!IsVectorOrRow) -// && (std::is_same_v,IV> && ...)) -//Matrix(const IV&... x) -// : Matrix(sizeof...(IV), std::get<0>(std::tie(x...)).size()) -//{ -// Index i = 0; -// ((this->row(i++) = x), ...); -// assert_release(i == rows() && "invalid input size"); -//} \ No newline at end of file diff --git a/src/core/matrices/codac2_matrices.h b/src/core/matrices/codac2_matrices.h index 1b3963df..b313d279 100644 --- a/src/core/matrices/codac2_matrices.h +++ b/src/core/matrices/codac2_matrices.h @@ -32,8 +32,8 @@ namespace Eigen concept IsIntervalDomain = std::is_same_v; } -#define EIGEN_MATRIX_PLUGIN "codac2_eigenaddons.h" -#define EIGEN_MATRIXBASE_PLUGIN "codac2_eigenaddons_test.h" +#define EIGEN_MATRIXBASE_PLUGIN "codac2_MatrixBase_addons_include.h" +#define EIGEN_MATRIX_PLUGIN "codac2_Matrix_addons_include.h" #ifndef EIGEN_NO_DEBUG /* Disables Eigen's assertions if defined. diff --git a/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Base.h b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Base.h new file mode 100644 index 00000000..ae49d330 --- /dev/null +++ b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Base.h @@ -0,0 +1,46 @@ +/** + * \file codac2_MatrixBase_addons_Base.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +inline bool is_squared() const +{ + return this->rows() == this->cols(); +} + +inline auto squared_norm() const +{ + return this->squaredNorm(); +} + +#define minmax_item(op) \ + Scalar m = (*this)(0,0); /* first element */ \ + for(Index i = 0 ; i < this->rows() ; i++) \ + for(Index j = 0 ; j < this->cols() ; j++) \ + { \ + if constexpr(std::is_same_v) \ + m = codac2::op(m,(*this)(i,j)); \ + else \ + m = std::op(m,(*this)(i,j)); \ + } \ + return m; \ + +inline Scalar min_coeff() const +{ + minmax_item(min); +} + +inline Scalar max_coeff() const +{ + minmax_item(max); +} \ No newline at end of file diff --git a/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrix.h b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrix.h new file mode 100644 index 00000000..fba89179 --- /dev/null +++ b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrix.h @@ -0,0 +1,14 @@ +/** + * \file codac2_MatrixBase_addons_IntervalMatrix.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ diff --git a/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrixBase.h b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrixBase.h new file mode 100644 index 00000000..54993bd9 --- /dev/null +++ b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalMatrixBase.h @@ -0,0 +1,338 @@ +/** + * \file codac2_MatrixBase_addons_IntervalMatrixBase.h + * + * This class reuses some of the functions developed for ibex::IntervalMatrixBase. + * The original IBEX code is revised in modern C++ and adapted to the template + * structure proposed in Codac, based on the Eigen library. + * See ibex::IntervalMatrixBase (IBEX lib, author: Gilles Chabert) + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Gilles Chabert + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +template + requires IsIntervalDomain +inline double volume() const +{ + if(this->is_empty()) + return 0.; + + double v = 0.; + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + { + if((*this)(i,j).is_unbounded()) return codac2::oo; + if((*this)(i,j).is_degenerated()) return 0.; + v += std::log((*this)(i,j).diam()); + } + return std::exp(v); +} + +inline bool is_empty() const +{ + for(Index i = 0 ; i < rows() ; i++) + for(Index j = 0 ; j < cols() ; j++) + if((*this)(i,j).is_empty()) + return true; + return false; +} + +#define degenerate_mat(op) \ + Matrix m(this->rows(),this->cols()); \ + \ + if(this->is_empty()) \ + m.init(std::numeric_limits::quiet_NaN()); \ + \ + else \ + { \ + for(Index i = 0 ; i < this->rows() ; i++) \ + for(Index j = 0 ; j < this->cols() ; j++) \ + m(i,j) = (*this)(i,j).op(); \ + } \ + \ + return m; \ + +template + requires IsIntervalDomain +inline auto lb() const +{ + degenerate_mat(lb); +} + +template + requires IsIntervalDomain +inline auto ub() const +{ + degenerate_mat(ub); +} + +template + requires IsIntervalDomain +inline auto mid() const +{ + degenerate_mat(mid); +} + +template + requires IsIntervalDomain +inline auto mag() const +{ + degenerate_mat(mag); +} + +template + requires IsIntervalDomain +inline auto mig() const +{ + degenerate_mat(mig); +} + +template + requires IsIntervalDomain +inline auto rand() const +{ + srand(time(NULL)); + degenerate_mat(rand); +} + +template + requires IsIntervalDomain +inline auto rad() const +{ + degenerate_mat(rad); +} + +template + requires IsIntervalDomain +inline auto diam() const +{ + degenerate_mat(diam); +} + +template +inline bool contains(const MatrixBase& x) const +{ + assert_release(x.size() == this->size()); + + if(this->is_empty()) + return false; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(!(*this)(i,j).contains(x(i,j))) + return false; + + return true; +} + +template +inline bool interior_contains(const MatrixBase& x) const +{ + assert_release(x.size() == this->size()); + + if(this->is_empty()) + return false; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(!(*this)(i,j).interior_contains(x(i,j))) + return false; + + return true; +} + +inline bool is_unbounded() const +{ + if(this->is_empty()) return false; + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if((*this)(i,j).is_unbounded()) + return true; + return false; +} + +inline bool is_degenerated() const +{ + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(!(*this)(i,j).is_degenerated()) + return false; + return true; +} + +inline bool is_flat() const +{ + if(this->is_empty()) return true; + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if((*this)(i,j).is_degenerated()) // don't use diam() because of roundoff + return true; + return false; +} + +template +inline bool intersects(const MatrixBase& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return false; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(!(*this)(i,j).intersects(x(i,j))) + return false; + + return true; +} + +template +inline bool is_disjoint(const MatrixBase& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if((*this)(i,j).is_disjoint(x(i,j))) + return true; + + return false; +} + +template +inline bool overlaps(const MatrixBase& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return false; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(!(*this)(i,j).overlaps(x(i,j))) + return false; + + return true; +} + +template +inline bool is_subset(const MatrixBase& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(!(*this)(i,j).is_subset(x(i,j))) + return false; + + return true; +} + +template +inline bool is_strict_subset(const MatrixBase& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + if(!is_subset(x)) + return false; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if((*this)(i,j).is_strict_subset(x(i,j))) + return true; + + return false; +} + +template +inline bool is_interior_subset(const MatrixBase& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(!(*this)(i,j).is_interior_subset(x(i,j))) + return false; + + return true; +} + +template +inline bool is_strict_interior_subset(const MatrixBase& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return true; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(!(*this)(i,j).is_strict_interior_subset(x(i,j))) + return false; + + return true; +} + +template +inline bool is_superset(const MatrixBase& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return false; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(!x(i,j).is_subset((*this)(i,j))) + return false; + + return true; +} + +template +inline bool is_strict_superset(const MatrixBase& x) const +{ + assert_release(this->size() == x.size()); + + if(this->is_empty()) + return false; + + if(!is_superset(x)) + return false; + + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if(x(i,j).is_strict_subset((*this)(i,j))) + return true; + + return false; +} + +inline bool is_bisectable() const +{ + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + if((*this)(i,j).is_bisectable()) + return true; + return false; +} \ No newline at end of file diff --git a/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalVector.h b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalVector.h new file mode 100644 index 00000000..d9e85d62 --- /dev/null +++ b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_IntervalVector.h @@ -0,0 +1,89 @@ +/** + * \file codac2_MatrixBase_addons_IntervalVector.h + * + * This class reuses some of the functions developed for ibex::IntervalVector. + * The original IBEX code is revised in modern C++ and adapted to the template + * structure proposed in Codac, based on the Eigen library. + * See ibex::IntervalVector (IBEX lib, author: Gilles Chabert) + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Gilles Chabert + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +template + requires IsIntervalDomain && IsVectorOrRow +inline auto complementary() const +{ + return Matrix((int)this->size()).diff(*this); +} + +template + requires IsIntervalDomain && IsVectorOrRow +inline std::list> diff(const MatrixBase& y, bool compactness = true) const +{ + // This code originates from the ibex-lib + // See: ibex_TemplateVector.h + // Author: Gilles Chabert + // It has been revised with modern C++ and templated types + + const Index n = this->size(); + assert_release(y.size() == n); + + if(y == *this) + return { }; + + Matrix x = *this; + Matrix z = x & y; + + if(z.is_empty()) + { + if(x.is_empty()) return { }; + else return { x }; + } + + else + { + // Check if in one dimension y is flat and x not, + // in which case the diff returns also x directly + if(compactness) + for(Index i = 0 ; i < n ; i++) + if(z[i].is_degenerated() && !x[i].is_degenerated()) + { + if(x.is_empty()) return { }; + else return { x }; + } + } + + std::list> l; + + for(Index var = 0 ; var < n ; var++) + { + codac2::Interval c1, c2; + + for(const auto& ci : x[var].diff(y[var], compactness)) + { + assert(!ci.is_empty()); + + Matrix v(n); + for(Index i = 0 ; i < var ; i++) + v[i] = x[i]; + v[var] = ci; + for(Index i = var+1 ; i < n ; i++) + v[i] = x[i]; + if(!v.is_empty()) + l.push_back(v); + } + + x[var] = z[var]; + } + + return l; +} \ No newline at end of file diff --git a/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Matrix.h b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Matrix.h new file mode 100644 index 00000000..247e837f --- /dev/null +++ b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Matrix.h @@ -0,0 +1,19 @@ +/** + * \file codac2_MatrixBase_addons_Matrix.h + * + * This class reuses some of the functions developed for ibex::Matrix. + * The original IBEX code is revised in modern C++ and adapted to the template + * structure proposed in Codac, based on the Eigen library. + * See ibex::Matrix (IBEX lib, author: Gilles Chabert) + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Gilles Chabert + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ diff --git a/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_MatrixBase.h b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_MatrixBase.h new file mode 100644 index 00000000..6c555930 --- /dev/null +++ b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_MatrixBase.h @@ -0,0 +1,14 @@ +/** + * \file codac2_MatrixBase_addons_MatrixBase.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ diff --git a/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Vector.h b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Vector.h new file mode 100644 index 00000000..22752f58 --- /dev/null +++ b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_Vector.h @@ -0,0 +1,34 @@ +/** + * \file codac2_MatrixBase_addons_Vector.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +template + requires (!IsIntervalDomain) && (IsVectorOrRow) +inline Index min_coeff_index() const +{ + Index r,c; + this->minCoeff(&r,&c); + assert(c == 0); + return r; +} + +template + requires (!IsIntervalDomain) && (IsVectorOrRow) +inline Index max_coeff_index() const +{ + Index r,c; + this->maxCoeff(&r,&c); + assert(c == 0); + return r; +} \ No newline at end of file diff --git a/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_VectorBase.h b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_VectorBase.h new file mode 100644 index 00000000..fe1a470d --- /dev/null +++ b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_VectorBase.h @@ -0,0 +1,30 @@ +/** + * \file codac2_MatrixBase_addons_VectorBase.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +template + requires IsVectorOrRow +inline auto diag_matrix() const +{ + return this->asDiagonal().toDenseMatrix(); +} + +template + requires IsVectorOrRow +inline auto subvector(Index start_id, Index end_id) const +{ + assert_release(end_id >= 0 && start_id >= 0); + assert_release(end_id < this->size() && start_id <= end_id); + return this->segment(start_id,end_id-start_id+1); +} \ No newline at end of file diff --git a/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_include.h b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_include.h new file mode 100644 index 00000000..30a8cb4f --- /dev/null +++ b/src/core/matrices/eigen/MatrixBase_addons/codac2_MatrixBase_addons_include.h @@ -0,0 +1,23 @@ +/** + * \file codac2_MatrixBase_addons_include.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_MatrixBase_addons_Base.h" +#include "codac2_MatrixBase_addons_IntervalMatrix.h" +#include "codac2_MatrixBase_addons_IntervalMatrixBase.h" +#include "codac2_MatrixBase_addons_IntervalVector.h" +#include "codac2_MatrixBase_addons_Matrix.h" +#include "codac2_MatrixBase_addons_MatrixBase.h" +#include "codac2_MatrixBase_addons_Vector.h" +#include "codac2_MatrixBase_addons_VectorBase.h" \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_Base_eigenaddons.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Base.h similarity index 77% rename from src/core/matrices/eigen/codac2_Base_eigenaddons.h rename to src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Base.h index d7af3d9b..8e94f720 100644 --- a/src/core/matrices/eigen/codac2_Base_eigenaddons.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Base.h @@ -1,5 +1,5 @@ /** - * \file codac2_Base_eigenaddons.h + * \file codac2_Matrix_addons_Base.h * * This file is included in the declaration of Eigen::MatrixBase, * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. @@ -56,37 +56,11 @@ inline auto& init(const Matrix& x) / return *this; } -inline bool is_squared() const -{ - return this->rows() == this->cols(); -} - -inline auto squared_norm() const -{ - return this->squaredNorm(); -} - -#define minmax_item(op) \ - Scalar m = *(this->data()); /* first element */ \ - for(Index i = 1 ; i < this->size() ; i++) \ - { \ - if constexpr(std::is_same_v) \ - m = codac2::op(m,*(this->data()+i)); \ - else \ - m = std::op(m,*(this->data()+i)); \ - } \ - return m; \ - -inline Scalar min_coeff() const -{ - minmax_item(min); -} - -inline Scalar max_coeff() const -{ - minmax_item(max); -} - +// This operator should be related to Eigen::MatrixBase, +// for allowing a comparison between two matrix expressions. +// However, it is not possible to overwrite Eigen::MatrixBase::operator==. +// Therefore, only comparisons between Eigen::Matrix types is possible. +// This must be corrected... template inline bool operator==(const Matrix& x) const { diff --git a/src/core/matrices/eigen/codac2_eigenaddons.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrix.h similarity index 55% rename from src/core/matrices/eigen/codac2_eigenaddons.h rename to src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrix.h index b2bec7db..059dfb19 100644 --- a/src/core/matrices/eigen/codac2_eigenaddons.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrix.h @@ -1,5 +1,5 @@ /** - * \file codac2_eigenaddons.h + * \file codac2_Matrix_addons_IntervalMatrix.h * * This file is included in the declaration of Eigen::MatrixBase, * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. @@ -12,12 +12,3 @@ * \copyright Copyright 2023 Codac Team * \license GNU Lesser General Public License (LGPL) */ - -#include "codac2_Base_eigenaddons.h" -#include "codac2_MatrixBase_eigenaddons.h" -#include "codac2_Matrix_eigenaddons.h" -#include "codac2_VectorBase_eigenaddons.h" -#include "codac2_Vector_eigenaddons.h" -#include "codac2_IntervalMatrixBase_eigenaddons.h" -#include "codac2_IntervalMatrix_eigenaddons.h" -#include "codac2_IntervalVector_eigenaddons.h" \ No newline at end of file diff --git a/src/core/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h similarity index 52% rename from src/core/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h rename to src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h index aff0d8e3..d3949a8c 100644 --- a/src/core/domains/interval/eigen/codac2_IntervalMatrixBase_eigenaddons.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h @@ -1,5 +1,5 @@ /** - * \file codac2_IntervalMatrixBase_eigenaddons.h + * \file codac2_Matrix_addons_IntervalMatrixBase.h * * This class reuses some of the functions developed for ibex::IntervalMatrixBase. * The original IBEX code is revised in modern C++ and adapted to the template @@ -77,94 +77,6 @@ inline bool operator==(const MatrixBase& x) const return operator==(x.eval().template cast()); } -template - requires IsIntervalDomain -inline double volume() const -{ - if(this->is_empty()) - return 0.; - - double v = 0.; - for(Index i = 0 ; i < this->size() ; i++) - { - if((this->data()+i)->is_unbounded()) return codac2::oo; - if((this->data()+i)->is_degenerated()) return 0.; - v += std::log((this->data()+i)->diam()); - } - return std::exp(v); -} - -#define degenerate_mat(op) \ - Matrix op(this->rows(),this->cols()); \ - \ - if(this->is_empty()) \ - op.init(std::numeric_limits::quiet_NaN()); \ - \ - else \ - { \ - for(Index i = 0 ; i < this->size() ; i++) \ - *(op.data()+i) = (this->data()+i)->op(); \ - } \ - \ - return op; \ - -template - requires IsIntervalDomain -inline auto lb() const -{ - degenerate_mat(lb); -} - -template - requires IsIntervalDomain -inline auto ub() const -{ - degenerate_mat(ub); -} - -template - requires IsIntervalDomain -inline auto mid() const -{ - degenerate_mat(mid); -} - -template - requires IsIntervalDomain -inline auto mag() const -{ - degenerate_mat(mag); -} - -template - requires IsIntervalDomain -inline auto mig() const -{ - degenerate_mat(mig); -} - -template - requires IsIntervalDomain -inline auto rand() const -{ - srand(time(NULL)); - degenerate_mat(rand); -} - -template - requires IsIntervalDomain -inline auto rad() const -{ - degenerate_mat(rad); -} - -template - requires IsIntervalDomain -inline auto diam() const -{ - degenerate_mat(diam); -} - template requires IsIntervalDomain inline double min_diam() const @@ -270,16 +182,6 @@ inline Index extr_diam_index(bool min) const return selected_index; } -// to MatrixBase template -// to MatrixBase requires IsIntervalDomain -// to MatrixBase inline bool is_empty() const -// to MatrixBase { -// to MatrixBase for(Index i = 0 ; i < this->size() ; i++) -// to MatrixBase if((this->data()+i)->is_empty()) -// to MatrixBase return true; -// to MatrixBase return false; -// to MatrixBase } - template requires IsIntervalDomain inline void set_empty() @@ -287,230 +189,6 @@ inline void set_empty() this->init(codac2::Interval::empty()); } -template - requires IsIntervalDomain -inline bool contains(const Matrix& x) const -{ - assert_release(x.size() == this->size()); - - if(this->is_empty()) - return false; - - for(Index i = 0 ; i < this->size() ; i++) - if(!(this->data()+i)->contains(*(x.data()+i))) - return false; - - return true; -} - -template - requires IsIntervalDomain -inline bool interior_contains(const Matrix& x) const -{ - assert_release(x.size() == this->size()); - - if(this->is_empty()) - return false; - - for(Index i = 0 ; i < this->size() ; i++) - if(!(this->data()+i)->interior_contains(*(x.data()+i))) - return false; - - return true; -} - -template - requires IsIntervalDomain -inline bool is_unbounded() const -{ - if(this->is_empty()) return false; - for(Index i = 0 ; i < this->size() ; i++) - if((this->data()+i)->is_unbounded()) - return true; - return false; -} - -template - requires IsIntervalDomain -inline bool is_degenerated() const -{ - for(Index i = 0 ; i < this->size() ; i++) - if(!(this->data()+i)->is_degenerated()) - return false; - return true; -} - -template - requires IsIntervalDomain -inline bool is_flat() const -{ - if(this->is_empty()) return true; - for(Index i = 0 ; i < this->size() ; i++) - if((this->data()+i)->is_degenerated()) // don't use diam() because of roundoff - return true; - return false; -} - -template - requires IsIntervalDomain -inline bool intersects(const Matrix& x) const -{ - assert_release(this->size() == x.size()); - - if(this->is_empty()) - return false; - - for(Index i = 0 ; i < this->size() ; i++) - if(!(this->data()+i)->intersects(*(x.data()+i))) - return false; - - return true; -} - -template - requires IsIntervalDomain -inline bool is_disjoint(const Matrix& x) const -{ - assert_release(this->size() == x.size()); - - if(this->is_empty()) - return true; - - for(Index i = 0 ; i < this->size() ; i++) - if((this->data()+i)->is_disjoint(*(x.data()+i))) - return true; - - return false; -} - -template - requires IsIntervalDomain -inline bool overlaps(const Matrix& x) const -{ - assert_release(this->size() == x.size()); - - if(this->is_empty()) - return false; - - for(Index i = 0 ; i < this->size() ; i++) - if(!(this->data()+i)->overlaps(*(x.data()+i))) - return false; - - return true; -} - -template - requires IsIntervalDomain -inline bool is_subset(const Matrix& x) const -{ - assert_release(this->size() == x.size()); - - if(this->is_empty()) - return true; - - for(Index i = 0 ; i < this->size() ; i++) - if(!(this->data()+i)->is_subset(*(x.data()+i))) - return false; - - return true; -} - -template - requires IsIntervalDomain -inline bool is_strict_subset(const Matrix& x) const -{ - assert_release(this->size() == x.size()); - - if(this->is_empty()) - return true; - - if(!is_subset(x)) - return false; - - for(Index i = 0 ; i < this->size() ; i++) - if((this->data()+i)->is_strict_subset(*(x.data()+i))) - return true; - - return false; -} - -template - requires IsIntervalDomain -inline bool is_interior_subset(const Matrix& x) const -{ - assert_release(this->size() == x.size()); - - if(this->is_empty()) - return true; - - for(Index i = 0 ; i < this->size() ; i++) - if(!(this->data()+i)->is_interior_subset(*(x.data()+i))) - return false; - - return true; -} - -template - requires IsIntervalDomain -inline bool is_strict_interior_subset(const Matrix& x) const -{ - assert_release(this->size() == x.size()); - - if(this->is_empty()) - return true; - - for(Index i = 0 ; i < this->size() ; i++) - if(!(this->data()+i)->is_strict_interior_subset(*(x.data()+i))) - return false; - - return true; -} - -template - requires IsIntervalDomain -inline bool is_superset(const Matrix& x) const -{ - assert_release(this->size() == x.size()); - - if(this->is_empty()) - return false; - - for(Index i = 0 ; i < this->size() ; i++) - if(!(x.data()+i)->is_subset(*(this->data()+i))) - return false; - - return true; -} - -template - requires IsIntervalDomain -inline bool is_strict_superset(const Matrix& x) const -{ - assert_release(this->size() == x.size()); - - if(this->is_empty()) - return false; - - if(!is_superset(x)) - return false; - - for(Index i = 0 ; i < this->size() ; i++) - if((x.data()+i)->is_strict_subset(*(this->data()+i))) - return true; - - return false; -} - -template - requires IsIntervalDomain -inline bool is_bisectable() const -{ - for(Index i = 0 ; i < this->size() ; i++) - if((this->data()+i)->is_bisectable()) - return true; - return false; -} - template requires IsIntervalDomain inline auto& inflate(double r) diff --git a/src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalVector.h similarity index 58% rename from src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h rename to src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalVector.h index 3da9e38c..1ff3fd2c 100644 --- a/src/core/domains/interval/eigen/codac2_IntervalVector_eigenaddons.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalVector.h @@ -1,5 +1,5 @@ /** - * \file codac2_IntervalVector_eigenaddons.h + * \file codac2_Matrix_addons_IntervalVector.h * * This class reuses some of the functions developed for ibex::IntervalVector. * The original IBEX code is revised in modern C++ and adapted to the template @@ -84,23 +84,6 @@ Matrix(int n, const double bounds[][2]) assert_release(n > 0); } -//template -// requires IsIntervalDomain && IsVectorOrRow -//explicit Matrix(std::initializer_list> l) -// : Matrix( -// [&]() -> int { if constexpr(R == 1) return 1; else return l.size(); }(), -// [&]() -> int { if constexpr(C == 1) return 1; else return l.size(); }() -// ) -//{ -// assert_release(!std::empty(l)); -// Index i = 0; -// for(const auto& li : l) -// { -// assert_release(!std::empty(li)); -// (*this)[i++] = codac2::Interval(li); -// } -//} - template requires IsIntervalDomain && IsVectorOrRow inline static auto empty(Index n) @@ -110,74 +93,4 @@ inline static auto empty(Index n) return Matrix((int)n,codac2::Interval::empty()); else return Matrix((int)n,codac2::Interval::empty()); -} - -template - requires IsIntervalDomain && IsVectorOrRow -inline auto complementary() const -{ - return Matrix((int)this->size()).diff(*this); -} - -template - requires IsIntervalDomain && IsVectorOrRow -inline std::list> diff(const Matrix& y, bool compactness = true) const -{ - // This code originates from the ibex-lib - // See: ibex_TemplateVector.h - // Author: Gilles Chabert - // It has been revised with modern C++ and templated types - - const Index n = this->size(); - assert_release(y.size() == n); - - if(y == *this) - return { }; - - Matrix x = *this; - Matrix z = x & y; - - if(z.is_empty()) - { - if(x.is_empty()) return { }; - else return { x }; - } - - else - { - // Check if in one dimension y is flat and x not, - // in which case the diff returns also x directly - if(compactness) - for(Index i = 0 ; i < n ; i++) - if(z[i].is_degenerated() && !x[i].is_degenerated()) - { - if(x.is_empty()) return { }; - else return { x }; - } - } - - std::list> l; - - for(Index var = 0 ; var < n ; var++) - { - codac2::Interval c1, c2; - - for(const auto& ci : x[var].diff(y[var], compactness)) - { - assert(!ci.is_empty()); - - Matrix v(n); - for(Index i = 0 ; i < var ; i++) - v[i] = x[i]; - v[var] = ci; - for(Index i = var+1 ; i < n ; i++) - v[i] = x[i]; - if(!v.is_empty()) - l.push_back(v); - } - - x[var] = z[var]; - } - - return l; } \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_Matrix_eigenaddons.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Matrix.h similarity index 95% rename from src/core/matrices/eigen/codac2_Matrix_eigenaddons.h rename to src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Matrix.h index 90c6ec54..f6d28008 100644 --- a/src/core/matrices/eigen/codac2_Matrix_eigenaddons.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Matrix.h @@ -1,5 +1,5 @@ /** - * \file codac2_Matrix_eigenaddons.h + * \file codac2_Matrix_addons_Matrix.h * * This class reuses some of the functions developed for ibex::Matrix. * The original IBEX code is revised in modern C++ and adapted to the template diff --git a/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_MatrixBase.h similarity index 98% rename from src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h rename to src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_MatrixBase.h index 7d68049d..a4c30c33 100644 --- a/src/core/matrices/eigen/codac2_MatrixBase_eigenaddons.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_MatrixBase.h @@ -1,5 +1,5 @@ /** - * \file codac2_MatrixBase_eigenaddons.h + * \file codac2_Matrix_addons_MatrixBase.h * * This file is included in the declaration of Eigen::MatrixBase, * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. diff --git a/src/core/matrices/eigen/codac2_Vector_eigenaddons.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Vector.h similarity index 75% rename from src/core/matrices/eigen/codac2_Vector_eigenaddons.h rename to src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Vector.h index 4ad8c346..a48b9ef9 100644 --- a/src/core/matrices/eigen/codac2_Vector_eigenaddons.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Vector.h @@ -1,5 +1,5 @@ /** - * \file codac2_Vector_eigenaddons.h + * \file codac2_Matrix_addons_Vector.h * * This file is included in the declaration of Eigen::MatrixBase, * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. @@ -49,24 +49,4 @@ explicit Matrix(int n, double values[]) ) { assert_release(n > 0); -} - -template - requires (!IsIntervalDomain) && (IsVectorOrRow) -inline Index min_coeff_index() const -{ - Index r,c; - this->minCoeff(&r,&c); - assert(c == 0); - return r; -} - -template - requires (!IsIntervalDomain) && (IsVectorOrRow) -inline Index max_coeff_index() const -{ - Index r,c; - this->maxCoeff(&r,&c); - assert(c == 0); - return r; } \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h similarity index 86% rename from src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h rename to src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h index 2f0aa75f..27369af7 100644 --- a/src/core/matrices/eigen/codac2_VectorBase_eigenaddons.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h @@ -1,5 +1,5 @@ /** - * \file codac2_VectorBase_eigenaddons.h + * \file codac2_Matrix_addons_VectorBase.h * * This file is included in the declaration of Eigen::MatrixBase, * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. @@ -25,13 +25,6 @@ explicit Matrix(int n, const Scalar& x) init(x); } -template - requires IsVectorOrRow -inline auto diag_matrix() const -{ - return this->asDiagonal().toDenseMatrix(); -} - template requires IsVectorOrRow inline Scalar& operator()(Index i) @@ -94,15 +87,6 @@ inline static Matrix random(Index n) return Matrix::Random(n); } -template - requires IsVectorOrRow -inline auto subvector(Index start_id, Index end_id) const -{ - assert_release(end_id >= 0 && start_id >= 0); - assert_release(end_id < this->size() && start_id <= end_id); - return this->segment(start_id,end_id-start_id+1); -} - template requires IsVectorOrRow inline void put(Index start_id, const Matrix& x) diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_include.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_include.h new file mode 100644 index 00000000..2802ca6e --- /dev/null +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_include.h @@ -0,0 +1,23 @@ +/** + * \file codac2_Matrix_addons_include.h + * + * This file is included in the declaration of Eigen::MatrixBase, + * thanks to the preprocessor token EIGEN_MATRIX_PLUGIN. + * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html + * and the file codac2_matrices.h + * + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2023 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_Matrix_addons_Base.h" +#include "codac2_Matrix_addons_IntervalMatrix.h" +#include "codac2_Matrix_addons_IntervalMatrixBase.h" +#include "codac2_Matrix_addons_IntervalVector.h" +#include "codac2_Matrix_addons_Matrix.h" +#include "codac2_Matrix_addons_MatrixBase.h" +#include "codac2_Matrix_addons_Vector.h" +#include "codac2_Matrix_addons_VectorBase.h" \ No newline at end of file diff --git a/src/core/matrices/eigen/codac2_eigenaddons_test.h b/src/core/matrices/eigen/codac2_eigenaddons_test.h deleted file mode 100644 index 1b431877..00000000 --- a/src/core/matrices/eigen/codac2_eigenaddons_test.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - * \file codac2_eigenaddons.h - * - * This file is included in the declaration of Eigen::MatrixBase, - * thanks to the preprocessor token EIGEN_MATRIXBASE_PLUGIN. - * See: https://eigen.tuxfamily.org/dox/TopicCustomizing_Plugins.html - * and the file codac2_matrices.h - * - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Simon Rohou - * \copyright Copyright 2023 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - - - -inline bool is_empty() const -{ - for(Index i = 0 ; i < rows() ; i++) - for(Index j = 0 ; j < cols() ; j++) - if((*this)(i,j).is_empty()) - return true; - return false; -} - - -#define degenerate_matt(op) \ - Matrix op(this->rows(),this->cols()); \ - \ - if(this->is_empty()) \ - op.init(std::numeric_limits::quiet_NaN()); \ - \ - else \ - { \ - for(Index i = 0 ; i < this->rows() ; i++) \ - for(Index j = 0 ; j < this->cols() ; j++) \ - op(i,j) = (*this)(i,j).mid(); \ - } \ - \ - return op; \ - -inline auto mid() const -{ - degenerate_matt(mid); -} \ No newline at end of file diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp index f227ea11..02dd012a 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp @@ -631,6 +631,27 @@ TEST_CASE("IntervalMatrix - mixing type") IntervalMatrix im_empty(m1,m2); CHECK(im_empty == IntervalMatrix::empty(2,2)); } + + { + IntervalMatrix m1 = IntervalMatrix::ones(3,3); + IntervalMatrix m2 = IntervalMatrix::zeros(3,3); + CHECK(m1.volume() == 0.); + CHECK(m2.volume() == 0.); + CHECK((m1+m2).volume() == 0.); + } + + { + IntervalMatrix m1 { + { {1,2},{2,3} }, + { {3,4},{4,5} } + }; + Matrix m2 { + { 1.5, 2.5 }, + { 3.5, 4.5 } + }; + CHECK(m1.contains(m2)); + CHECK(m2.template cast().is_strict_subset(m1)); + } } #if 0 diff --git a/tests/core/domains/interval/codac2_tests_IntervalVector.py b/tests/core/domains/interval/codac2_tests_IntervalVector.py index 740d4c35..66edc90b 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalVector.py +++ b/tests/core/domains/interval/codac2_tests_IntervalVector.py @@ -50,7 +50,7 @@ def tests_intervalvector(self): x = IntervalVector(2) x[0] = Interval(0,1) x[1] = Interval(0,1) - self.assertTrue(x == IntervalVector(2,Interval(0,1))) + self.assertTrue(x == IntervalVector([[0,1],[0,1]])) self.assertTrue(x == IntervalVector(x)) #self.assertTrue(x == (IntervalVector(2)=x)) @@ -219,8 +219,8 @@ def tests_intervalvector(self): self.assertTrue(not IntervalVector([[0,1],[2,3],[4,5]]).is_flat()) self.assertTrue(IntervalVector.empty(3).is_flat()) - self.assertTrue(IntervalVector(1,Interval(0,0)).is_flat()) - self.assertTrue(not IntervalVector(1,Interval(0,1)).is_flat()) + self.assertTrue(IntervalVector([[0,0]]).is_flat()) + self.assertTrue(not IntervalVector([[0,1]]).is_flat()) self.assertTrue(IntervalVector([[0,1],[2,2],[3,4]]).is_flat()) self.assertTrue(IntervalVector([[0,1],[2,3],[4,4]]).is_flat()) self.assertTrue(not IntervalVector.empty(3).is_unbounded()) diff --git a/tests/core/functions/analytic/codac2_tests_AnalyticFunction.py b/tests/core/functions/analytic/codac2_tests_AnalyticFunction.py index ffefce83..2dc92337 100644 --- a/tests/core/functions/analytic/codac2_tests_AnalyticFunction.py +++ b/tests/core/functions/analytic/codac2_tests_AnalyticFunction.py @@ -96,7 +96,7 @@ def test_eval(f,*args): # .def("__rmul__", [](const ScalarVar& e1, const Interval& e2) self.assertTrue(test_eval(AnalyticFunction([x1], Interval(6.)*x1), 5.) == 30.) # .def("__mul__", [](const ScalarVar& e1, const VectorVar& e2) - self.assertTrue(test_eval(AnalyticFunction([v1,v2], v1[0]*v2), Vector([5.,10.]),IntervalVector(2,3.)) == Vector([15,15])) + self.assertTrue(test_eval(AnalyticFunction([v1,v2], v1[0]*v2), Vector([5.,10.]),IntervalVector([[3],[3]])) == Vector([15,15])) # .def("__mul__", [](const ScalarVar& e1, const IntervalVector& e2) self.assertTrue(test_eval(AnalyticFunction([x1], x1*IntervalVector([[-2,3],[0,1]])), 5.) == IntervalVector([[-10,15],[0,5]])) # .def("__truediv__", [](const ScalarVar& e1, const ScalarVar& e2) From 69ec78bed1efc925c39bb7b5a6b706bf61f937fe Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Sat, 23 Nov 2024 10:21:23 +0100 Subject: [PATCH 052/102] [mat] using OtherDerived instead of Matrix when possible --- .../interval/codac2_py_IntervalMatrixBase.h | 12 ++--- .../src/core/matrices/codac2_py_MatrixBase.h | 2 +- .../src/core/matrices/codac2_py_VectorBase.h | 2 +- src/core/matrices/codac2_matrices.h | 24 +++++----- .../codac2_Matrix_addons_IntervalMatrixBase.h | 45 ++++++++----------- .../codac2_Matrix_addons_VectorBase.h | 6 +-- .../interval/codac2_tests_IntervalMatrix.cpp | 8 ++++ 7 files changed, 50 insertions(+), 49 deletions(-) diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h index 2b3b2639..b2b48f96 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h @@ -138,8 +138,8 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_INFLATE_DOUBLE, "r"_a) - .def("inflate", (S&(S::*)(const V&))&S::inflate, - MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_INFLATE_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, + .def("inflate", [](S& x, const V& r) { return x.inflate(r); }, + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_INFLATE_CONST_MATRIXBASE_OTHERDERIVED_REF, "r"_a) .def("bisect", [](const S& x, Index_type i, double ratio) @@ -155,19 +155,19 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) "ratio"_a = 0.49) .def(py::self &= py::self, - MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_OPERATORANDEQ_CONST_MATRIX_U_ROWSATCOMPILETIMECOLSATCOMPILETIME_REF + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_OPERATORANDEQ_CONST_MATRIXBASE_OTHERDERIVED_REF "x"_a) .def(py::self |= py::self, - MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_OPERATOROREQ_CONST_MATRIX_U_ROWSATCOMPILETIMECOLSATCOMPILETIME_REF + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_OPERATOROREQ_CONST_MATRIXBASE_OTHERDERIVED_REF "x"_a) .def(py::self & py::self, - MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_OPERATORAND_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_OPERATORAND_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST "x"_a) .def(py::self | py::self, - MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_OPERATOROR_CONST_MATRIX_INTERVALROWSATCOMPILETIMECOLSATCOMPILETIME_REF_CONST, + MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_OPERATOROR_CONST_MATRIXBASE_OTHERDERIVED_REF_CONST, "x"_a) ; diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index 3a1dec66..c396c1a7 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -243,5 +243,5 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) //S abs(const MatrixBase& x) m.def("abs", [](const S& x) { return abs(x); }, - AUTO_ABS_CONST_EIGEN_MATRIX_SCALARROWSATCOMPILETIMECOLSATCOMPILETIME_REF); + AUTO_ABS_CONST_EIGEN_MATRIXBASE_OTHERDERIVED_REF); } \ No newline at end of file diff --git a/python/src/core/matrices/codac2_py_VectorBase.h b/python/src/core/matrices/codac2_py_VectorBase.h index e396bca0..c3d5efb7 100644 --- a/python/src/core/matrices/codac2_py_VectorBase.h +++ b/python/src/core/matrices/codac2_py_VectorBase.h @@ -74,7 +74,7 @@ void export_VectorBase(py::module& m, py::class_& pyclass) matlab::test_integer(start_id); x.put(matlab::input_index(start_id), x1); }, - MATRIX_ADDONS_VECTORBASE_VOID_PUT_INDEX_CONST_MATRIX_SCALARRC_REF, + MATRIX_ADDONS_VECTORBASE_VOID_PUT_INDEX_CONST_MATRIXBASE_OTHERDERIVED_REF, "start_id"_a, "x"_a) .def_static("zeros", [](Index_type n) diff --git a/src/core/matrices/codac2_matrices.h b/src/core/matrices/codac2_matrices.h index b313d279..5158b28c 100644 --- a/src/core/matrices/codac2_matrices.h +++ b/src/core/matrices/codac2_matrices.h @@ -94,18 +94,20 @@ namespace codac2 namespace codac2 { - template - inline auto abs(const Eigen::Matrix& x) + template + inline auto abs(const Eigen::MatrixBase& x) { - Eigen::Matrix a(x); - - for(int i = 0 ; i < x.size() ; i++) - { - if constexpr(std::is_same_v) - *(a.data()+i) = fabs(*(x.data()+i)); - else - *(a.data()+i) = abs(*(x.data()+i)); - } + using M = Eigen::MatrixBase; + Eigen::Matrix a(x); + + for(Index i = 0 ; i < x.rows() ; i++) + for(Index j = 0 ; j < x.cols() ; j++) + { + if constexpr(std::is_same_v) + a(i,j) = fabs(x(i,j)); + else + a(i,j) = abs(x(i,j)); + } return a; } diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h index d3949a8c..d01e4f3b 100644 --- a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h @@ -200,25 +200,26 @@ inline auto& inflate(double r) return *this; } -template +template requires IsIntervalDomain -inline auto& inflate(const Matrix& r) +inline auto& inflate(const MatrixBase& r) { assert_release(this->size() == r.size()); assert_release(r.min_coeff() >= 0.); - for(Index i = 0 ; i < this->size() ; i++) - (this->data()+i)->inflate(*(r.data()+i)); + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + (*this)(i,j).inflate(r(i,j)); return *this; } -template +template requires IsIntervalDomain -inline auto& operator&=(const Matrix& x) +inline auto& operator&=(const MatrixBase& x) { assert_release(this->size() == x.size()); - if constexpr(std::is_same_v) + if constexpr(std::is_same_v::Scalar,codac2::Interval>) { if(x.is_empty()) { @@ -227,51 +228,41 @@ inline auto& operator&=(const Matrix& x) } } - for(Index i = 0 ; i < this->size() ; i++) - *(this->data()+i) &= *(x.data()+i); - return *this; -} - -template - requires IsIntervalDomain -inline auto& operator&=(const MatrixBase& x) -{ - assert_release(this->size() == x.size()); - for(Index i = 0 ; i < this->rows() ; i++) for(Index j = 0 ; j < this->cols() ; j++) (*this)(i,j) &= x(i,j); return *this; } -template +template requires IsIntervalDomain -inline auto& operator|=(const Matrix& x) +inline auto& operator|=(const MatrixBase& x) { assert_release(this->size() == x.size()); - if constexpr(std::is_same_v) + if constexpr(std::is_same_v::Scalar,codac2::Interval>) { if(x.is_empty()) return *this; } - for(Index i = 0 ; i < this->size() ; i++) - *(this->data()+i) |= *(x.data()+i); + for(Index i = 0 ; i < this->rows() ; i++) + for(Index j = 0 ; j < this->cols() ; j++) + (*this)(i,j) |= x(i,j); return *this; } -template +template requires IsIntervalDomain -inline auto operator&(const Matrix& x) const +inline auto operator&(const MatrixBase& x) const { auto y = *this; return y &= x; } -template +template requires IsIntervalDomain -inline auto operator|(const Matrix& x) const +inline auto operator|(const MatrixBase& x) const { auto y = *this; return y |= x; diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h index 27369af7..a3d41c5f 100644 --- a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h @@ -87,9 +87,9 @@ inline static Matrix random(Index n) return Matrix::Random(n); } -template - requires IsVectorOrRow -inline void put(Index start_id, const Matrix& x) +template + requires IsVectorOrRow && IsVectorOrRow::RowsAtCompileTime,MatrixBase::ColsAtCompileTime> +inline void put(Index start_id, const MatrixBase& x) { assert_release(start_id >= 0 && start_id < this->size()); assert_release(start_id+x.size() <= this->size()); diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp index 02dd012a..2efde4cd 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp @@ -649,8 +649,16 @@ TEST_CASE("IntervalMatrix - mixing type") { 1.5, 2.5 }, { 3.5, 4.5 } }; + CHECK(m1.contains(m2)); CHECK(m2.template cast().is_strict_subset(m1)); + + Matrix m3(2,2); + m3.init(m2+m2); + CHECK(m3 == Matrix({ + { 3, 5 }, + { 7, 9 } + })); } } From 8f2eef66abce66b40937c5b3cec20c26b90184cb Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sat, 23 Nov 2024 17:42:49 +0100 Subject: [PATCH 053/102] Missing escape characters --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 6808f8b0..509e784a 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -574,14 +574,14 @@ void Figure2D_IPE::print_header_page() \n \ \n \ \n \ - \n \ + \n \ \n \ \n \ \n \ - \n \ - \n \ - \n \ - \n \ + \n \ + \n \ + \n \ + \n \ \n \ \n \ \n \ From 668902029826a456dc536d2d9ef1138b6472b44b Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sat, 23 Nov 2024 14:39:43 +0100 Subject: [PATCH 054/102] Submodules should already be OK --- .github/workflows/unixmatrix.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index c5a37b52..2668946e 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -145,7 +145,6 @@ jobs: # shell: bash - run: | if [ ${{ runner.os }} = Windows ]; then source ~/refreshenv.bashrc ; refreshenv ; export PATH=$BASHMINGWPATH:$PATH ; fi - git submodule init ; git submodule update mkdir build ; cd build cmake -E env CXXFLAGS="${{ matrix.cfg.cmake_flags }}" CFLAGS="${{ matrix.cfg.cmake_flags }}" cmake ${{ matrix.cfg.cmake_params }} -D CMAKE_INSTALL_PREFIX="../codac" .. cmake --build . -j 4 --config Debug --target install From e05074fed27b62b62a743b410a66f5a0f5f59082 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sat, 23 Nov 2024 14:36:37 +0100 Subject: [PATCH 055/102] Other changes related to Eigen dependency --- .github/workflows/dockermatrix.yml | 3 ++- .github/workflows/macosmatrix.yml | 4 ++-- .github/workflows/vcmatrix.yml | 4 ++-- packages/temporary/gennewcodacpi_armhf.sh | 3 ++- tests/test_codac/CMakeLists.txt | 12 +----------- 5 files changed, 9 insertions(+), 17 deletions(-) diff --git a/.github/workflows/dockermatrix.yml b/.github/workflows/dockermatrix.yml index 1b84294a..c91d623e 100644 --- a/.github/workflows/dockermatrix.yml +++ b/.github/workflows/dockermatrix.yml @@ -69,7 +69,8 @@ jobs: git config --global --add safe.directory ${PWD} && \ if [ ${{ matrix.cfg.deb }} = true ]; then \ sudo sh -c 'echo \"deb [trusted=yes] https://packages.ensta-bretagne.fr/\$(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 dpkg-dev || true && \ + #sudo apt-get -q update ; sudo apt-get -y install libeigen3-dev dpkg-dev || true && \\ + sudo apt-get -q update ; sudo apt-get -y install dpkg-dev || true && \ wget https://github.com/lebarsfa/ibex-lib/releases/download/ibex-2.8.9.20241117/libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb --no-check-certificate -nv && \ sudo dpkg -i libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb && \ rm -Rf libibex-dev-2.8.9.20241117-0${{ matrix.cfg.runtime }}0_\$(dpkg --print-architecture).deb ; \ diff --git a/.github/workflows/macosmatrix.yml b/.github/workflows/macosmatrix.yml index 4edfa029..057d5408 100644 --- a/.github/workflows/macosmatrix.yml +++ b/.github/workflows/macosmatrix.yml @@ -55,8 +55,8 @@ jobs: if: matrix.cfg.py_v_maj!='' - run: echo "VERBOSE=1" >> $GITHUB_ENV shell: bash - - run: brew install eigen - if: runner.os=='macOS' + #- run: brew install eigen + # if: runner.os=='macOS' - run: brew install graphviz ; brew install --formula doxygen ; python -m pip install --upgrade pip ; pip install --upgrade wheel setuptools sphinx breathe sphinx_rtd_theme sphinx-tabs sphinx-issues sphinx-reredirects if: runner.os=='macOS' - run: | diff --git a/.github/workflows/vcmatrix.yml b/.github/workflows/vcmatrix.yml index 648b5977..bf794dd9 100644 --- a/.github/workflows/vcmatrix.yml +++ b/.github/workflows/vcmatrix.yml @@ -58,8 +58,8 @@ jobs: 7z x C:\Windows\Temp\windows_extra_tools.zip -o"C:\Windows" -y shell: pwsh if: runner.os=='Windows' - - run: choco install -y -r --no-progress eigen --version=3.4.0.20240224 ${{ matrix.cfg.choco_flags }} - if: runner.os=='Windows' + #- run: choco install -y -r --no-progress eigen --version=3.4.0.20240224 ${{ matrix.cfg.choco_flags }} + # if: runner.os=='Windows' - run: choco install -y -r --no-progress graphviz doxygen.install & python -m pip install --upgrade pip & pip install --upgrade wheel setuptools sphinx breathe sphinx-issues sphinx-tabs sphinx_rtd_theme sphinx-reredirects if: runner.os=='Windows' - run: | diff --git a/packages/temporary/gennewcodacpi_armhf.sh b/packages/temporary/gennewcodacpi_armhf.sh index eab7df2e..2a69afa0 100644 --- a/packages/temporary/gennewcodacpi_armhf.sh +++ b/packages/temporary/gennewcodacpi_armhf.sh @@ -23,7 +23,8 @@ else \ PIP_OPTIONS= ; \ #python3 -m pip install \$PIP_OPTIONS --upgrade \"auditwheel==5.1.2\" ; \\ fi && \ -sudo apt-get -q update --allow-releaseinfo-change ; sudo apt-get -y install libeigen3-dev python3-dev patchelf || true && \ +#sudo apt-get -q update --allow-releaseinfo-change ; sudo apt-get -y install libeigen3-dev python3-dev patchelf || true && \\ +sudo apt-get -q update --allow-releaseinfo-change ; sudo apt-get -y install python3-dev patchelf || true && \ python3 -m pip install \$PIP_OPTIONS --upgrade patchelf --prefer-binary --extra-index-url https://www.piwheels.org/simple && \ 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.20241117/ibex_armhf_\$(lsb_release -cs).zip --no-check-certificate -nv is causing illegal instruction on a Mac M1... \\ diff --git a/tests/test_codac/CMakeLists.txt b/tests/test_codac/CMakeLists.txt index e65acc82..8841c252 100644 --- a/tests/test_codac/CMakeLists.txt +++ b/tests/test_codac/CMakeLists.txt @@ -19,16 +19,6 @@ ibex_init_common() # IBEX should have installed this function message(STATUS "Found IBEX version ${IBEX_VERSION}") -# Adding Eigen3 - - # In case you installed Eigen3 in a local directory, you need - # to specify its path with the CMAKE_PREFIX_PATH option, e.g. - # set(CMAKE_PREFIX_PATH "~/eigen/build_install") - set(CMAKE_PREFIX_PATH "../eigen") - - find_package(Eigen3 3.4 REQUIRED NO_MODULE) - message(STATUS "Found Eigen3 version ${Eigen3_VERSION}") - # Adding Codac # In case you installed Codac in a local directory, you need @@ -44,4 +34,4 @@ add_executable(${PROJECT_NAME} main.cpp) target_compile_options(${PROJECT_NAME} PUBLIC ${CODAC_CXX_FLAGS}) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CODAC_INCLUDE_DIRS}) - target_link_libraries(${PROJECT_NAME} PUBLIC ${CODAC_LIBRARIES} Ibex::ibex Eigen3::Eigen) \ No newline at end of file + target_link_libraries(${PROJECT_NAME} PUBLIC ${CODAC_LIBRARIES} Ibex::ibex) \ No newline at end of file From 7d84ab37e97f5954e9a0f925d8e58b55a7abf9f8 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sat, 23 Nov 2024 14:37:18 +0100 Subject: [PATCH 056/102] Codac packages should not depend on the default Eigen package any more --- packages/choco/codac/codac.nuspec | 3 +-- packages/deb/control | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/choco/codac/codac.nuspec b/packages/choco/codac/codac.nuspec index a4db6d02..8ca1fddf 100644 --- a/packages/choco/codac/codac.nuspec +++ b/packages/choco/codac/codac.nuspec @@ -27,7 +27,7 @@ Codac is a library providing tools for constraint programming over reals, trajec ## Package parameters The following package parameters can be set: -- `/url:URL` - Will install the specified binary package (e.g. built for Visual Studio), see versions from https://github.com/codac-team/codac/releases (the Windows `PATH` might need to be updated manually with e.g. `C:\ProgramData\chocolatey\lib\ibex\bin`, etc.). By default, only the MinGW libraries compatible with the corresponding MinGW Chocolatey package dependency are installed. Use the standard parameter `choco install --ignore-dependencies ...` to avoid installing the default MinGW and IBEX Chocolatey package dependencies if needed (you might want to install manually [IBEX](https://community.chocolatey.org/packages/ibex) package with the corresponding parameters, as well as the corresponding compiler and the Eigen package). +- `/url:URL` - Will install the specified binary package (e.g. built for Visual Studio), see versions from https://github.com/codac-team/codac/releases (the Windows `PATH` might need to be updated manually with e.g. `C:\ProgramData\chocolatey\lib\ibex\bin`, etc.). By default, only the MinGW libraries compatible with the corresponding MinGW Chocolatey package dependency are installed. Use the standard parameter `choco install --ignore-dependencies ...` to avoid installing the default MinGW and IBEX Chocolatey package dependencies if needed (you might want to install manually [IBEX](https://community.chocolatey.org/packages/ibex) package with the corresponding parameters, as well as the corresponding compiler). - `/checksum:SHA256` - SHA256 checksum of the binary package specified by the `/url` parameter. If needed, use the standard parameter `choco install --ignore-checksums ...` for trusted sources. - `/urlX:URL` - Same as above, with X in [1,99], except this will not disable the installation of the MinGW libraries compatible with the corresponding MinGW Chocolatey package dependency. - `/checksumX:SHA256` - SHA256 checksum of the binary package specified by the `/urlX` parameter. If needed, use the standard parameter `choco install --ignore-checksums ...` for trusted sources. @@ -44,7 +44,6 @@ choco install -y --ignore-dependencies codac --params "'/url:https://github.com/ - diff --git a/packages/deb/control b/packages/deb/control index 152866dc..7d652a59 100644 --- a/packages/deb/control +++ b/packages/deb/control @@ -1,7 +1,7 @@ Package: libcodac-dev Version: 1 Architecture: amd64 -Depends: libeigen3-dev (>=3.4.0), libibex-dev +Depends: libibex-dev Section: math Priority: optional Description: Codac is a library providing tools for constraint programming over reals, trajectories and sets From e88812fe219bfbf367ccd2be0d7c4ff3f8fbfd78 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Sat, 23 Nov 2024 17:31:36 +0100 Subject: [PATCH 057/102] Visual Studio 2019 might be too old --- .github/workflows/unixmatrix.yml | 4 ++-- .github/workflows/vcmatrix.yml | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index 2668946e..41c66bea 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -30,9 +30,9 @@ jobs: cfg: - { os: windows-2022, shell: cmd, arch: x64, bitness: 64, runtime: vc17, cmake_params: '-G "Visual Studio 17" -T v143 -A x64', cmake_flags: ' /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: ' /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', choco_flags: '--x86', desc: 'Windows Visual Studio 2022 x86' } - - { os: windows-2022, shell: cmd, arch: x64, bitness: 64, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A x64', cmake_flags: ' /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', desc: 'Windows Visual Studio 2019 x64' } - - { os: windows-2022, shell: cmd, arch: x86, bitness: 32, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', cmake_flags: ' /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', choco_flags: '--x86', desc: 'Windows Visual Studio 2019 x86' } # Problems related to C++20? + #- { os: windows-2022, shell: cmd, arch: x64, bitness: 64, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A x64', cmake_flags: ' /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', desc: 'Windows Visual Studio 2019 x64' } + #- { os: windows-2022, shell: cmd, arch: x86, bitness: 32, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', cmake_flags: ' /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', choco_flags: '--x86', desc: 'Windows Visual Studio 2019 x86' } #- { os: windows-2019, shell: cmd, arch: x64, bitness: 64, runtime: vc15, cmake_params: '-G "Visual Studio 16" -T v141 -A x64', cmake_flags: ' /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', desc: 'Windows Visual Studio 2017 x64' } #- { os: windows-2019, shell: cmd, arch: x86, bitness: 32, runtime: vc15, cmake_params: '-G "Visual Studio 16" -T v141 -A Win32', cmake_flags: ' /wd4267 /wd4244 /wd4305 /wd4996', test_config: 'Release/', choco_flags: '--x86', desc: 'Windows Visual Studio 2017 x86' } - { os: windows-2022, shell: cmd, arch: x64, bitness: 64, runtime: mingw13, cmake_params: '-G "MinGW Makefiles"', cmake_flags: '-fPIC', desc: 'Windows MinGW 13.2.0 x64' } diff --git a/.github/workflows/vcmatrix.yml b/.github/workflows/vcmatrix.yml index bf794dd9..f2269977 100644 --- a/.github/workflows/vcmatrix.yml +++ b/.github/workflows/vcmatrix.yml @@ -18,23 +18,23 @@ jobs: fail-fast: false matrix: cfg: + # Should be Visual Studio 2015 for Python 3.5-3.7, Visual Studio 2019 for Python 3.8-3.10, but need 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: 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' } - { 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: 11, desc: 'Windows Visual Studio 2022 x86 Python 3.11' } - - { os: windows-2022, shell: cmd, arch: x86, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 10, desc: 'Windows Visual Studio 2019 x86 Python 3.10' } - - { os: windows-2022, shell: cmd, arch: x86, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 9, desc: 'Windows Visual Studio 2019 x86 Python 3.9' } - - { os: windows-2022, shell: cmd, arch: x86, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', choco_flags: '--x86', cpcfg: '-win32', py_v_maj: 3, py_v_min: 8, desc: 'Windows Visual Studio 2019 x86 Python 3.8' } + - { 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-2022, shell: cmd, arch: x86, runtime: vc17, cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', choco_flags: '--x86', cpcfg: 'm-win32', py_v_maj: 3, py_v_min: 7, desc: 'Windows Visual Studio 2022 x86 Python 3.7' } + - { os: windows-2022, shell: cmd, arch: x86, runtime: vc17, cmake_params: '-G "Visual Studio 17" -T v143 -A Win32', choco_flags: '--x86', cpcfg: 'm-win32', py_v_maj: 3, py_v_min: 6, desc: 'Windows Visual Studio 2022 x86 Python 3.6' } - { 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' } - { 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: 11, desc: 'Windows Visual Studio 2022 x64 Python 3.11' } - - { os: windows-2022, shell: cmd, arch: x64, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A x64', cpcfg: '-win_amd64', py_v_maj: 3, py_v_min: 10, desc: 'Windows Visual Studio 2019 x64 Python 3.10' } - - { os: windows-2022, shell: cmd, arch: x64, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A x64', cpcfg: '-win_amd64', py_v_maj: 3, py_v_min: 9, desc: 'Windows Visual Studio 2019 x64 Python 3.9' } - - { os: windows-2022, shell: cmd, arch: x64, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A x64', cpcfg: '-win_amd64', py_v_maj: 3, py_v_min: 8, desc: 'Windows Visual Studio 2019 x64 Python 3.8' } - # Should be Visual Studio 2015 for Python 3.5-3.7, but need Visual Studio 2019 for C++20 compatibility...? - - { os: windows-2022, shell: cmd, arch: x86, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', choco_flags: '--x86', cpcfg: 'm-win32', py_v_maj: 3, py_v_min: 7, desc: 'Windows Visual Studio 2019 x86 Python 3.7' } - - { os: windows-2022, shell: cmd, arch: x86, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A Win32', choco_flags: '--x86', cpcfg: 'm-win32', py_v_maj: 3, py_v_min: 6, desc: 'Windows Visual Studio 2019 x86 Python 3.6' } - - { os: windows-2022, shell: cmd, arch: x64, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A x64', cpcfg: 'm-win_amd64', py_v_maj: 3, py_v_min: 7, desc: 'Windows Visual Studio 2019 x64 Python 3.7' } - - { os: windows-2022, shell: cmd, arch: x64, runtime: vc16, cmake_params: '-G "Visual Studio 17" -T v142 -A x64', cpcfg: 'm-win_amd64', py_v_maj: 3, py_v_min: 6, desc: 'Windows Visual Studio 2019 x64 Python 3.6' } + - { 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: 10, desc: 'Windows Visual Studio 2022 x64 Python 3.10' } + - { 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: 9, desc: 'Windows Visual Studio 2022 x64 Python 3.9' } + - { 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: 8, desc: 'Windows Visual Studio 2022 x64 Python 3.8' } + - { os: windows-2022, shell: cmd, arch: x64, runtime: vc17, cmake_params: '-G "Visual Studio 17" -T v143 -A x64', cpcfg: 'm-win_amd64', py_v_maj: 3, py_v_min: 7, desc: 'Windows Visual Studio 2022 x64 Python 3.7' } + - { os: windows-2022, shell: cmd, arch: x64, runtime: vc17, cmake_params: '-G "Visual Studio 17" -T v143 -A x64', cpcfg: 'm-win_amd64', py_v_maj: 3, py_v_min: 6, desc: 'Windows Visual Studio 2022 x64 Python 3.6' } name: ${{ matrix.cfg.desc }} steps: - uses: actions/checkout@v4 From e4254fa077d995ba64bc837369b7f4c6ba009555 Mon Sep 17 00:00:00 2001 From: lebarsfa Date: Mon, 25 Nov 2024 11:58:00 +0100 Subject: [PATCH 058/102] Undefining __STRICT_ANSI__ may cause issues on recent MinGW versions --- CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bc5581e..85f9e411 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,11 +62,6 @@ # add_compile_options(-std=c++2a) # else() # message(FATAL_ERROR "Codac needs a compiler with C++20 support") -# endif() - -# if(WIN32) -# # We need this for strdup under Windows (see issue #287 of ibex-lib repo) -# add_definitions(-U__STRICT_ANSI__) # endif() #if(NOT CMAKE_CXX_STANDARD) From b084c0dabc22eb9e5504c8c73ab6b84e683ce09b Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 26 Nov 2024 10:56:26 +0100 Subject: [PATCH 059/102] [examples] updated CMakeLists.txt --- examples/03_sivia/CMakeLists.txt | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/examples/03_sivia/CMakeLists.txt b/examples/03_sivia/CMakeLists.txt index 3c62a678..314b49ff 100644 --- a/examples/03_sivia/CMakeLists.txt +++ b/examples/03_sivia/CMakeLists.txt @@ -18,15 +18,6 @@ ibex_init_common() # IBEX should have installed this function message(STATUS "Found IBEX version ${IBEX_VERSION}") -# Adding Eigen3 - - # In case you installed Eigen3 in a local directory, you need - # to specify its path with the CMAKE_PREFIX_PATH option, e.g. - # set(CMAKE_PREFIX_PATH "~/eigen/build_install") - - find_package(Eigen3 3.4 REQUIRED NO_MODULE) - message(STATUS "Found Eigen3 version ${Eigen3_VERSION}") - # Adding Codac # In case you installed Codac in a local directory, you need @@ -46,4 +37,4 @@ add_executable(${PROJECT_NAME} main.cpp) target_compile_options(${PROJECT_NAME} PUBLIC ${CODAC_CXX_FLAGS}) target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CODAC_INCLUDE_DIRS}) - target_link_libraries(${PROJECT_NAME} PUBLIC ${CODAC_LIBRARIES} Ibex::ibex Eigen3::Eigen) \ No newline at end of file + target_link_libraries(${PROJECT_NAME} PUBLIC ${CODAC_LIBRARIES} Ibex::ibex) \ No newline at end of file From f853d722dff815a40f1e765cd3f2c0b7943be011 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 26 Nov 2024 13:22:03 +0100 Subject: [PATCH 060/102] [mat] updates: constructors, static functions --- .../interval/codac2_py_IntervalMatrix.cpp | 10 ------ .../interval/codac2_py_IntervalVector.cpp | 3 +- .../src/core/matrices/codac2_py_MatrixBase.h | 14 ++++++-- python/src/core/matrices/codac2_py_Vector.cpp | 2 +- .../src/core/matrices/codac2_py_VectorBase.h | 14 ++++++-- src/core/contractors/codac2_directed_ctc.cpp | 2 +- .../analytic/codac2_AnalyticFunction.h | 2 +- .../analytic/codac2_analytic_constants.h | 2 +- src/core/matrices/codac2_GaussJordan.cpp | 2 +- .../Matrix_addons/codac2_Matrix_addons_Base.h | 8 ----- .../codac2_Matrix_addons_IntervalMatrixBase.h | 15 +------- .../codac2_Matrix_addons_IntervalVector.h | 17 +--------- .../codac2_Matrix_addons_MatrixBase.h | 28 +++++++-------- .../codac2_Matrix_addons_Vector.h | 12 ------- .../codac2_Matrix_addons_VectorBase.h | 34 +++++++------------ tests/core/3rd/codac2_tests_ibex.cpp | 8 ++--- .../interval/codac2_tests_IntervalMatrix.cpp | 18 ++++++++-- tests/core/matrices/codac2_tests_Vector.py | 2 +- 18 files changed, 75 insertions(+), 118 deletions(-) diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp index 92c78bc9..d8db8bf7 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp @@ -62,20 +62,10 @@ py::class_ export_IntervalMatrix(py::module& m) DOC_TO_BE_DEFINED, "r"_a, "c"_a) - .def(py::init( - [](Index_type r, Index_type c, const Interval& x) - { - matlab::test_integer(r,c); - return std::make_unique(r,c,x); - }), - MATRIX_ADDONS_MATRIXBASE_MATRIX_INT_INT_CONST_SCALAR_REF, - "r"_a, "c"_a, "x"_a) - .def(py::init(), "x"_a) .def(py::init(), - MATRIX_ADDONS_INTERVALMATRIXBASE_MATRIX_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "x"_a) .def(py::init(), diff --git a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp index b68c0d6e..7e156941 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp @@ -57,14 +57,13 @@ py::class_ export_IntervalVector(py::module& m) matlab::test_integer(n); return std::make_unique(n); }), - MATRIX_ADDONS_INTERVALVECTOR_MATRIX_INT, + DOC_TO_BE_DEFINED, "n"_a) .def(py::init(), "x"_a) .def(py::init(), - MATRIX_ADDONS_INTERVALMATRIXBASE_MATRIX_CONST_MATRIX_DOUBLEROWSATCOMPILETIMECOLSATCOMPILETIME_REF, "x"_a) .def(py::init(), diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index c396c1a7..d126ea2a 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -206,12 +206,12 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) MATRIX_ADDONS_MATRIXBASE_VOID_RESIZE_SAVE_VALUES_INDEX_INDEX, "nb_rows"_a, "nb_cols"_a) - .def_static("zeros", [](Index_type r, Index_type c) + .def_static("zero", [](Index_type r, Index_type c) { matlab::test_integer(r,c); - return S::zeros(r,c); + return S::zero(r,c); }, - MATRIX_ADDONS_MATRIXBASE_STATIC_MATRIX_SCALARRC_ZEROS_INDEX_INDEX, + MATRIX_ADDONS_MATRIXBASE_STATIC_MATRIX_SCALARRC_ZERO_INDEX_INDEX, "r"_a, "c"_a) .def_static("ones", [](Index_type r, Index_type c) @@ -222,6 +222,14 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) MATRIX_ADDONS_MATRIXBASE_STATIC_MATRIX_SCALARRC_ONES_INDEX_INDEX, "r"_a, "c"_a) + .def_static("constant", [](Index_type r, Index_type c, const T& x) + { + matlab::test_integer(r,c); + return S::constant(r,c,x); + }, + MATRIX_ADDONS_MATRIXBASE_STATIC_MATRIX_SCALARRC_CONSTANT_INDEX_INDEX_CONST_SCALAR_REF, + "r"_a, "c"_a, "x"_a) + .def_static("eye", [](Index_type r, Index_type c) { matlab::test_integer(r,c); diff --git a/python/src/core/matrices/codac2_py_Vector.cpp b/python/src/core/matrices/codac2_py_Vector.cpp index 9bf3a1ea..1377daff 100644 --- a/python/src/core/matrices/codac2_py_Vector.cpp +++ b/python/src/core/matrices/codac2_py_Vector.cpp @@ -55,7 +55,7 @@ py::class_ export_Vector(py::module& m) matlab::test_integer(n); return std::make_unique(n); }), - MATRIX_ADDONS_VECTOR_MATRIX_INT, + DOC_TO_BE_DEFINED, "n"_a) .def(py::init(), diff --git a/python/src/core/matrices/codac2_py_VectorBase.h b/python/src/core/matrices/codac2_py_VectorBase.h index c3d5efb7..43d2905c 100644 --- a/python/src/core/matrices/codac2_py_VectorBase.h +++ b/python/src/core/matrices/codac2_py_VectorBase.h @@ -77,12 +77,12 @@ void export_VectorBase(py::module& m, py::class_& pyclass) MATRIX_ADDONS_VECTORBASE_VOID_PUT_INDEX_CONST_MATRIXBASE_OTHERDERIVED_REF, "start_id"_a, "x"_a) - .def_static("zeros", [](Index_type n) + .def_static("zero", [](Index_type n) { matlab::test_integer(n); - return S::zeros(n); + return S::zero(n); }, - MATRIX_ADDONS_VECTORBASE_STATIC_MATRIX_SCALARRC_ZEROS_INDEX, + MATRIX_ADDONS_VECTORBASE_STATIC_MATRIX_SCALARRC_ZERO_INDEX, "n"_a) .def_static("ones", [](Index_type n) @@ -93,6 +93,14 @@ void export_VectorBase(py::module& m, py::class_& pyclass) MATRIX_ADDONS_VECTORBASE_STATIC_MATRIX_SCALARRC_ONES_INDEX, "n"_a) + .def_static("constant", [](Index_type n, const T& x) + { + matlab::test_integer(n); + return S::constant(n,x); + }, + MATRIX_ADDONS_VECTORBASE_STATIC_MATRIX_SCALARRC_CONSTANT_INDEX_CONST_SCALAR_REF, + "n"_a, "x"_a) + .def_static("random", [](Index_type n) { matlab::test_integer(n); diff --git a/src/core/contractors/codac2_directed_ctc.cpp b/src/core/contractors/codac2_directed_ctc.cpp index 87d68b98..39f4e46c 100644 --- a/src/core/contractors/codac2_directed_ctc.cpp +++ b/src/core/contractors/codac2_directed_ctc.cpp @@ -373,7 +373,7 @@ using namespace codac2; return { fwd(x1.a, /* <<----- x1.m */ x2.m), fwd(x1.a, x2.a), - IntervalMatrix::zeros(x1.a.rows(),x1.a.cols()), // todo + IntervalMatrix::zero(x1.a.rows(),x1.a.cols()), // todo x1.def_domain && x2.def_domain }; } diff --git a/src/core/functions/analytic/codac2_AnalyticFunction.h b/src/core/functions/analytic/codac2_AnalyticFunction.h index e56b3e4d..1b474cc3 100644 --- a/src/core/functions/analytic/codac2_AnalyticFunction.h +++ b/src/core/functions/analytic/codac2_AnalyticFunction.h @@ -132,7 +132,7 @@ namespace codac2 assert(i >= 0 && i < (Index)this->args().size()); assert_release(size_of(x) == this->args()[i]->size() && "provided arguments do not match function inputs"); - IntervalMatrix d = IntervalMatrix::zeros(size_of(x), this->args().total_size()); + IntervalMatrix d = IntervalMatrix::zero(size_of(x), this->args().total_size()); Index p = 0, j = 0; for( ; j < i ; j++) diff --git a/src/core/functions/analytic/codac2_analytic_constants.h b/src/core/functions/analytic/codac2_analytic_constants.h index 633956bc..a73c1464 100644 --- a/src/core/functions/analytic/codac2_analytic_constants.h +++ b/src/core/functions/analytic/codac2_analytic_constants.h @@ -36,7 +36,7 @@ namespace codac2 _x, _x, // the derivative of a const value is zero: - IntervalMatrix::zeros(_x.size(),total_input_size), + IntervalMatrix::zero(_x.size(),total_input_size), // the definition domain is necesarily met at this point: true )); diff --git a/src/core/matrices/codac2_GaussJordan.cpp b/src/core/matrices/codac2_GaussJordan.cpp index 67f3b9cd..0b2b2e42 100644 --- a/src/core/matrices/codac2_GaussJordan.cpp +++ b/src/core/matrices/codac2_GaussJordan.cpp @@ -40,7 +40,7 @@ namespace codac2 Matrix gauss_jordan(const Matrix& A) { - Index n = A.rows(), m = A.cols(); + Index n = A.rows();//, m = A.cols(); Eigen::FullPivLU lu(A); Matrix L = Matrix::Identity(n,n); diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Base.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Base.h index 8e94f720..8ed5f578 100644 --- a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Base.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Base.h @@ -13,14 +13,6 @@ * \license GNU Lesser General Public License (LGPL) */ -template - requires (R_ != RowsAtCompileTime || C_ != ColsAtCompileTime) -Matrix(const Matrix& x) - : Matrix(x.rows(),x.cols()) -{ - *this = x.template cast(); -} - template inline Scalar& operator()(Index i, Index j) { diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h index d01e4f3b..21ed9e54 100644 --- a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h @@ -18,12 +18,6 @@ * \license GNU Lesser General Public License (LGPL) */ -template - requires IsIntervalDomain -Matrix(const Matrix& x) - : Matrix(x.template cast()) -{ } - template requires IsIntervalDomain Matrix(const Matrix& lb, const Matrix& ub) @@ -64,12 +58,6 @@ Matrix(int r, int c, const double bounds[][2]) assert_release(k == this->size() && "incorrect array size"); } -template - requires IsIntervalDomain -Matrix(const MatrixBase& x) - : Matrix(x.eval().template cast()) -{ } - template requires IsIntervalDomain inline bool operator==(const MatrixBase& x) const @@ -273,8 +261,7 @@ template inline static auto empty(Index r, Index c) { assert_release(r >= 0 && c >= 0); - Matrix e(r,c); - return e.init(codac2::Interval::empty()); + return Matrix::constant(r,c,codac2::Interval::empty()); } template diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalVector.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalVector.h index 1ff3fd2c..75617809 100644 --- a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalVector.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalVector.h @@ -60,18 +60,6 @@ Matrix(const std::initializer_list& l) (*this)[i++] = li; } -template - requires IsIntervalDomain && IsVectorOrRow -explicit Matrix(int n) - : Matrix( - [&]() -> int { if(R == 1) return 1; else return n; }(), - [&]() -> int { if(C == 1) return 1; else return n; }() - ) -{ - assert_release(n >= 0); - this->init(codac2::Interval()); -} - template requires IsIntervalDomain && IsVectorOrRow Matrix(int n, const double bounds[][2]) @@ -89,8 +77,5 @@ template inline static auto empty(Index n) { assert_release(n >= 0); - if constexpr(R == 1) - return Matrix((int)n,codac2::Interval::empty()); - else - return Matrix((int)n,codac2::Interval::empty()); + return Matrix::constant((int)n,codac2::Interval::empty()); } \ No newline at end of file diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_MatrixBase.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_MatrixBase.h index a4c30c33..3eb5ca87 100644 --- a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_MatrixBase.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_MatrixBase.h @@ -13,16 +13,6 @@ * \license GNU Lesser General Public License (LGPL) */ -template - requires (!IsVectorOrRow) -explicit Matrix(int r, int c, const Scalar& x) - : Matrix(r,c) -{ - assert((R==(int)r || R==-1) && (C==(int)c || C==-1)); - assert(r >= 0 && c >= 0); - init(x); -} - template requires (!IsVectorOrRow) explicit Matrix(int r, int c, const Scalar values[]) @@ -46,10 +36,10 @@ explicit Matrix(int r, int c, const Scalar values[]) template requires (!IsVectorOrRow) -inline static Matrix zeros(Index r, Index c) +inline static Matrix zero(Index r, Index c) { assert_release(r >= 0 && c >= 0); - return Matrix::Zero(r,c); + return DenseBase>::Zero(r,c); } template @@ -57,7 +47,7 @@ template inline static Matrix ones(Index r, Index c) { assert_release(r >= 0 && c >= 0); - return Matrix::Ones(r,c); + return DenseBase>::Ones(r,c); } template @@ -65,7 +55,15 @@ template inline static Matrix eye(Index r, Index c) { assert_release(r >= 0 && c >= 0); - return Matrix::Identity(r,c); + return MatrixBase>::Identity(r,c); +} + +template + requires (!IsVectorOrRow) +inline static Matrix constant(Index r, Index c, const Scalar& x) +{ + assert_release(r >= 0 && c >= 0); + return DenseBase>::Constant(r,c,x); } // Note that this static function is not called "rand" @@ -75,7 +73,7 @@ template inline static Matrix random(Index r, Index c) { assert_release(r >= 0 && c >= 0); - return Matrix::Random(r,c); + return DenseBase>::Random(r,c); } template diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Vector.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Vector.h index a48b9ef9..33e315ed 100644 --- a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Vector.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_Vector.h @@ -27,18 +27,6 @@ Matrix(std::initializer_list l) (*this)[i++] = li; } -template - requires (!IsIntervalDomain) && (IsVectorOrRow) -explicit Matrix(int n) - : Matrix( - [&]() -> int { if(R == 1) return 1; else return n; }(), - [&]() -> int { if(C == 1) return 1; else return n; }() - ) -{ - assert_release(n >= 0); - this->init(0.); -} - template requires (!IsIntervalDomain) && (IsVectorOrRow) explicit Matrix(int n, double values[]) diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h index a3d41c5f..0a825e30 100644 --- a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_VectorBase.h @@ -13,18 +13,6 @@ * \license GNU Lesser General Public License (LGPL) */ -template - requires IsVectorOrRow -explicit Matrix(int n, const Scalar& x) - : Matrix( - [&]() -> int { if(R == 1) return 1; else return n; }(), - [&]() -> int { if(C == 1) return 1; else return n; }() - ) -{ - assert_release(n > 0); - init(x); -} - template requires IsVectorOrRow inline Scalar& operator()(Index i) @@ -57,13 +45,10 @@ inline const Scalar& operator[](Index i) const template requires IsVectorOrRow -inline static Matrix zeros(Index n) +inline static Matrix zero(Index n) { assert_release(n >= 0); - if constexpr(R == 1) - return Matrix::Zero(1,n); - else - return Matrix::Zero(n,1); + return DenseBase>::Zero(n); } template @@ -71,10 +56,15 @@ template inline static Matrix ones(Index n) { assert_release(n >= 0); - if constexpr(R == 1) - return Matrix::Ones(1,n); - else - return Matrix::Ones(n,1); + return DenseBase>::Ones(n); +} + +template + requires IsVectorOrRow +inline static Matrix constant(Index n, const Scalar& x) +{ + assert_release(n >= 0); + return DenseBase>::Constant(n,x); } // Note that this static function is not called "rand" @@ -84,7 +74,7 @@ template inline static Matrix random(Index n) { assert_release(n >= 0); - return Matrix::Random(n); + return DenseBase>::Random(n); } template diff --git a/tests/core/3rd/codac2_tests_ibex.cpp b/tests/core/3rd/codac2_tests_ibex.cpp index 86b94fba..a75725a5 100644 --- a/tests/core/3rd/codac2_tests_ibex.cpp +++ b/tests/core/3rd/codac2_tests_ibex.cpp @@ -38,13 +38,13 @@ TEST_CASE("IBEX") // [Vector] Codac -> IBEX { - CHECK(codac2::to_ibex(codac2::Vector::zeros(2)) == ibex::Vector(2)); + CHECK(codac2::to_ibex(codac2::Vector::zero(2)) == ibex::Vector(2)); CHECK(codac2::to_ibex(codac2::Vector({1,2,3})) == ibex::Vector({1,2,3})); } // [Vector] IBEX -> Codac { - CHECK(codac2::to_codac(ibex::Vector::zeros(2)) == codac2::Vector::zeros(2)); + CHECK(codac2::to_codac(ibex::Vector::zeros(2)) == codac2::Vector::zero(2)); CHECK(codac2::to_codac(ibex::Vector({1,2,3})) == codac2::Vector({1,2,3})); } @@ -64,14 +64,14 @@ TEST_CASE("IBEX") // [Matrix] Codac -> IBEX { - CHECK(codac2::to_ibex(codac2::Matrix::zeros(2,3)) == ibex::Matrix(2,3)); + CHECK(codac2::to_ibex(codac2::Matrix::zero(2,3)) == ibex::Matrix(2,3)); CHECK(codac2::to_ibex(codac2::Matrix({{1,2,3},{4,5,6}})) == ibex::Matrix({{1,2,3},{4,5,6}})); } // [Matrix] IBEX -> Codac { - CHECK(codac2::to_codac(ibex::Matrix(2,3)) == codac2::Matrix::zeros(2,3)); + CHECK(codac2::to_codac(ibex::Matrix(2,3)) == codac2::Matrix::zero(2,3)); CHECK(codac2::to_codac(ibex::Matrix({{1,2,3},{4,5,6}})) == codac2::Matrix({{1,2,3},{4,5,6}})); } diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp index 2efde4cd..b52890ae 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp @@ -121,7 +121,7 @@ TEST_CASE("IntervalMatrix") } { - IntervalMatrix m1(2,3, 0.); + IntervalMatrix m1 = IntervalMatrix::zero(2,3); auto r1_0 = IntervalVector({{0,1},{0,2},{0,3}}); CHECK(r1_0.cols() == 1); CHECK(r1_0.rows() == 3); @@ -164,7 +164,7 @@ TEST_CASE("IntervalMatrix") { Interval x(-1,2); - IntervalMatrix m(2,3,x); + IntervalMatrix m = IntervalMatrix::constant(2,3,x); CHECK(m.rows() == 2); CHECK(m.cols() == 3); @@ -634,7 +634,7 @@ TEST_CASE("IntervalMatrix - mixing type") { IntervalMatrix m1 = IntervalMatrix::ones(3,3); - IntervalMatrix m2 = IntervalMatrix::zeros(3,3); + IntervalMatrix m2 = IntervalMatrix::zero(3,3); CHECK(m1.volume() == 0.); CHECK(m2.volume() == 0.); CHECK((m1+m2).volume() == 0.); @@ -659,6 +659,18 @@ TEST_CASE("IntervalMatrix - mixing type") { 3, 5 }, { 7, 9 } })); + + IntervalMatrix m4(m2+m2); + CHECK(m4 == IntervalMatrix({ + {{3,3},{5,5}}, + {{7,7},{9,9}} + })); + + IntervalMatrix m5(m2*m2); + CHECK(m5 == IntervalMatrix({ + {{11,11},{15,15}}, + {{21,21},{29,29}} + })); } } diff --git a/tests/core/matrices/codac2_tests_Vector.py b/tests/core/matrices/codac2_tests_Vector.py index eb85f873..c6a27a46 100644 --- a/tests/core/matrices/codac2_tests_Vector.py +++ b/tests/core/matrices/codac2_tests_Vector.py @@ -20,7 +20,7 @@ def tests_Vector(self): def tests_vector_specific_to_python(self): x = Vector([1,2,3]) - y = Vector.zeros(3) + y = Vector.zero(3) i = 0 for xi in x: # using __iter__ From a0edc08ac7daca25625401702484989e139eda66 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 26 Nov 2024 19:11:07 +0100 Subject: [PATCH 061/102] [core] setting -Wall -Wextra -Wpedantic -Werror + related code updates --- CMakeLists.txt | 26 ++-- python/src/core/codac2_py_core.cpp | 16 +-- python/src/core/contractors/codac2_py_Ctc.h | 4 +- .../interval/codac2_py_IntervalMatrixBase.h | 10 +- .../analytic/codac2_py_ExprWrapper.h | 4 +- .../src/core/matrices/codac2_py_VectorBase.h | 2 +- .../matrices/codac2_py_arithmetic_add.cpp | 2 +- .../matrices/codac2_py_arithmetic_div.cpp | 2 +- .../matrices/codac2_py_arithmetic_mul.cpp | 2 +- .../matrices/codac2_py_arithmetic_sub.cpp | 2 +- python/src/core/separators/codac2_py_Sep.h | 4 +- .../styles/codac2_py_StyleProperties.cpp | 4 - src/core/contractors/codac2_CtcIdentity.cpp | 2 +- src/core/contractors/codac2_CtcIdentity.h | 2 +- src/core/contractors/codac2_CtcNot.h | 4 +- src/core/contractors/codac2_directed_ctc.cpp | 2 +- src/core/domains/interval/codac2_Interval.h | 120 +++++++++--------- .../analytic/codac2_AnalyticFunction.h | 2 +- .../analytic/codac2_analytic_constants.h | 4 +- .../analytic/codac2_analytic_variables.h | 6 +- src/core/functions/codac2_FunctionArgsList.h | 4 +- src/core/tools/codac2_template_tools.h | 4 +- src/graphics/paver/codac2_drawwhilepaving.cpp | 2 +- .../styles/codac2_StyleProperties.cpp | 4 - src/graphics/styles/codac2_StyleProperties.h | 1 - .../interval/codac2_tests_IntervalMatrix.cpp | 2 +- 26 files changed, 120 insertions(+), 117 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 85f9e411..47bb065d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,15 +28,6 @@ set(PROJECT_HOMEPAGE_URL "http://codac.io") message(STATUS "Configuring build for ${PROJECT_NAME} ${PROJECT_VERSION}") - if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Debug) - message(STATUS "Configuring ${PROJECT_NAME} in DEBUG mode as none was specified.") - if(MSVC) - add_compile_options(/MD) # Temporary fix to avoid debug vs release inconsistencies... - else() - add_compile_options(-O3) - endif() - endif() ################################################################################ # Options for directories @@ -54,6 +45,22 @@ # Compilation configuration ################################################################################ + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug) + message(STATUS "Configuring ${PROJECT_NAME} in DEBUG mode as none was specified.") + if(MSVC) + add_compile_options(/MD) # Temporary fix to avoid debug vs release inconsistencies... + else() + add_compile_options(-O3) + endif() + endif() + + if(MSVC) + add_compile_options(/W4 /WX) + else() + add_compile_options(-Wall -Wextra -Wpedantic -Werror) + endif() + # # Check that the compiler supports c++20 # include(CheckCXXCompilerFlag) # check_cxx_compiler_flag("-std=c++2a" COMPILER_SUPPORTS_CXX20) @@ -84,7 +91,6 @@ ################################################################################ add_subdirectory(3rd/eigen) - #find_package(Eigen3 3.4 REQUIRED NO_MODULE) message(STATUS "Found Eigen3 version ${Eigen3_VERSION}") add_definitions(${EIGEN3_DEFINITIONS}) diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index 824dd56a..3fdf41a6 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -73,19 +73,19 @@ void export_geometry(py::module& m); void export_Polygon(py::module& m); // matrices -void export_arithmetic_add(py::module& m, +void export_arithmetic_add( py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, py::class_>& py_B, py::class_>& py_IB); -void export_arithmetic_sub(py::module& m, +void export_arithmetic_sub( py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, py::class_>& py_B, py::class_>& py_IB); -void export_arithmetic_mul(py::module& m, +void export_arithmetic_mul( py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, py::class_>& py_B, py::class_>& py_IB); -void export_arithmetic_div(py::module& m, +void export_arithmetic_div( py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, py::class_>& py_B, py::class_>& py_IB); @@ -169,10 +169,10 @@ PYBIND11_MODULE(_core, m) export_EigenBlock(m, "IntervalRowBlock"); export_EigenBlock(m, "IntervalVectorBlock"); - export_arithmetic_add(m, py_V, py_IV, py_M, py_IM, py_B, py_IB); - export_arithmetic_sub(m, py_V, py_IV, py_M, py_IM, py_B, py_IB); - export_arithmetic_mul(m, py_V, py_IV, py_M, py_IM, py_B, py_IB); - export_arithmetic_div(m, py_V, py_IV, py_M, py_IM, py_B, py_IB); + export_arithmetic_add(py_V, py_IV, py_M, py_IM, py_B, py_IB); + export_arithmetic_sub(py_V, py_IV, py_M, py_IM, py_B, py_IB); + export_arithmetic_mul(py_V, py_IV, py_M, py_IM, py_B, py_IB); + export_arithmetic_div(py_V, py_IV, py_M, py_IM, py_B, py_IB); export_Paving(m); export_PavingNode(m); diff --git a/python/src/core/contractors/codac2_py_Ctc.h b/python/src/core/contractors/codac2_py_Ctc.h index a3617565..73d9626d 100644 --- a/python/src/core/contractors/codac2_py_Ctc.h +++ b/python/src/core/contractors/codac2_py_Ctc.h @@ -62,6 +62,8 @@ class pyCtcIntervalVector : public CtcBase assert_release(overload && "CtcBase: copy method not found"); auto obj = overload(); - return std::shared_ptr>(obj.cast*>(), [](auto p) { /* no delete */ }); + return std::shared_ptr>(obj.cast*>(), + []([[maybe_unused]] auto p) + { /* no delete */ }); } }; \ No newline at end of file diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h index b2b48f96..64b4a53a 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h @@ -28,13 +28,13 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) pyclass - .def("volume", &S::volume, + .def("volume", [](const S& x) { return x.volume(); }, MATRIXBASE_ADDONS_INTERVALMATRIXBASE_DOUBLE_VOLUME_CONST) - .def("is_empty", &S::is_empty, + .def("is_empty", [](const S& x) { return x.is_empty(); }, MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_EMPTY_CONST) - .def("set_empty", &S::set_empty, + .def("set_empty", [](S& x) { x.set_empty(); }, MATRIX_ADDONS_INTERVALMATRIXBASE_VOID_SET_EMPTY) .def("lb", [](const S& x) { return x.lb(); }, @@ -134,7 +134,7 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) .def("is_bisectable", [](const S& x) { return x.is_bisectable(); }, MATRIXBASE_ADDONS_INTERVALMATRIXBASE_BOOL_IS_BISECTABLE_CONST) - .def("inflate", (S&(S::*)(double))&S::inflate, + .def("inflate", [](S& x, double r) { return x.inflate(r); }, MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_REF_INFLATE_DOUBLE, "r"_a) @@ -150,7 +150,7 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_BISECT_INDEX_FLOAT_CONST, "i"_a, "ratio"_a = 0.49) - .def("bisect_largest", [](const S& x, double ratio = 0.49) { return x.bisect_largest(); }, + .def("bisect_largest", [](const S& x, double ratio = 0.49) { return x.bisect_largest(ratio); }, MATRIX_ADDONS_INTERVALMATRIXBASE_AUTO_BISECT_LARGEST_FLOAT_CONST, "ratio"_a = 0.49) diff --git a/python/src/core/functions/analytic/codac2_py_ExprWrapper.h b/python/src/core/functions/analytic/codac2_py_ExprWrapper.h index ec86d507..0bac7b35 100644 --- a/python/src/core/functions/analytic/codac2_py_ExprWrapper.h +++ b/python/src/core/functions/analytic/codac2_py_ExprWrapper.h @@ -39,7 +39,7 @@ struct ExprWrapperBase }; template<> -struct ExprWrapper : public ExprWrapperBase +struct ExprWrapper { ExprWrapper(const Interval& e) : e(std::dynamic_pointer_cast>(const_value(e)->copy())) @@ -110,7 +110,7 @@ inline ScalarExpr operator/(const ScalarExpr& e1, const ScalarExpr& e2) } template<> -struct ExprWrapper : public ExprWrapperBase +struct ExprWrapper { ExprWrapper(const IntervalVector& e) : e(std::dynamic_pointer_cast>(const_value(e)->copy())) diff --git a/python/src/core/matrices/codac2_py_VectorBase.h b/python/src/core/matrices/codac2_py_VectorBase.h index 43d2905c..86bb0f3e 100644 --- a/python/src/core/matrices/codac2_py_VectorBase.h +++ b/python/src/core/matrices/codac2_py_VectorBase.h @@ -22,7 +22,7 @@ namespace py = pybind11; using namespace pybind11::literals; template -void export_VectorBase(py::module& m, py::class_& pyclass) +void export_VectorBase([[maybe_unused]] py::module& m, py::class_& pyclass) { //export_MatrixBase(m, pyclass); // ^ We do not "inherit" from export_MatrixBase here, in order to diff --git a/python/src/core/matrices/codac2_py_arithmetic_add.cpp b/python/src/core/matrices/codac2_py_arithmetic_add.cpp index 7176336f..4a92fe8d 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_add.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_add.cpp @@ -24,7 +24,7 @@ using namespace pybind11::literals; using B = Eigen::Block; using IB = Eigen::Block; -void export_arithmetic_add(py::module& m, +void export_arithmetic_add( py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, py::class_& py_B, py::class_& py_IB) diff --git a/python/src/core/matrices/codac2_py_arithmetic_div.cpp b/python/src/core/matrices/codac2_py_arithmetic_div.cpp index 3d16ae8c..5aab18d8 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_div.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_div.cpp @@ -24,7 +24,7 @@ using namespace pybind11::literals; using B = Eigen::Block; using IB = Eigen::Block; -void export_arithmetic_div(py::module& m, +void export_arithmetic_div( py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, py::class_& py_B, py::class_& py_IB) diff --git a/python/src/core/matrices/codac2_py_arithmetic_mul.cpp b/python/src/core/matrices/codac2_py_arithmetic_mul.cpp index 97aa6439..12f56a67 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_mul.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_mul.cpp @@ -24,7 +24,7 @@ using namespace pybind11::literals; using B = Eigen::Block; using IB = Eigen::Block; -void export_arithmetic_mul(py::module& m, +void export_arithmetic_mul( py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, py::class_& py_B, py::class_& py_IB) diff --git a/python/src/core/matrices/codac2_py_arithmetic_sub.cpp b/python/src/core/matrices/codac2_py_arithmetic_sub.cpp index 683e4c50..bc1fe3b6 100644 --- a/python/src/core/matrices/codac2_py_arithmetic_sub.cpp +++ b/python/src/core/matrices/codac2_py_arithmetic_sub.cpp @@ -24,7 +24,7 @@ using namespace pybind11::literals; using B = Eigen::Block; using IB = Eigen::Block; -void export_arithmetic_sub(py::module& m, +void export_arithmetic_sub( py::class_& py_V, py::class_& py_IV, py::class_& py_M, py::class_& py_IM, py::class_& py_B, py::class_& py_IB) diff --git a/python/src/core/separators/codac2_py_Sep.h b/python/src/core/separators/codac2_py_Sep.h index b89a3670..9825f870 100644 --- a/python/src/core/separators/codac2_py_Sep.h +++ b/python/src/core/separators/codac2_py_Sep.h @@ -63,6 +63,8 @@ class pySep : public SepBase assert(overload && "SepBase: copy method not found"); auto obj = overload(); - return std::shared_ptr(obj.cast(), [](auto p) { /* no delete */ }); + return std::shared_ptr(obj.cast(), + []([[maybe_unused]] auto p) + { /* no delete */ }); } }; \ No newline at end of file diff --git a/python/src/graphics/styles/codac2_py_StyleProperties.cpp b/python/src/graphics/styles/codac2_py_StyleProperties.cpp index aa222d0e..0259a3db 100644 --- a/python/src/graphics/styles/codac2_py_StyleProperties.cpp +++ b/python/src/graphics/styles/codac2_py_StyleProperties.cpp @@ -45,10 +45,6 @@ void export_StyleProperties(py::module& m) }), STYLEPROPERTIES_STYLEPROPERTIES_INITIALIZER_LIST_COLOR, "v"_a) - - .def(py::init(), - STYLEPROPERTIES_STYLEPROPERTIES_CONST_STRING_REF, - "vibes_style"_a) .def_static("inside", &StyleProperties::inside, STATIC_STYLEPROPERTIES_STYLEPROPERTIES_INSIDE) diff --git a/src/core/contractors/codac2_CtcIdentity.cpp b/src/core/contractors/codac2_CtcIdentity.cpp index 90a901f2..0a3e95b4 100644 --- a/src/core/contractors/codac2_CtcIdentity.cpp +++ b/src/core/contractors/codac2_CtcIdentity.cpp @@ -16,5 +16,5 @@ CtcIdentity::CtcIdentity(Index n) : Ctc(n) { } -void CtcIdentity::contract(IntervalVector& x) const +void CtcIdentity::contract([[maybe_unused]] IntervalVector& x) const { } \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcIdentity.h b/src/core/contractors/codac2_CtcIdentity.h index f08d1616..78d15d78 100644 --- a/src/core/contractors/codac2_CtcIdentity.h +++ b/src/core/contractors/codac2_CtcIdentity.h @@ -20,6 +20,6 @@ namespace codac2 CtcIdentity(Index n); - void contract(IntervalVector& x) const; + void contract([[maybe_unused]] IntervalVector& x) const; }; } \ No newline at end of file diff --git a/src/core/contractors/codac2_CtcNot.h b/src/core/contractors/codac2_CtcNot.h index bf0c45b8..1972b1c3 100644 --- a/src/core/contractors/codac2_CtcNot.h +++ b/src/core/contractors/codac2_CtcNot.h @@ -26,9 +26,9 @@ namespace codac2 : Ctc(size_of(c)) { } - void contract(IntervalVector& x) const + void contract([[maybe_unused]] IntervalVector& x) const { - /* does nothing: no inner information */ + /* nothing can be done: no inner information */ } }; } \ No newline at end of file diff --git a/src/core/contractors/codac2_directed_ctc.cpp b/src/core/contractors/codac2_directed_ctc.cpp index 39f4e46c..7e1053f2 100644 --- a/src/core/contractors/codac2_directed_ctc.cpp +++ b/src/core/contractors/codac2_directed_ctc.cpp @@ -32,7 +32,7 @@ using namespace codac2; }; } - void AddOp::bwd(const Interval& y, Interval& x1) + void AddOp::bwd([[maybe_unused]] const Interval& y, [[maybe_unused]] Interval& x1) { } IntervalVector AddOp::fwd(const IntervalVector& x1) diff --git a/src/core/domains/interval/codac2_Interval.h b/src/core/domains/interval/codac2_Interval.h index 275ee097..aa6f69a0 100644 --- a/src/core/domains/interval/codac2_Interval.h +++ b/src/core/domains/interval/codac2_Interval.h @@ -565,88 +565,88 @@ namespace codac2 friend Interval f(const Interval&, double); \ friend Interval f(const Interval&, const Interval&); \ - _dec_friend_interval_arithm_op(operator&); - _dec_friend_interval_arithm_op(operator|); - _dec_friend_interval_arithm_op(operator+); - _dec_friend_interval_arithm_op(operator-); - _dec_friend_interval_arithm_op(operator*); - _dec_friend_interval_arithm_op(operator/); + _dec_friend_interval_arithm_op(operator&) + _dec_friend_interval_arithm_op(operator|) + _dec_friend_interval_arithm_op(operator+) + _dec_friend_interval_arithm_op(operator-) + _dec_friend_interval_arithm_op(operator*) + _dec_friend_interval_arithm_op(operator/) #define _dec_friend_interval_unary_op(f) \ friend Interval f(const Interval&); \ - _dec_friend_interval_unary_op(sqr); - _dec_friend_interval_unary_op(sqrt); - _dec_friend_interval_unary_op(exp); - _dec_friend_interval_unary_op(log); - _dec_friend_interval_unary_op(cos); - _dec_friend_interval_unary_op(sin); - _dec_friend_interval_unary_op(tan); - _dec_friend_interval_unary_op(acos); - _dec_friend_interval_unary_op(asin); - _dec_friend_interval_unary_op(atan); - _dec_friend_interval_unary_op(cosh); - _dec_friend_interval_unary_op(sinh); - _dec_friend_interval_unary_op(tanh); - _dec_friend_interval_unary_op(acosh); - _dec_friend_interval_unary_op(asinh); - _dec_friend_interval_unary_op(atanh); - _dec_friend_interval_unary_op(abs); - _dec_friend_interval_unary_op(sign); - _dec_friend_interval_unary_op(integer); - _dec_friend_interval_unary_op(floor); - _dec_friend_interval_unary_op(ceil); + _dec_friend_interval_unary_op(sqr) + _dec_friend_interval_unary_op(sqrt) + _dec_friend_interval_unary_op(exp) + _dec_friend_interval_unary_op(log) + _dec_friend_interval_unary_op(cos) + _dec_friend_interval_unary_op(sin) + _dec_friend_interval_unary_op(tan) + _dec_friend_interval_unary_op(acos) + _dec_friend_interval_unary_op(asin) + _dec_friend_interval_unary_op(atan) + _dec_friend_interval_unary_op(cosh) + _dec_friend_interval_unary_op(sinh) + _dec_friend_interval_unary_op(tanh) + _dec_friend_interval_unary_op(acosh) + _dec_friend_interval_unary_op(asinh) + _dec_friend_interval_unary_op(atanh) + _dec_friend_interval_unary_op(abs) + _dec_friend_interval_unary_op(sign) + _dec_friend_interval_unary_op(integer) + _dec_friend_interval_unary_op(floor) + _dec_friend_interval_unary_op(ceil) #define _dec_friend_interval_binary_op(f) \ friend Interval f(const Interval&, const Interval&); \ - _dec_friend_interval_binary_op(max); - _dec_friend_interval_binary_op(min); - _dec_friend_interval_binary_op(atan2); + _dec_friend_interval_binary_op(max) + _dec_friend_interval_binary_op(min) + _dec_friend_interval_binary_op(atan2) friend Interval pow(const Interval&, int); friend Interval pow(const Interval&, double); - _dec_friend_interval_binary_op(pow); + _dec_friend_interval_binary_op(pow) friend Interval root(const Interval&, int); #define _dec_friend_interval_unary_bwd(f) \ friend void f(const Interval&, Interval&); \ - _dec_friend_interval_unary_bwd(bwd_sqr); - _dec_friend_interval_unary_bwd(bwd_sqrt); - _dec_friend_interval_unary_bwd(bwd_exp); - _dec_friend_interval_unary_bwd(bwd_log); - _dec_friend_interval_unary_bwd(bwd_cos); - _dec_friend_interval_unary_bwd(bwd_sin); - _dec_friend_interval_unary_bwd(bwd_tan); - _dec_friend_interval_unary_bwd(bwd_acos); - _dec_friend_interval_unary_bwd(bwd_asin); - _dec_friend_interval_unary_bwd(bwd_atan); - _dec_friend_interval_unary_bwd(bwd_cosh); - _dec_friend_interval_unary_bwd(bwd_sinh); - _dec_friend_interval_unary_bwd(bwd_tanh); - _dec_friend_interval_unary_bwd(bwd_acosh); - _dec_friend_interval_unary_bwd(bwd_asinh); - _dec_friend_interval_unary_bwd(bwd_atanh); - _dec_friend_interval_unary_bwd(bwd_abs); - _dec_friend_interval_unary_bwd(bwd_sign); - _dec_friend_interval_unary_bwd(bwd_floor); - _dec_friend_interval_unary_bwd(bwd_ceil); - _dec_friend_interval_unary_bwd(bwd_saw); + _dec_friend_interval_unary_bwd(bwd_sqr) + _dec_friend_interval_unary_bwd(bwd_sqrt) + _dec_friend_interval_unary_bwd(bwd_exp) + _dec_friend_interval_unary_bwd(bwd_log) + _dec_friend_interval_unary_bwd(bwd_cos) + _dec_friend_interval_unary_bwd(bwd_sin) + _dec_friend_interval_unary_bwd(bwd_tan) + _dec_friend_interval_unary_bwd(bwd_acos) + _dec_friend_interval_unary_bwd(bwd_asin) + _dec_friend_interval_unary_bwd(bwd_atan) + _dec_friend_interval_unary_bwd(bwd_cosh) + _dec_friend_interval_unary_bwd(bwd_sinh) + _dec_friend_interval_unary_bwd(bwd_tanh) + _dec_friend_interval_unary_bwd(bwd_acosh) + _dec_friend_interval_unary_bwd(bwd_asinh) + _dec_friend_interval_unary_bwd(bwd_atanh) + _dec_friend_interval_unary_bwd(bwd_abs) + _dec_friend_interval_unary_bwd(bwd_sign) + _dec_friend_interval_unary_bwd(bwd_floor) + _dec_friend_interval_unary_bwd(bwd_ceil) + _dec_friend_interval_unary_bwd(bwd_saw) #define _dec_friend_interval_binary_bwd(f) \ friend void f(const Interval&, Interval&, Interval&); \ - _dec_friend_interval_binary_bwd(bwd_add); - _dec_friend_interval_binary_bwd(bwd_sub); - _dec_friend_interval_binary_bwd(bwd_mul); - _dec_friend_interval_binary_bwd(bwd_div); - _dec_friend_interval_binary_bwd(bwd_pow); - _dec_friend_interval_binary_bwd(bwd_min); - _dec_friend_interval_binary_bwd(bwd_max); - _dec_friend_interval_binary_bwd(bwd_atan2); + _dec_friend_interval_binary_bwd(bwd_add) + _dec_friend_interval_binary_bwd(bwd_sub) + _dec_friend_interval_binary_bwd(bwd_mul) + _dec_friend_interval_binary_bwd(bwd_div) + _dec_friend_interval_binary_bwd(bwd_pow) + _dec_friend_interval_binary_bwd(bwd_min) + _dec_friend_interval_binary_bwd(bwd_max) + _dec_friend_interval_binary_bwd(bwd_atan2) friend void bwd_pow(const Interval&, Interval&, int); friend void bwd_root(const Interval&, Interval&, int); diff --git a/src/core/functions/analytic/codac2_AnalyticFunction.h b/src/core/functions/analytic/codac2_AnalyticFunction.h index 1b474cc3..8cc232d3 100644 --- a/src/core/functions/analytic/codac2_AnalyticFunction.h +++ b/src/core/functions/analytic/codac2_AnalyticFunction.h @@ -112,7 +112,7 @@ namespace codac2 return eval_(x...).da; } - friend std::ostream& operator<<(std::ostream& os, const AnalyticFunction& f) + friend std::ostream& operator<<(std::ostream& os, [[maybe_unused]] const AnalyticFunction& f) { if constexpr(std::is_same_v) os << "scalar function"; diff --git a/src/core/functions/analytic/codac2_analytic_constants.h b/src/core/functions/analytic/codac2_analytic_constants.h index a73c1464..11af1d00 100644 --- a/src/core/functions/analytic/codac2_analytic_constants.h +++ b/src/core/functions/analytic/codac2_analytic_constants.h @@ -47,10 +47,10 @@ namespace codac2 AnalyticExpr::value(v).a &= _x; } - void replace_expr(const ExprID& old_expr_id, const std::shared_ptr& new_expr) + void replace_expr([[maybe_unused]] const ExprID& old_expr_id, [[maybe_unused]] const std::shared_ptr& new_expr) { } - virtual bool belongs_to_args_list(const FunctionArgsList& args) const + virtual bool belongs_to_args_list([[maybe_unused]] const FunctionArgsList& args) const { return true; } diff --git a/src/core/functions/analytic/codac2_analytic_variables.h b/src/core/functions/analytic/codac2_analytic_variables.h index 657c5b78..3ea24a07 100644 --- a/src/core/functions/analytic/codac2_analytic_variables.h +++ b/src/core/functions/analytic/codac2_analytic_variables.h @@ -28,15 +28,15 @@ namespace codac2 return AnalyticExpr::unique_id(); } - T fwd_eval(ValuesMap& v, Index total_input_size) const + T fwd_eval(ValuesMap& v, [[maybe_unused]] Index total_input_size) const { return AnalyticExpr::value(v); } - void bwd_eval(ValuesMap& v) const + void bwd_eval([[maybe_unused]] ValuesMap& v) const { } - void replace_expr(const ExprID& old_expr_id, const std::shared_ptr& new_expr) + void replace_expr([[maybe_unused]] const ExprID& old_expr_id, [[maybe_unused]] const std::shared_ptr& new_expr) { } operator std::shared_ptr>() const diff --git a/src/core/functions/codac2_FunctionArgsList.h b/src/core/functions/codac2_FunctionArgsList.h index e91f3bc2..8377bbe3 100644 --- a/src/core/functions/codac2_FunctionArgsList.h +++ b/src/core/functions/codac2_FunctionArgsList.h @@ -22,9 +22,11 @@ namespace codac2 { } FunctionArgsList(const FunctionArgsList& args) + : std::vector>(args.size()) { + size_t i = 0; for(const auto& arg : args) - push_back(arg->arg_copy()); + (*this)[i++] = arg->arg_copy(); } FunctionArgsList(const std::vector>& args) diff --git a/src/core/tools/codac2_template_tools.h b/src/core/tools/codac2_template_tools.h index afdc5603..0e1cd4cf 100644 --- a/src/core/tools/codac2_template_tools.h +++ b/src/core/tools/codac2_template_tools.h @@ -26,12 +26,12 @@ namespace codac2 concept IsSepBaseOrPtr = (std::is_base_of_v || std::is_base_of_v>); - inline Index size_of(int x) + inline Index size_of([[maybe_unused]] int x) { return 1; } - inline Index size_of(double x) + inline Index size_of([[maybe_unused]] double x) { return 1; } diff --git a/src/graphics/paver/codac2_drawwhilepaving.cpp b/src/graphics/paver/codac2_drawwhilepaving.cpp index aeeb5bfd..42097051 100644 --- a/src/graphics/paver/codac2_drawwhilepaving.cpp +++ b/src/graphics/paver/codac2_drawwhilepaving.cpp @@ -83,7 +83,7 @@ namespace codac2 } } - printf("Computation time: %.4fs, %zd boxes\n", (double)(clock()-t_start)/CLOCKS_PER_SEC, n); + printf("Computation time: %.4fs, %ld boxes\n", (double)(clock()-t_start)/CLOCKS_PER_SEC, n); } void draw_while_paving(const IntervalVector& x0, std::shared_ptr s, double eps, std::shared_ptr fig) diff --git a/src/graphics/styles/codac2_StyleProperties.cpp b/src/graphics/styles/codac2_StyleProperties.cpp index 869b6e0b..38e15389 100644 --- a/src/graphics/styles/codac2_StyleProperties.cpp +++ b/src/graphics/styles/codac2_StyleProperties.cpp @@ -25,10 +25,6 @@ StyleProperties::StyleProperties(std::initializer_list colors) assert(colors.size() <= 2); } -StyleProperties::StyleProperties(const string& vibes_style) - : stroke_color(Color::green()), fill_color(Color::none()) -{ } - StyleProperties StyleProperties::inside() { StyleProperties s; diff --git a/src/graphics/styles/codac2_StyleProperties.h b/src/graphics/styles/codac2_StyleProperties.h index 4b6455dd..218b7c30 100644 --- a/src/graphics/styles/codac2_StyleProperties.h +++ b/src/graphics/styles/codac2_StyleProperties.h @@ -22,7 +22,6 @@ namespace codac2 StyleProperties(); StyleProperties(const Color& stroke_color); StyleProperties(std::initializer_list colors); - StyleProperties(const std::string& vibes_style); static StyleProperties inside(); static StyleProperties outside(); diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp index b52890ae..5b35b5cf 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp @@ -338,7 +338,7 @@ TEST_CASE("IntervalMatrix") } { - CHECK(-IntervalMatrix::empty(2,3).is_empty()); + CHECK((-IntervalMatrix::empty(2,3)).is_empty()); } { From 168419e137d8861ff89d627e6be70e0210c7db1b Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 26 Nov 2024 19:18:00 +0100 Subject: [PATCH 062/102] [cmake] removing -Werror --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47bb065d..1d8d6b74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ if(MSVC) add_compile_options(/W4 /WX) else() - add_compile_options(-Wall -Wextra -Wpedantic -Werror) + add_compile_options(-Wall -Wextra -Wpedantic) endif() # # Check that the compiler supports c++20 From 9503f60f2594d24e821e374ff288ef7d70f32685 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 26 Nov 2024 19:32:40 +0100 Subject: [PATCH 063/102] [cmake] warning compile options temporarily removed for windows --- CMakeLists.txt | 2 +- src/graphics/paver/codac2_drawwhilepaving.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d8d6b74..a3e4bd7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,7 @@ endif() if(MSVC) - add_compile_options(/W4 /WX) + #add_compile_options(/W4 /WX) # temporarily removed because of multiple "the following warning is treated as an error" with WS else() add_compile_options(-Wall -Wextra -Wpedantic) endif() diff --git a/src/graphics/paver/codac2_drawwhilepaving.cpp b/src/graphics/paver/codac2_drawwhilepaving.cpp index 42097051..8aa87323 100644 --- a/src/graphics/paver/codac2_drawwhilepaving.cpp +++ b/src/graphics/paver/codac2_drawwhilepaving.cpp @@ -138,7 +138,7 @@ namespace codac2 } } - printf("Computation time: %.4fs, %zd inner boxes, %zd boundary boxes\n", + printf("Computation time: %.4fs, %ld inner boxes, %ld boundary boxes\n", (double)(clock()-t_start)/CLOCKS_PER_SEC, n_inner, n_boundary); } } \ No newline at end of file From 73a18d0021cc454afb36c7efb07340f391ab8654 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 26 Nov 2024 19:43:36 +0100 Subject: [PATCH 064/102] [all] removing some warnings appearing in release mode --- src/core/actions/codac2_OctaSym.cpp | 2 +- src/core/contractors/codac2_directed_ctc.cpp | 4 ++-- src/core/domains/paving/codac2_Paving.h | 2 +- src/core/functions/analytic/codac2_AnalyticFunction.h | 2 +- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 2 +- src/graphics/figures/codac2_Figure2D.cpp | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/actions/codac2_OctaSym.cpp b/src/core/actions/codac2_OctaSym.cpp index f1e6c6f9..355bbb5b 100644 --- a/src/core/actions/codac2_OctaSym.cpp +++ b/src/core/actions/codac2_OctaSym.cpp @@ -18,7 +18,7 @@ using namespace codac2; OctaSym::OctaSym(const vector& s) : std::vector(s) { - for(const auto& i : s) + for([[maybe_unused]] const auto& i : s) { assert_release(std::abs(i) > 0 && std::abs(i) <= size()); } diff --git a/src/core/contractors/codac2_directed_ctc.cpp b/src/core/contractors/codac2_directed_ctc.cpp index 7e1053f2..6187a4db 100644 --- a/src/core/contractors/codac2_directed_ctc.cpp +++ b/src/core/contractors/codac2_directed_ctc.cpp @@ -50,7 +50,7 @@ using namespace codac2; }; } - void AddOp::bwd(const IntervalVector& y, IntervalVector& x1) + void AddOp::bwd([[maybe_unused]] const IntervalVector& y, [[maybe_unused]] IntervalVector& x1) { assert(y.size() == x1.size()); } @@ -70,7 +70,7 @@ using namespace codac2; }; } - void AddOp::bwd(const IntervalMatrix& y, IntervalMatrix& x1) + void AddOp::bwd([[maybe_unused]] const IntervalMatrix& y, [[maybe_unused]] IntervalMatrix& x1) { assert(y.size() == x1.size()); } diff --git a/src/core/domains/paving/codac2_Paving.h b/src/core/domains/paving/codac2_Paving.h index 75cf7263..27ba92fa 100644 --- a/src/core/domains/paving/codac2_Paving.h +++ b/src/core/domains/paving/codac2_Paving.h @@ -85,7 +85,7 @@ namespace codac2 std::list connected_subsets(const IntervalVector& x0, const NodeValue_& node_value) const { std::list l_boxes = intersecting_boxes(x0, node_value); - Index nb_boxes = l_boxes.size(); + [[maybe_unused]] Index nb_boxes = l_boxes.size(); std::list l_subsets; while(!l_boxes.empty()) diff --git a/src/core/functions/analytic/codac2_AnalyticFunction.h b/src/core/functions/analytic/codac2_AnalyticFunction.h index 8cc232d3..d15886f7 100644 --- a/src/core/functions/analytic/codac2_AnalyticFunction.h +++ b/src/core/functions/analytic/codac2_AnalyticFunction.h @@ -186,7 +186,7 @@ namespace codac2 template void check_valid_inputs(const Args&... x) const { - Index n = 0; + [[maybe_unused]] Index n = 0; ((n += size_of(x)), ...); assert_release(this->_args.total_size() == n && diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 509e784a..5dab8020 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -69,7 +69,7 @@ void Figure2D_IPE::update_window_properties() } -void Figure2D_IPE::center_viewbox(const Vector& c, const Vector& r) +void Figure2D_IPE::center_viewbox([[maybe_unused]] const Vector& c, [[maybe_unused]] const Vector& r) { assert(_fig.size() <= c.size() && _fig.size() <= r.size()); assert(r.min_coeff() > 0.); diff --git a/src/graphics/figures/codac2_Figure2D.cpp b/src/graphics/figures/codac2_Figure2D.cpp index d2c93a74..2f076a42 100644 --- a/src/graphics/figures/codac2_Figure2D.cpp +++ b/src/graphics/figures/codac2_Figure2D.cpp @@ -147,7 +147,7 @@ void Figure2D::draw_polyline(const vector& x, float tip_length, const St { assert_release(x.size() > 1); assert_release(tip_length >= 0.); // 0 = disabled tip - for(const auto& xi : x) + for([[maybe_unused]] const auto& xi : x) { assert_release(this->size() <= xi.size()); } @@ -159,7 +159,7 @@ void Figure2D::draw_polyline(const vector& x, float tip_length, const St void Figure2D::draw_polygone(const vector& x, const StyleProperties& s) { assert_release(x.size() > 1); - for(const auto& xi : x) + for([[maybe_unused]] const auto& xi : x) { assert_release(this->size() <= xi.size()); } From 53b156bbe9657c82ff18411add6320c81d6d9eaf Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 26 Nov 2024 22:27:45 +0100 Subject: [PATCH 065/102] [ellips] updates following new matrices implementation --- .../domains/ellipsoid/codac2_Ellipsoid.cpp | 6 +- .../ellipsoid/codac2_Ellipsoid_utils.cpp | 4 +- src/graphics/CMakeLists.txt | 1 + src/graphics/figures/codac2_Figure2D.cpp | 41 +------------- .../figures/codac2_Figure2D_ellipsoid.cpp | 56 +++++++++++++++++++ 5 files changed, 65 insertions(+), 43 deletions(-) create mode 100644 src/graphics/figures/codac2_Figure2D_ellipsoid.cpp diff --git a/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp b/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp index 893fac3b..aff80c98 100644 --- a/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp +++ b/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp @@ -12,7 +12,7 @@ #include using namespace std; -using namespace codac2; +using codac2::Vector; namespace codac2 { Ellipsoid::Ellipsoid(Index n) @@ -132,7 +132,7 @@ namespace codac2 { auto e_G_ = e.G.template cast(); auto A_ = A.template cast(); auto b_ = b.template cast(); - IntervalVector unit_box_(n, {-1,1}); + IntervalVector unit_box_ = IntervalVector::constant(n, {-1,1}); // compute rounding error as a small box auto mu_res_guaranteed = A_ * e_mu_ + b_; @@ -141,7 +141,7 @@ namespace codac2 { (G_res_guaranteed - e_res_G_) * unit_box_; double rho = error_box_.norm().ub(); // max radius of error_box - Ellipsoid elli_error(Vector::zeros(n), + Ellipsoid elli_error(Vector::zero(n), Matrix::eye(n,n) * rho); // = rho*unit_ball return e_res + elli_error; } diff --git a/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.cpp b/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.cpp index a0502049..2416c949 100644 --- a/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.cpp +++ b/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.cpp @@ -12,7 +12,9 @@ #include using namespace std; -using namespace codac2; +using codac2::Matrix; +using codac2::Vector; +using codac2::BoolInterval; namespace codac2 { diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt index 7b38751b..9da2bb33 100644 --- a/src/graphics/CMakeLists.txt +++ b/src/graphics/CMakeLists.txt @@ -12,6 +12,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/3rd/vibes/vibes.h ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_Figure2D.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_Figure2D_ellipsoid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_Figure2D.h ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_Figure2DInterface.h ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_OutputFigure2D.cpp diff --git a/src/graphics/figures/codac2_Figure2D.cpp b/src/graphics/figures/codac2_Figure2D.cpp index 972ecd3b..b3af3ef9 100644 --- a/src/graphics/figures/codac2_Figure2D.cpp +++ b/src/graphics/figures/codac2_Figure2D.cpp @@ -13,6 +13,8 @@ #include "codac2_Figure2D_IPE.h" #include "codac2_math.h" #include "codac2_pave.h" +#include "codac2_matrices.h" +#include "codac2_Matrix.h" using namespace std; using namespace codac2; @@ -197,45 +199,6 @@ void Figure2D::draw_ellipse(const Vector& c, const Vector& ab, double theta, con output_fig->draw_ellipse(c,ab,theta,s); } -void Figure2D::draw_ellipsoid(const Ellipsoid &e, const StyleProperties &s) { - assert_release(this->size() <= e.size()); - for (const auto &output_fig: _output_figures) { - Matrix G_draw(2, 2); - Vector mu_draw(2); - // 2d projection of the ellipsoid - if (e.size() > 2) { - // affine space of the projection - Vector d(Eigen::VectorXd::Zero(e.mu.rows())); - Matrix T(Eigen::MatrixXd::Zero(e.G.rows(), 2)); - T(output_fig->i(), 0) = 1; - T(output_fig->j(), 1) = 1; - - // project ellipsoid E(mu,Q) = {x in R^n | (x-mu).T*G.{-T}*G^{-1}*(x-mu)<1} - // on the affine plan A = {x|x=d+Tt} [Pope -2008] - // reduce the dimensions of mu and Q - - auto TTG = T.transpose() * e.G; - Eigen::BDCSVD bdcsvd(TTG, Eigen::ComputeFullU); - Matrix U(bdcsvd.matrixU()); - Matrix E((Eigen::MatrixXd) bdcsvd.singularValues().asDiagonal()); - G_draw = U * E; - mu_draw = T.transpose() * (d + T * T.transpose() * (e.mu - d)); - } else { - G_draw = e.G; - mu_draw = e.mu; - } - - // draw the 2d ellipsoid - Eigen::JacobiSVD jsvd(G_draw, Eigen::ComputeThinU); - Matrix U(jsvd.matrixU()); - Vector ab(jsvd.singularValues()); - - double theta = atan2(U(1, 0), U(0, 0)).mid(); - - output_fig->draw_ellipse(mu_draw, ab, theta, s); - } -} - void Figure2D::draw_tank(const Vector& x, float size, const StyleProperties& s) { assert_release(this->size() <= x.size()+1); diff --git a/src/graphics/figures/codac2_Figure2D_ellipsoid.cpp b/src/graphics/figures/codac2_Figure2D_ellipsoid.cpp new file mode 100644 index 00000000..4d1c8373 --- /dev/null +++ b/src/graphics/figures/codac2_Figure2D_ellipsoid.cpp @@ -0,0 +1,56 @@ +/** + * codac2_Figure2D.cpp + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Morgan Louédec + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include "codac2_Index.h" +#include "codac2_Figure2D.h" +#include "codac2_matrices.h" +#include "codac2_Matrix.h" + +using namespace std; +using codac2::Vector; +using codac2::Matrix; + +void codac2::Figure2D::draw_ellipsoid(const codac2::Ellipsoid &e, const codac2::StyleProperties &s) { + //assert_release(this->size() <= e.size()); + for (const auto &output_fig: _output_figures) { + Matrix G_draw(2, 2); + Vector mu_draw(2); + // 2d projection of the ellipsoid + if (e.size() > 2) { + // affine space of the projection + Vector d(Eigen::VectorXd::Zero(e.mu.rows())); + Matrix T(Eigen::MatrixXd::Zero(e.G.rows(), 2)); + T(output_fig->i(), 0) = 1; + T(output_fig->j(), 1) = 1; + + // project ellipsoid E(mu,Q) = {x in R^n | (x-mu).T*G.{-T}*G^{-1}*(x-mu)<1} + // on the affine plan A = {x|x=d+Tt} [Pope -2008] + // reduce the dimensions of mu and Q + + auto TTG = T.transpose().eval() * e.G; + Eigen::BDCSVD bdcsvd(Matrix(TTG.eval()), Eigen::ComputeFullU); + Matrix U(bdcsvd.matrixU()); + Matrix E((Eigen::MatrixXd) bdcsvd.singularValues().asDiagonal()); + G_draw = U * E; + mu_draw = T.transpose() * (d + T * T.transpose() * (e.mu - d)); + } else { + G_draw = e.G; + mu_draw = e.mu; + } + + // draw the 2d ellipsoid + Eigen::JacobiSVD jsvd(G_draw, Eigen::ComputeThinU); + Matrix U(jsvd.matrixU()); + Vector ab(jsvd.singularValues()); + + double theta = atan2(U(1, 0), U(0, 0)).mid(); + + output_fig->draw_ellipse(mu_draw, ab, theta, s); + } +} \ No newline at end of file From 88b1fc1a3450f8cad59caf3e62d758e51525cfde Mon Sep 17 00:00:00 2001 From: damien-masse Date: Wed, 27 Nov 2024 10:36:06 +0100 Subject: [PATCH 066/102] Adding matrix inversion. --- python/src/core/CMakeLists.txt | 3 +- python/src/core/codac2_py_core.cpp | 4 +- .../src/core/matrices/codac2_py_Inversion.cpp | 65 ++++++ src/core/CMakeLists.txt | 4 +- src/core/matrices/codac2_Inversion.cpp | 190 ++++++++++++++++++ src/core/matrices/codac2_Inversion.h | 59 ++++++ tests/CMakeLists.txt | 4 +- .../core/matrices/codac2_tests_Inversion.cpp | 46 +++++ tests/core/matrices/codac2_tests_Inversion.py | 31 +++ 9 files changed, 402 insertions(+), 4 deletions(-) create mode 100644 python/src/core/matrices/codac2_py_Inversion.cpp create mode 100644 src/core/matrices/codac2_Inversion.cpp create mode 100644 src/core/matrices/codac2_Inversion.h create mode 100644 tests/core/matrices/codac2_tests_Inversion.cpp create mode 100644 tests/core/matrices/codac2_tests_Inversion.py diff --git a/python/src/core/CMakeLists.txt b/python/src/core/CMakeLists.txt index e97e6646..4da7eeeb 100644 --- a/python/src/core/CMakeLists.txt +++ b/python/src/core/CMakeLists.txt @@ -55,6 +55,7 @@ matrices/codac2_py_arithmetic_sub.cpp matrices/codac2_py_arithmetic_mul.cpp matrices/codac2_py_arithmetic_div.cpp + matrices/codac2_py_Inversion.cpp matrices/codac2_py_Matrix.cpp matrices/codac2_py_MatrixBase.h matrices/codac2_py_MatrixBlock.h @@ -112,4 +113,4 @@ # ex: from codac import core # core.Tube # ex: from codac.core import Tube - # Tube \ No newline at end of file + # Tube diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index 3fdf41a6..76aba22a 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -92,6 +92,7 @@ void export_arithmetic_div( py::class_ export_Row(py::module& m); py::class_ export_Vector(py::module& m); py::class_ export_Matrix(py::module& m); +void export_Inversion(py::module& m); // paver void export_pave(py::module& m); @@ -157,6 +158,7 @@ PYBIND11_MODULE(_core, m) auto py_B = export_EigenBlock(m, "MatrixBlock"); export_EigenBlock(m, "RowBlock"); export_EigenBlock(m, "VectorBlock"); + export_Inversion(m); // domains export_BoolInterval(m); @@ -215,4 +217,4 @@ PYBIND11_MODULE(_core, m) // tools export_Approx(m); -} \ No newline at end of file +} diff --git a/python/src/core/matrices/codac2_py_Inversion.cpp b/python/src/core/matrices/codac2_py_Inversion.cpp new file mode 100644 index 00000000..be0d4da8 --- /dev/null +++ b/python/src/core/matrices/codac2_py_Inversion.cpp @@ -0,0 +1,65 @@ +/** + * Inversion of matrices + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Damien + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "codac2_py_doc.h" +#include "codac2_py_Inversion_docs.h" // Generated file from Doxygen + + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +using B = Eigen::Block; +using IB = Eigen::Block; + +void export_Inversion(py::module& m) +{ + m + + .def("infinite_sum_enclosure", + (IntervalMatrix(*)(const IntervalMatrix&,double&)) + &codac2::infinite_sum_enclosure, + INTERVALMATRIX_INFINITE_SUM_ENCLOSURE_CONST_INTERVALMATRIX_REF_DOUBLE_REF, + "A"_a, "mrad"_a) + + .def("inverse_correction", + (IntervalMatrix(*)(const Matrix&,const Matrix&,bool)) + &codac2::inverse_correction, + INTERVALMATRIX_INVERSE_CORRECTION_CONST_MATRIX_REF_CONST_MATRIX_REF_BOOL, + "A"_a, "B"_a, "left"_a) + + .def("inverse_correction", + (IntervalMatrix(*)(const IntervalMatrix&,const Matrix&,bool)) + &codac2::inverse_correction, + INTERVALMATRIX_INVERSE_CORRECTION_CONST_INTERVALMATRIX_REF_CONST_MATRIX_REF_BOOL, + "A"_a, "B"_a, "left"_a) + + .def("inverse_enclosure", + (IntervalMatrix(*)(const Matrix&)) + &codac2::inverse_enclosure, + INTERVALMATRIX_INVERSE_ENCLOSURE_CONST_MATRIX_REF, + "A"_a) + + .def("inverse_enclosure", + (IntervalMatrix(*)(const IntervalMatrix&)) + &codac2::inverse_enclosure, + INTERVALMATRIX_INVERSE_ENCLOSURE_CONST_MATRIX_REF, + "A"_a) + + ; +} diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 56c2808d..a323bb92 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -109,6 +109,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_GaussJordan.cpp ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_GaussJordan.h + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Inversion.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Inversion.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_matrices.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Matrix.h ${CMAKE_CURRENT_SOURCE_DIR}/matrices/codac2_Row.h @@ -232,4 +234,4 @@ install(TARGETS ${PROJECT_NAME}-core DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ${CODAC_CORE_HDR} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-core) - install(FILES ${CODAC_CORE_MAIN_HEADER} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-core) \ No newline at end of file + install(FILES ${CODAC_CORE_MAIN_HEADER} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-core) diff --git a/src/core/matrices/codac2_Inversion.cpp b/src/core/matrices/codac2_Inversion.cpp new file mode 100644 index 00000000..2dae4060 --- /dev/null +++ b/src/core/matrices/codac2_Inversion.cpp @@ -0,0 +1,190 @@ +/** + * \file codac2_Inversion.cpp + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Damien Massé + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include "codac2_Inversion.h" +#include "codac2_Matrix.h" +#include "codac2_IntervalMatrix.h" + +using namespace std; + +namespace codac2 +{ + /** \brief Compute an upper bound of A+A^2+A^3 with A a matrix of intervals + * \param A matrix of intervals (supposed around 0) + * \param mrad the maximum radius of the result added (output argument) + * \return the enclosure. May include (-oo,oo) + */ + IntervalMatrix infinite_sum_enclosure(const IntervalMatrix& A, double &mrad) { + assert_release(A.is_squared()); + Index N = A.rows(); + + Matrix B = A.mag(); + + // modified Floyd algorithm + for (Index k=0;k0.0 && B(k,r)0.0 && B(r,k)=1.0) { + mrad=oo; + res(r,c)=Interval(); + } else { + Interval sumprod=1.0/(1.0-sum); + if (sumprod.ub()>mrad) mrad=sumprod.ub(); + res(r,c)=(v*B(r,c))*sumprod; + } + } + } + return res; + } + + /** \brief Correct the approximate inverse of a matrix + * \param A a matrix + * \param B a punctual approximation of its inverse + * \param left use BA + * \return the enclosure + */ + IntervalMatrix inverse_correction(const Matrix &A, const Matrix &B, bool left) { + assert_release(A.is_squared()); + assert_release(B.is_squared()); + Index N = A.rows(); + assert_release(N==B.rows()); + + IntervalMatrix Id = IntervalMatrix::Identity(N,N); + IntervalMatrix erMat = (left ? + IntervalMatrix(-IntervalMatrix(B)*IntervalMatrix(A)+Id) : + IntervalMatrix(-IntervalMatrix(A)*IntervalMatrix(B)+Id)); + + double mrad=0.0; + IntervalMatrix E = infinite_sum_enclosure(erMat,mrad); + IntervalMatrix Ep = Id+erMat*(Id+E); + /* one could use several iterations here, either + using mrad, or directly */ + + IntervalMatrix res(N,N); + if (left) + res = Ep*IntervalMatrix(B); + else + res = IntervalMatrix(B)*Ep; + /* small problem with the matrix product : 0*oo = 0. We correct that + "by hand" (?) */ + if (mrad==oo) { + for (Index c=0;c +#include "codac2_Matrix.h" +#include "codac2_IntervalMatrix.h" + +namespace codac2 +{ + /** \brief Compute an upper bound of A+A^2+A^3 with A a matrix of intervals + * as an "error term" (use only bounds on coefficients) + * \param A matrix of intervals (supposed around 0) + * \param mrad the maximum radius of the result added (output argument) + * \return the enclosure. May include (-oo,oo) + */ + IntervalMatrix infinite_sum_enclosure(const IntervalMatrix& A, double &mrad); + + /** \brief Correct the approximate inverse of a matrix + * \param A a matrix + * \param B a punctual approximation of its inverse + * \param left use the inverse of BA (otherwise use the inverse of AB, + * true is normally better) + * \return the enclosure + */ + IntervalMatrix inverse_correction(const Matrix &A, const Matrix &B, + bool left=true); + + /** \brief Correct the approximate inverse of a matrix + * \param A a matrix + * \param B a (almost punctual) approximation of its inverse, + * \param left use the inverse of BA (otherwise use the inverse of AB, + * left is normally better) + * \return the enclosure + */ + IntervalMatrix inverse_correction(const IntervalMatrix &A, const Matrix &B, + bool left=true); + + /** \brief Enclosure of the inverse of a (non-singular) matrix + * \param A matrix + * \return the enclosure. Can have (-oo,oo) coefficients if A is singular + * or almost singular + */ + IntervalMatrix inverse_enclosure(const Matrix &A); + + /** \brief Enclosure of the inverse of a matrix of intervals + * \param A matrix of intervals + * \return the enclosure. Can have (-oo,oo) coefficients if the + * inversion "failed" + */ + IntervalMatrix inverse_enclosure(const IntervalMatrix &A); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9c1c6371..0ac83aa7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -67,6 +67,7 @@ list(APPEND SRC_TESTS # listing files without extension core/matrices/codac2_tests_arithmetic_sub core/matrices/codac2_tests_Matrix core/matrices/codac2_tests_Vector + core/matrices/codac2_tests_Inversion core/separators/codac2_tests_SepCartProd core/separators/codac2_tests_SepCtcBoundary @@ -76,6 +77,7 @@ list(APPEND SRC_TESTS # listing files without extension core/separators/codac2_tests_SepTransform core/tools/codac2_tests_Approx + ) @@ -97,4 +99,4 @@ foreach(SRC_TEST ${SRC_TESTS}) add_test(NAME ${TEST_NAME}_py COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_TEST}.py) endif() -endforeach() \ No newline at end of file +endforeach() diff --git a/tests/core/matrices/codac2_tests_Inversion.cpp b/tests/core/matrices/codac2_tests_Inversion.cpp new file mode 100644 index 00000000..315ba733 --- /dev/null +++ b/tests/core/matrices/codac2_tests_Inversion.cpp @@ -0,0 +1,46 @@ +/** + * Codac tests + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace codac2; + +TEST_CASE("Matrix") +{ + IntervalMatrix x({ + { {0.0,0.0}, {-0.1,-0.1}, {0.2,0.2} }, + { {0.0,0.0}, {-0.2,-0.2}, {0.1,0.1} }, + { {0.1,0.1}, {-0.1,-0.1}, {0.1,0.1} } + }); + + double a=0.0; + + IntervalMatrix y = infinite_sum_enclosure(x,a); + CHECK(Approx(Interval(a))==Interval(5.0)/Interval(2.0)); + + IntervalMatrix z = inverse_enclosure(x); + CHECK(z(1,2)==Interval(0)); + CHECK(Approx(z*x)==IntervalMatrix::Identity(3,3)); + + Matrix u( { + { 1,2,3 }, + { 1,3,5 }, + { 3,4,5 } + }); + + IntervalMatrix v=inverse_enclosure(u); + CHECK((IntervalMatrix(u)*v).contains(Matrix::Identity(3,3))); + +} diff --git a/tests/core/matrices/codac2_tests_Inversion.py b/tests/core/matrices/codac2_tests_Inversion.py new file mode 100644 index 00000000..a831263a --- /dev/null +++ b/tests/core/matrices/codac2_tests_Inversion.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +# Codac tests +# ---------------------------------------------------------------------------- +# \date 2024 +# \author Damien Massé +# \copyright Copyright 2024 Codac Team +# \license GNU Lesser General Public License (LGPL) + + +import unittest +from codac import * + +class TestInversion(unittest.TestCase): + + def tests_Inversion(self): + + x = Matrix([ + [ 1, 2, 0 ], + [ 3, 4, 1 ], + [ 0, 1, 0 ], + ]) + + y = inverse_enclosure(x) + + + self.assertTrue((x*y).contains(Matrix.eye(3,3))); + + +if __name__ == '__main__': + unittest.main() From fcc7d49c00f2a32b058301b2ad902b67081eac9a Mon Sep 17 00:00:00 2001 From: damien-masse Date: Wed, 27 Nov 2024 10:37:58 +0100 Subject: [PATCH 067/102] author name --- tests/core/matrices/codac2_tests_Inversion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/matrices/codac2_tests_Inversion.cpp b/tests/core/matrices/codac2_tests_Inversion.cpp index 315ba733..88f9c0d8 100644 --- a/tests/core/matrices/codac2_tests_Inversion.cpp +++ b/tests/core/matrices/codac2_tests_Inversion.cpp @@ -2,7 +2,7 @@ * Codac tests * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou + * \author Damien Massé * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ From 4bc95601e21626e91ebb1907e7ec94bdaf3390b1 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 28 Nov 2024 09:05:09 +0100 Subject: [PATCH 068/102] [cmake] add_compile_options(/W4) for MSVC --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3e4bd7c..2a39db1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,7 +56,7 @@ endif() if(MSVC) - #add_compile_options(/W4 /WX) # temporarily removed because of multiple "the following warning is treated as an error" with WS + add_compile_options(/W4) else() add_compile_options(-Wall -Wextra -Wpedantic) endif() From 6ead0a60993f2a1306b91d8d6825a69374617b1b Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 28 Nov 2024 14:31:01 +0100 Subject: [PATCH 069/102] [core] correction of unnoticed errors --- python/src/core/functions/analytic/codac2_py_AnalyticFunction.h | 2 +- python/src/core/separators/codac2_py_Sep.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h b/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h index 5c006001..9dd8c75b 100644 --- a/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h +++ b/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h @@ -115,7 +115,7 @@ void export_AnalyticFunction(py::module& m, const std::string& export_name) .def("__repr__", [](const AnalyticFunction& f) { std::ostringstream stream; stream << f; - return string(stream.str()); + return std::string(stream.str()); }, OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_ANALYTICFUNCTION_T_REF) ; diff --git a/python/src/core/separators/codac2_py_Sep.cpp b/python/src/core/separators/codac2_py_Sep.cpp index 81eefac6..9148232e 100644 --- a/python/src/core/separators/codac2_py_Sep.cpp +++ b/python/src/core/separators/codac2_py_Sep.cpp @@ -47,7 +47,7 @@ py::class_ export_Sep(py::module& m) .def("__repr__", [](const BoxPair& x) { std::ostringstream stream; stream << x; - return string(stream.str()); + return std::string(stream.str()); }, OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_BOXPAIR_REF) ; From c0a1ed189410a3702313b8a774a6b44012534f80 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 28 Nov 2024 17:06:08 +0100 Subject: [PATCH 070/102] [py] binding Row types + update of .block/.row/.col methods + IntervalMatrix py tests --- python/src/core/CMakeLists.txt | 2 + python/src/core/codac2_py_core.cpp | 2 +- .../interval/codac2_py_IntervalRow.cpp | 51 ++ .../interval/codac2_py_IntervalVector.cpp | 81 +-- .../interval/codac2_py_IntervalVector_templ.h | 111 ++++ .../src/core/matrices/codac2_py_MatrixBase.h | 65 +- .../src/core/matrices/codac2_py_VectorBase.h | 8 + .../interval/codac2_tests_IntervalMatrix.cpp | 2 +- .../interval/codac2_tests_IntervalMatrix.py | 572 +++++++++++++++++- .../interval/codac2_tests_IntervalVector.cpp | 2 +- .../interval/codac2_tests_IntervalVector.py | 2 +- .../codac2_tests_Interval_operations.cpp | 2 +- .../codac2_tests_Interval_operations.py | 2 +- 13 files changed, 814 insertions(+), 88 deletions(-) create mode 100644 python/src/core/domains/interval/codac2_py_IntervalRow.cpp create mode 100644 python/src/core/domains/interval/codac2_py_IntervalVector_templ.h diff --git a/python/src/core/CMakeLists.txt b/python/src/core/CMakeLists.txt index e97e6646..2a708094 100644 --- a/python/src/core/CMakeLists.txt +++ b/python/src/core/CMakeLists.txt @@ -36,7 +36,9 @@ domains/interval/codac2_py_Interval_operations.cpp domains/interval/codac2_py_IntervalMatrix.cpp domains/interval/codac2_py_IntervalMatrixBase.h + domains/interval/codac2_py_IntervalRow.cpp domains/interval/codac2_py_IntervalVector.cpp + domains/interval/codac2_py_IntervalVector_templ.h domains/paving/codac2_py_Paving.cpp domains/paving/codac2_py_PavingNode.cpp domains/paving/codac2_py_Subpaving.cpp diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index 3fdf41a6..e518e11e 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -162,7 +162,7 @@ PYBIND11_MODULE(_core, m) export_BoolInterval(m); auto py_Interval = export_Interval(m); export_Interval_operations(m, py_Interval); - py::class_ exported_intervalrow_class(m, "IntervalRow", DOC_TO_BE_DEFINED); + auto py_IR = export_IntervalRow(m); auto py_IV = export_IntervalVector(m); auto py_IM = export_IntervalMatrix(m); auto py_IB = export_EigenBlock(m, "IntervalMatrixBlock"); diff --git a/python/src/core/domains/interval/codac2_py_IntervalRow.cpp b/python/src/core/domains/interval/codac2_py_IntervalRow.cpp new file mode 100644 index 00000000..80c828b6 --- /dev/null +++ b/python/src/core/domains/interval/codac2_py_IntervalRow.cpp @@ -0,0 +1,51 @@ +/** + * Interval Python binding + * Originated from the former pyIbex library (Benoît Desrochers) + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Benoît Desrochers, Simon Rohou, Fabrice Le Bars + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "codac2_py_doc.h" +#include "codac2_py_Matrix_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_Matrix_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_Matrix_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Base_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_IntervalMatrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalMatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_IntervalVector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_Matrix_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +//#include "codac2_py_MatrixBase_addons_MatrixBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_Vector_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_MatrixBase_addons_VectorBase_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) +#include "codac2_py_IntervalVector_docs.h" + +#include "codac2_py_IntervalVector_templ.h" + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +py::class_ export_IntervalRow(py::module& m) +{ + py::class_ exported_intervalrow_class(m, "IntervalRow", DOC_TO_BE_DEFINED); + export_IntervalVector_(m, exported_intervalrow_class); + return exported_intervalrow_class; +} \ No newline at end of file diff --git a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp index 7e156941..82642be6 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalVector.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalVector.cpp @@ -35,8 +35,7 @@ #include "codac2_py_matrices_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py) #include "codac2_py_IntervalVector_docs.h" -#include "codac2_py_VectorBase.h" -#include "codac2_py_IntervalMatrixBase.h" +#include "codac2_py_IntervalVector_templ.h" using namespace std; using namespace codac2; @@ -46,82 +45,6 @@ using namespace pybind11::literals; py::class_ export_IntervalVector(py::module& m) { py::class_ exported_intervalvector_class(m, "IntervalVector", DOC_TO_BE_DEFINED); - export_IntervalMatrixBase(m, exported_intervalvector_class); - export_VectorBase(m, exported_intervalvector_class); - - exported_intervalvector_class - - .def(py::init( - [](Index_type n) - { - matlab::test_integer(n); - return std::make_unique(n); - }), - DOC_TO_BE_DEFINED, - "n"_a) - - .def(py::init(), - "x"_a) - - .def(py::init(), - "x"_a) - - .def(py::init(), - MATRIX_ADDONS_INTERVALMATRIXBASE_MATRIX_CONST_MATRIX_DOUBLERC_REF_CONST_MATRIX_DOUBLERC_REF, - "lb"_a, "ub"_a) - - .def(py::init( // this constructor must be the last one to be declared - [](const std::vector& v) - { - auto iv = std::make_unique(v.size()); - for(size_t i = 0 ; i < v.size() ; i++) - (*iv)[i] = v[i]; - return iv; - }), - MATRIX_ADDONS_INTERVALVECTOR_MATRIX_CONST_INITIALIZER_LIST_INTERVAL_REF, - "v"_a) - - .def("complementary", [](const IntervalVector& x) { return x.complementary(); }, - MATRIXBASE_ADDONS_INTERVALVECTOR_AUTO_COMPLEMENTARY_CONST) - - .def("diff", [](const IntervalVector& x, const IntervalVector& y, bool compactness = true) { return x.diff(y,compactness); }, - MATRIXBASE_ADDONS_INTERVALVECTOR_LIST_MATRIX_INTERVALRC_DIFF_CONST_MATRIXBASE_OTHERDERIVED_REF_BOOL_CONST, - "y"_a, "compactness"_a = true) - - .def_static("empty", [](Index_type n) - { - matlab::test_integer(n); - return IntervalVector::empty(n); - }, - MATRIX_ADDONS_INTERVALVECTOR_STATIC_AUTO_EMPTY_INDEX, - "n"_a) - - .def("__repr__", [](const IntervalVector& x) - { - std::ostringstream s; - s << x; - return string(s.str()); - }, - OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_INTERVALVECTOR_REF) - - ; - - py::implicitly_convertible(); - py::implicitly_convertible(); - - m.def("cart_prod_boxes", [](const std::list& l) - { - IntervalVector c = *l.begin(); - for(auto it = std::next(l.cbegin()); it != l.cend(); it++) - c = cart_prod(c,*it); - return c; - }, - INTERVALVECTOR_CART_PROD_CONST_X_REF_VARIADIC); - // The variadic version of this function is defined in __init__.py file - - m.def("hull", [](const std::list& l) { return hull(l); }, - AUTO_HULL_CONST_LIST_EIGEN_MATRIX_SCALARROWSATCOMPILETIMECOLSATCOMPILETIME_REF, - "l"_a); - + export_IntervalVector_(m, exported_intervalvector_class); return exported_intervalvector_class; } \ No newline at end of file diff --git a/python/src/core/domains/interval/codac2_py_IntervalVector_templ.h b/python/src/core/domains/interval/codac2_py_IntervalVector_templ.h new file mode 100644 index 00000000..e55418c8 --- /dev/null +++ b/python/src/core/domains/interval/codac2_py_IntervalVector_templ.h @@ -0,0 +1,111 @@ +/** + * IV_templ binding + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#pragma once + +#include +#include +#include +#include + +#include + +#include "codac2_py_MatrixBase.h" +#include "codac2_py_IntervalMatrixBase.h" +#include "codac2_py_VectorBase.h" + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + + +template +void export_IntervalVector_(py::module& m, py::class_& pyclass) +{ + export_IntervalMatrixBase(m, pyclass); + export_VectorBase(m, pyclass); + + pyclass + + .def(py::init( + [](Index_type n) + { + matlab::test_integer(n); + return std::make_unique(n); + }), + DOC_TO_BE_DEFINED, + "n"_a) + + .def(py::init(), + "x"_a) + + .def(py::init(), + "x"_a) + + .def(py::init(), + MATRIX_ADDONS_INTERVALMATRIXBASE_MATRIX_CONST_MATRIX_DOUBLERC_REF_CONST_MATRIX_DOUBLERC_REF, + "lb"_a, "ub"_a) + + .def(py::init( // this constructor must be the last one to be declared + [](const std::vector& v) + { + auto iv = std::make_unique(v.size()); + for(size_t i = 0 ; i < v.size() ; i++) + (*iv)[i] = v[i]; + return iv; + }), + MATRIX_ADDONS_INTERVALVECTOR_MATRIX_CONST_INITIALIZER_LIST_INTERVAL_REF, + "v"_a) + + .def("complementary", [](const IV& x) { return x.complementary(); }, + MATRIXBASE_ADDONS_INTERVALVECTOR_AUTO_COMPLEMENTARY_CONST) + + .def("diff", [](const IV& x, const IV& y, bool compactness = true) { return x.diff(y,compactness); }, + MATRIXBASE_ADDONS_INTERVALVECTOR_LIST_MATRIX_INTERVALRC_DIFF_CONST_MATRIXBASE_OTHERDERIVED_REF_BOOL_CONST, + "y"_a, "compactness"_a = true) + + .def_static("empty", [](Index_type n) + { + matlab::test_integer(n); + return IV::empty(n); + }, + MATRIX_ADDONS_INTERVALVECTOR_STATIC_AUTO_EMPTY_INDEX, + "n"_a) + + .def("__repr__", [](const IV& x) + { + std::ostringstream s; + s << x; + return string(s.str()); + }, + OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_INTERVALVECTOR_REF) + + ; + + py::implicitly_convertible(); + py::implicitly_convertible(); + + if constexpr(std::is_same_v) + { + m.def("cart_prod_boxes", [](const std::list& l) + { + IV c = *l.begin(); + for(auto it = std::next(l.cbegin()); it != l.cend(); it++) + c = cart_prod(c,*it); + return c; + }, + INTERVALVECTOR_CART_PROD_CONST_X_REF_VARIADIC); + // The variadic version of this function is defined in __init__.py file + } + + m.def("hull", [](const std::list& l) { return hull(l); }, + AUTO_HULL_CONST_LIST_EIGEN_MATRIX_SCALARROWSATCOMPILETIMECOLSATCOMPILETIME_REF, + "l"_a); +} \ No newline at end of file diff --git a/python/src/core/matrices/codac2_py_MatrixBase.h b/python/src/core/matrices/codac2_py_MatrixBase.h index d126ea2a..1239e573 100644 --- a/python/src/core/matrices/codac2_py_MatrixBase.h +++ b/python/src/core/matrices/codac2_py_MatrixBase.h @@ -29,6 +29,12 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) .def(py::self == py::self) .def(py::self != py::self) + .def("__eq__", [](const S& x1, const Eigen::Matrix& x2) + { + return x1 == x2; + }, + DOC_TO_BE_DEFINED) + .def("__len__", [](const S& x) { return x.size(); @@ -160,7 +166,7 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) pyclass - .def("block", [](S& x, Index_type i, Index_type j, Index_type p, Index_type q) -> Eigen::Block + .def("block", [](S& x, Index_type i, Index_type j, Index_type p, Index_type q) -> Eigen::Matrix { matlab::test_integer(i,j); matlab::test_integer(p,q); @@ -183,6 +189,63 @@ void export_MatrixBase(py::module& m, py::class_& pyclass) }, DOC_TO_BE_DEFINED) + .def("set_block", [](S& x, Index_type i, Index_type j, Index_type p, Index_type q, const S& y) + { + matlab::test_integer(i,j); + matlab::test_integer(p,q); + x.block(matlab::input_index(i),matlab::input_index(j),matlab::input_index(p),matlab::input_index(q)) = y; + }, + py::keep_alive<0,1>(), + DOC_TO_BE_DEFINED) + + .def("set_block", [](S& x, Index_type i, Index_type j, Index_type p, Index_type q, const Eigen::Matrix& y) + { + matlab::test_integer(i,j); + matlab::test_integer(p,q); + x.block(matlab::input_index(i),matlab::input_index(j),matlab::input_index(p),matlab::input_index(q)) = y; + }, + py::keep_alive<0,1>(), + DOC_TO_BE_DEFINED) + + .def("set_block", [](S& x, Index_type i, Index_type j, Index_type p, Index_type q, const Eigen::Matrix& y) + { + matlab::test_integer(i,j); + matlab::test_integer(p,q); + x.block(matlab::input_index(i),matlab::input_index(j),matlab::input_index(p),matlab::input_index(q)) = y; + }, + py::keep_alive<0,1>(), + DOC_TO_BE_DEFINED) + + .def("set_col", [](S& x, Index_type i, const Eigen::Matrix& y) + { + matlab::test_integer(i); + x.col(matlab::input_index(i)) = y; + }, + DOC_TO_BE_DEFINED) + + .def("set_col", [](S& x, Index_type i, const Eigen::Matrix& y) + { + assert_release(y.cols() == 1); + matlab::test_integer(i); + x.col(matlab::input_index(i)) = y; + }, + DOC_TO_BE_DEFINED) + + .def("set_row", [](S& x, Index_type i, const Eigen::Matrix& y) + { + matlab::test_integer(i); + x.row(matlab::input_index(i)) = y; + }, + DOC_TO_BE_DEFINED) + + .def("set_row", [](S& x, Index_type i, const Eigen::Matrix& y) + { + assert_release(y.rows() == 1); + matlab::test_integer(i); + x.row(matlab::input_index(i)) = y; + }, + DOC_TO_BE_DEFINED) + .def("__call__", [](S& x, Index_type i, Index_type j) -> T& { matlab::test_integer(i,j); diff --git a/python/src/core/matrices/codac2_py_VectorBase.h b/python/src/core/matrices/codac2_py_VectorBase.h index 86bb0f3e..bcebe0c5 100644 --- a/python/src/core/matrices/codac2_py_VectorBase.h +++ b/python/src/core/matrices/codac2_py_VectorBase.h @@ -31,6 +31,14 @@ void export_VectorBase([[maybe_unused]] py::module& m, py::class_& pyclass) pyclass + .def(py::init( + [](const Eigen::Matrix& x) + { + return std::make_unique(x); + }), + DOC_TO_BE_DEFINED, + "x"_a) + .def("__getitem__", [](const S& x, Index_type index) -> const T& { matlab::test_integer(index); diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp index 5b35b5cf..00408843 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp @@ -7,7 +7,7 @@ * * ---------------------------------------------------------------------------- * \date 2024 - * \author Gilles Chabert, (Simon Rohou) + * \author Gilles Chabert, Simon Rohou * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.py b/tests/core/domains/interval/codac2_tests_IntervalMatrix.py index 7498053b..69862df6 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.py +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.py @@ -8,7 +8,7 @@ # # ---------------------------------------------------------------------------- # \date 2024 -# \author Gilles Chabert, (Simon Rohou) +# \author Gilles Chabert, Simon Rohou # \copyright Copyright 2024 Codac Team # \license GNU Lesser General Public License (LGPL) @@ -19,7 +19,26 @@ class TestIntervalMatrix(unittest.TestCase): - def tests_intervalmatrix(self): + def M1(self): + return IntervalMatrix([ + [[0,1],[0,2],[0,3]], + [[-1,0],[-2,0],[-3,0]] + ]) + + def M2(self): # the transpose of M1 + return IntervalMatrix([ + [[0,1],[-1,0]], + [[0,2],[-2,0]], + [[0,3],[-3,0]] + ]) + + def M3(self): # non-null intersection with M1 + return IntervalMatrix([ + [[1,2],[1,2],[2,4]], + [[-2,-1],[-2,-1],[-4,-2]] + ]) + + def tests_0_intervalmatrix(self): x = IntervalMatrix([ [ [-1,1], [-2,2] ], @@ -36,5 +55,554 @@ def tests_intervalmatrix(self): #m = IntervalMatrix(x) + def tests_intervalmatrix(self): + + m1 = IntervalMatrix(2,3) + m2 = IntervalMatrix(3,2) + self.assertTrue(m1 != m2) + self.assertTrue(not (m1 == m2)) + + m1 = IntervalMatrix(3,2) + m2 = IntervalMatrix(2,2) + self.assertTrue(m1 != m2) + self.assertTrue(not (m1 == m2)) + + m1 = IntervalMatrix(2,3) + m2 = IntervalMatrix(2,3) + + self.assertTrue(m1.rows() == 2) + self.assertTrue(m1.cols() == 3) + self.assertTrue(m2.rows() == 2) + self.assertTrue(m2.cols() == 3) + + m1[0,0] = 1. + m1[0,1] = 2. + m1[0,2] = 3. + m1[1,0] = 4. + m1[1,1] = 5. + m1[1,2] = 6. + m2[0,0] = 1. + m2[0,1] = 2. + m2[0,2] = 3. + m2[1,0] = 4. + m2[1,1] = 5. + m2[1,2] = 6. + + self.assertTrue(m1 == m2) + self.assertTrue(not (m1 != m2)) + + m2[1,2] = 7. + self.assertTrue(m1 != m2) + self.assertTrue(not (m1 == m2)) + + m1 = IntervalMatrix(2,3) + m2 = IntervalMatrix(2,3) + m1[1,1] = -1 + m2[1,1] = -2 + self.assertTrue(m1 != m2) + self.assertTrue(not (m1 == m2)) + m1.set_empty() + m2.set_empty() + self.assertTrue(m1 == m2) + self.assertTrue(not (m1 != m2)) + + m = IntervalMatrix(2,3) + self.assertTrue(m.rows() == 2) + self.assertTrue(m.cols() == 3) + self.assertTrue(m(0,0) == Interval(-oo,oo)) + self.assertTrue(m(0,1) == Interval(-oo,oo)) + self.assertTrue(m(0,2) == Interval(-oo,oo)) + self.assertTrue(m(1,0) == Interval(-oo,oo)) + self.assertTrue(m(1,1) == Interval(-oo,oo)) + self.assertTrue(m(1,2) == Interval(-oo,oo)) + + self.assertTrue(m == IntervalMatrix(m)) + #self.assertTrue(m == (IntervalMatrix(2,3)=m)) + + m1 = IntervalMatrix.zero(2,3) + r1_0 = IntervalVector([[0,1],[0,2],[0,3]]) + self.assertTrue(r1_0.cols() == 1) + self.assertTrue(r1_0.rows() == 3) + r1 = IntervalVector([[0,1],[0,2],[0,3]]).transpose() + self.assertTrue(r1.cols() == 3) + self.assertTrue(r1.rows() == 1) + r2 = IntervalVector([[-1,0],[-2,0],[-3,0]]).transpose() + self.assertTrue(r2.cols() == 3) + self.assertTrue(r2.rows() == 1) + self.assertTrue(r1 == IntervalMatrix([ + [ [0,1], [0,2], [0,3] ] + ])) + + m1.set_row(0,r1) + m1.set_row(1,r2) + + c1 = IntervalVector([[0,1],[-1,0]]) + c2 = IntervalVector([[0,2],[-2,0]]) + c3 = IntervalVector([[0,3],[-3,0]]) + + self.assertTrue(m1.rows() == 2) + self.assertTrue(m1.cols() == 3) + + a1 = IntervalRow(r1) + a2 = IntervalRow(m1.row(0)) + self.assertTrue(a1 == a2) + + self.assertTrue((m1.row(0) == r1)) + self.assertTrue((m1.row(1) == r2)) + self.assertTrue((m1.row(0) == r1)) + self.assertTrue((m1.row(1) == r2)) + + self.assertTrue((m1.col(0) == c1)) + self.assertTrue((m1.col(1) == c2)) + self.assertTrue((m1.col(2) == c3)) + self.assertTrue(m1(0,0) == Interval(0,1)) + self.assertTrue(m1(0,1) == Interval(0,2)) + self.assertTrue(m1(0,2) == Interval(0,3)) + self.assertTrue(m1(1,0) == Interval(-1,0)) + self.assertTrue(m1(1,1) == Interval(-2,0)) + self.assertTrue(m1(1,2) == Interval(-3,0)) + + self.assertTrue(m1 == IntervalMatrix(m1)) + #self.assertTrue(m1 == (IntervalMatrix(2,3)=m1)) + + x = Interval(-1,2) + m = IntervalMatrix.constant(2,3,x) + + self.assertTrue(m.rows() == 2) + self.assertTrue(m.cols() == 3) + for i in range (0,2): + for j in range (0,3): + self.assertTrue(m(i,j) == x) + + self.assertTrue(m == IntervalMatrix(m)) + #self.assertTrue(m == (IntervalMatrix(2,3)=m)) + + #double _m[][2] = [ + # [0,1], [0,2], [0,3], + # [-1,0],[-2,0],[-3,0] + #] + #m = IntervalMatrix(2,3,_m) + #self.assertTrue(m == self.M1()) + + m = IntervalMatrix([ + [[0,1], [0,2], [0,3]], + [[-1,0],[-2,0],[-3,0]] + ]) + self.assertTrue(m == self.M1()) + + m = IntervalMatrix(2,3) + # accessor (row,col) + m[0,0] = Interval(0,1) + m[0,1] = Interval(0,2) + m[0,2] = Interval(0,3) + m[1,0] = Interval(-1,0) + m[1,1] = Interval(-2,0) + m[1,2] = Interval(-3,0) + self.assertTrue(m == self.M1()) + + self.assertTrue(IntervalMatrix.empty(2,3).rows() == 2) + self.assertTrue(IntervalMatrix.empty(2,3).cols() == 3) + + self.assertTrue(IntervalMatrix(IntervalMatrix.empty(2,3)) == IntervalMatrix.empty(2,3)) + #self.assertTrue((IntervalMatrix(2,3)=IntervalMatrix.empty(2,3)) == IntervalMatrix.empty(2,3)) + + self.assertTrue(not IntervalMatrix(2,3).is_empty()) + self.assertTrue(IntervalMatrix.empty(2,3).is_empty()) + + m = IntervalMatrix(2,3) + m.set_empty() + self.assertTrue(m.is_empty()) + + # Intersection of a matrix with itself + m1 = self.M1() + m1 &= self.M1() + self.assertTrue(m1 == self.M1()) + + # Intersection of two overlapping matrices + m = IntervalMatrix([ + [[1,1], [1,2], [2,3]], + [[-1,-1],[-2,-1],[-3,-2]] + ]) + + m1 = self.M1() + m1 &= self.M3() + self.assertTrue(m1 == m) + + # Intersection of two non-overlapping matrices + m3 = IntervalMatrix(self.M3()) + m3[1,2] = Interval(-5,-4) + m1 = IntervalMatrix(self.M1()) + m1 &= m3 + self.assertTrue(m1.is_empty()) + + m1 = IntervalMatrix(self.M1()) + + v = IntervalVector(2) + v[0] = Interval(1,2) + v[1] = Interval(-2,-1) + + m1.set_col(1,v) + + m2 = IntervalMatrix([ + [[0,1], [1,2], [0,3]], + [[-1,0],[-2,-1],[-3,0]] + ]) + self.assertTrue(m1 == m2) + + self.assertTrue(self.M1().block(0,0,2,3) == self.M1()) + self.assertTrue(self.M1().block(0,0,1,3) == IntervalMatrix([[0,1],[0,2],[0,3]])) + self.assertTrue(self.M1().block(1,0,1,3) == IntervalMatrix([[-1,0],[-2,0],[-3,0]])) + self.assertTrue(self.M1().block(0,0,2,1) == IntervalMatrix([[[0,1]],[[-1,0]]])) + self.assertTrue(self.M1().block(0,1,2,1) == IntervalMatrix([[[0,2]],[[-2,0]]])) + self.assertTrue(self.M1().block(0,2,2,1) == IntervalMatrix([[[0,3]],[[-3,0]]])) + self.assertTrue(self.M1().block(0,1,2,2) == IntervalMatrix([[[0,2],[0,3]],[[-2,0],[-3,0]]])) + + m1 = IntervalMatrix(2,2) + r1 = IntervalVector([[0,1],[0,2]]) + r2 = IntervalVector([[-1,0],[-2,0]]) + m1.set_row(0,r1.transpose()) + m1.set_row(1,r2.transpose()) + m1.resize_save_values(2,3) + m1[0,2] = Interval(0,3) + m1[1,2] = Interval(-3,0) + + self.assertTrue(m1 == self.M1()) + + m1 = IntervalMatrix(1,3) + r1 = IntervalVector([[0,1],[0,2],[0,3]]) + m1.set_row(0,r1.transpose()) + m1.resize_save_values(2,3) + m1[1,0] = Interval(-1,0) + m1[1,1] = Interval(-2,0) + m1[1,2] = Interval(-3,0) + + self.assertTrue(m1 == self.M1()) + + e = IntervalMatrix.empty(1,1) + e.resize_save_values(2,3) + self.assertTrue(e.is_empty()) + + m1 = IntervalMatrix(self.M1()) + m2 = IntervalMatrix(-m1) + for i in range (0,2): + for j in range(0,3): + self.assertTrue(m2(i,j) == -m1(i,j)) + + self.assertTrue((-IntervalMatrix.empty(2,3)).is_empty()) + + m1 = IntervalMatrix(self.M1()) + m2 = IntervalMatrix(m1+m1) + + for i in range (0,2): + for j in range(0,3): + self.assertTrue(m2(i,j) == m1(i,j)+m1(i,j)) + + m0 = IntervalMatrix(m1) + m0 += m1 + self.assertTrue(m2 == m0) + + m1 = IntervalMatrix.empty(2,3) + m2 = IntervalMatrix(2,3) + + self.assertTrue((m1+m2).is_empty()) + m1+=m2 + self.assertTrue(m1.is_empty()) + m2+=m1 + self.assertTrue(m2.is_empty()) + + m1 = IntervalMatrix(self.M1()) + m2 = IntervalMatrix(m1-m1) + for i in range (0,2): + for j in range(0,3): + self.assertTrue(m2(i,j) == m1(i,j)-m1(i,j)) + + m0 = IntervalMatrix(m1) + m0 -= m1 + self.assertTrue(m2 == m0) + + m1 = IntervalMatrix.empty(2,3) + m2 = IntervalMatrix(2,3) + + self.assertTrue((m1-m2).is_empty()) + m1-=m2 + self.assertTrue(m1.is_empty()) + m2-=m1 + self.assertTrue(m2.is_empty()) + + m1 = IntervalMatrix(self.M1()) + m2 = IntervalMatrix(self.M2()) + m3 = IntervalMatrix(m1*m2) + self.assertTrue(m3.rows() == 2) + self.assertTrue(m3.cols() == 2) + + for i in range (0,2): + for j in range(0,2): + self.assertTrue(m3(i,j) == m1(i,0)*m2(0,j)+m1(i,1)*m2(1,j)+m1(i,2)*m2(2,j)) + + # Not supported by Eigen: self.assertTrue(m3 == (IntervalMatrix(m1)*=m2)) + + m1 = IntervalMatrix.empty(2,3) + m2 = IntervalMatrix(3,2) + + self.assertTrue((m1*m2).is_empty()) + # Not supported by Eigen: self.assertTrue((m1*=m2).is_empty()) + # Not supported by Eigen: self.assertTrue((m2*=m1).is_empty()) + + M1 = IntervalMatrix(Matrix.eye(2,2)) + self.assertTrue(M1 == IntervalMatrix([ + [ [1,1],[0,0] ], + [ [0,0],[1,1] ] + ])) + + M2 = IntervalMatrix(2.*Matrix.eye(2,2)) + self.assertTrue(M2 == IntervalMatrix([ + [ [2,2],[0,0] ], + [ [0,0],[2,2] ] + ])) + + M3_degenerate = Matrix(-1.*Matrix.eye(2,2)) + self.assertTrue(M3_degenerate == Matrix([ + [ -1,0 ], + [ 0,-1 ] + ])) + + M3_Matrix = IntervalMatrix(Interval(-1,1)*Matrix.eye(2,2)) + self.assertTrue(M3_Matrix == IntervalMatrix([ + [ [-1,1],[0,0] ], + [ [0,0],[-1,1] ] + ])) + + M3_IntervalMatrix = IntervalMatrix(Interval(-1,1)*IntervalMatrix.eye(2,2)) + self.assertTrue(M3_IntervalMatrix == IntervalMatrix([ + [ [-1,1],[0,0] ], + [ [0,0],[-1,1] ] + ])) + + M1 = IntervalMatrix(2.*Matrix.eye(3,3)) + V1 = IntervalVector(3) + V1[0] = 3 + V1[1] = 4 + V1[2] = 5 + res = IntervalMatrix(4,4) + res.set_block(0,0,3,3,M1) + res.set_block(0,3,3,1,V1) + res.set_block(3,0,1,3,IntervalVector.ones(3).transpose()) + res[3,3] = 6 + + self.assertTrue((res == Matrix([ + [2,0,0,3], + [0,2,0,4], + [0,0,2,5], + [1,1,1,6] + ]))) + + m1 = Matrix([ + [ 0,2 ], + [ 3,10 ] + ]) + m2 = Matrix([ + [ -1,7 ], + [ 8,4 ] + ]) + + self.assertTrue((IntervalMatrix(m1) | m2) == IntervalMatrix([ + [ [-1,0],[2,7] ], + [ [3,8],[4,10] ] + ])) + + m1 = IntervalMatrix([ + [ [0,1],[0,2] ], + [ [0,0],Interval.empty() ] + ]) + m2 = IntervalMatrix([ + [ [-oo,oo],[-1,3] ], + [ [2,4],[1,1] ] + ]) + + self.assertTrue((m1 | m2) == IntervalMatrix([ + [ [-oo,oo],[-1,3] ], + [ [0,4],[1,1] ] + ])) + + m1 = IntervalMatrix([ + [ [0,1],[0,2] ], + [ [0,0],Interval.empty() ] + ]) + m2 = IntervalMatrix([ + [ [-oo,oo],[-1,3] ], + [ [2,4],[1,1] ] + ]) + + self.assertTrue((m1 & m2) == IntervalMatrix([ + [ [0,1],[0,2] ], + [ Interval.empty(),Interval.empty() ] + ])) + + + def tests_intervalmatrix_mixing_type(self): + + m1 = Matrix([ + [ 1,2 ], + [ 3,4 ] + ]) + + # Interval - Matrix + self.assertTrue((Interval(-1,1) * m1) == IntervalMatrix([ + [ [-1,1],[-2,2] ], + [ [-3,3],[-4,4] ] + ])) + + # Matrix - Interval + self.assertTrue((m1 / Interval(2)) == IntervalMatrix([ + [ [1./2.],[2./2.] ], + [ [3./2.],[4./2.] ] + ])) + + v1 = IntervalVector([ + -1, + -2 + ]) + + self.assertTrue(v1[0] == -1) + self.assertTrue(v1[1] == -2) + + iv1 = IntervalVector([ + [-1,1], + [-1,1] + ]) + + # Matrix - IntervalVector + self.assertTrue((m1 * iv1) == IntervalVector([ + [-3,3], + [-7,7] + ])) + + # double - IntervalVector + self.assertTrue((-3 * iv1) == IntervalVector([ + [-3,3], + [-3,3] + ])) + + # Interval - Vector + self.assertTrue((Interval(-1,1) * v1) == IntervalVector([ + [-1,1], + [-2,2] + ])) + + im1 = IntervalMatrix([ + [ [-1,1],[-2,2] ], + [ [-3,3],[-4,4] ] + ]) + + # Matrix - IntervalMatrix + self.assertTrue((m1 + im1) == IntervalMatrix([ + [ [0,2],[0,4] ], + [ [0,6],[0,8] ] + ])) + + # IntervalMatrix - Matrix + self.assertTrue((im1 + m1) == IntervalMatrix([ + [ [0,2],[0,4] ], + [ [0,6],[0,8] ] + ])) + + # IntervalMatrix - Matrix block + self.assertTrue((im1 + m1.block(0,0,2,2)) == IntervalMatrix([ + [ [0,2],[0,4] ], + [ [0,6],[0,8] ] + ])) + + # Matrix block - IntervalMatrix + self.assertTrue((m1.block(0,0,2,2) + im1) == IntervalMatrix([ + [ [0,2],[0,4] ], + [ [0,6],[0,8] ] + ])) + + # Matrix - IntervalMatrix + self.assertTrue((m1 - im1) == IntervalMatrix([ + [ [0,2],[0,4] ], + [ [0,6],[0,8] ] + ])) + + # IntervalMatrix - Matrix + self.assertTrue((im1 - m1) == IntervalMatrix([ + [ [-2,0],[-4,0] ], + [ [-6,0],[-8,0] ] + ])) + + # Matrix - col of IntervalMatrix + self.assertTrue((m1 * im1.col(0)) == IntervalMatrix([ + [ [-7,7] ], + [ [-15,15] ] + ])) + + # Row of Matrix - col of Matrix + # operations on Row types not supported yet in Python: self.assertTrue((m1.row(1) * m1.col(0)) == Matrix([[15]])) + + # Row of Matrix - col of IntervalMatrix + # operations on Row types not supported yet in Python: self.assertTrue((m1.row(1) * im1.col(0)) == IntervalMatrix([[[-15,15]]])) + + # Row of IntervalMatrix - col of IntervalMatrix + # operations on Row types not supported yet in Python: self.assertTrue((im1.row(1) * im1.col(0)) == IntervalMatrix([[[-15,15]]])) + + m1 = Matrix([ + [ 1,2 ], + [ 3,4 ] + ]) + + m2 = Matrix([ + [ 2,3 ], + [ 4,5 ] + ]) + + im = IntervalMatrix(m1,m2) + self.assertTrue(im == IntervalMatrix([ + [ [1,2],[2,3] ], + [ [3,4],[4,5] ] + ])) + + m2[0,1] = 1. + + im_empty = IntervalMatrix(m1,m2) + self.assertTrue(im_empty == IntervalMatrix.empty(2,2)) + + m1 = IntervalMatrix.ones(3,3) + m2 = IntervalMatrix.zero(3,3) + self.assertTrue(m1.volume() == 0.) + self.assertTrue(m2.volume() == 0.) + self.assertTrue((m1+m2).volume() == 0.) + + m1 = IntervalMatrix([ + [ [1,2],[2,3] ], + [ [3,4],[4,5] ] + ]) + m2 = Matrix([ + [ 1.5, 2.5 ], + [ 3.5, 4.5 ] + ]) + + self.assertTrue(m1.contains(m2)) + self.assertTrue(IntervalMatrix(m2).is_strict_subset(m1)) + + m3 = Matrix(2,2) + m3.init(m2+m2) + self.assertTrue(m3 == Matrix([ + [ 3, 5 ], + [ 7, 9 ] + ])) + + m4 = IntervalMatrix(m2+m2) + self.assertTrue(m4 == IntervalMatrix([ + [[3,3],[5,5]], + [[7,7],[9,9]] + ])) + + m5 = IntervalMatrix(m2*m2) + self.assertTrue(m5 == IntervalMatrix([ + [[11,11],[15,15]], + [[21,21],[29,29]] + ])) + + if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/tests/core/domains/interval/codac2_tests_IntervalVector.cpp b/tests/core/domains/interval/codac2_tests_IntervalVector.cpp index 3e52d181..5102b483 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalVector.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalVector.cpp @@ -7,7 +7,7 @@ * * ---------------------------------------------------------------------------- * \date 2024 - * \author Gilles Chabert, (Simon Rohou) + * \author Gilles Chabert, Simon Rohou * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ diff --git a/tests/core/domains/interval/codac2_tests_IntervalVector.py b/tests/core/domains/interval/codac2_tests_IntervalVector.py index 66edc90b..93a3851b 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalVector.py +++ b/tests/core/domains/interval/codac2_tests_IntervalVector.py @@ -8,7 +8,7 @@ # # ---------------------------------------------------------------------------- # \date 2024 -# \author Gilles Chabert, (Simon Rohou) +# \author Gilles Chabert, Simon Rohou # \copyright Copyright 2024 Codac Team # \license GNU Lesser General Public License (LGPL) diff --git a/tests/core/domains/interval/codac2_tests_Interval_operations.cpp b/tests/core/domains/interval/codac2_tests_Interval_operations.cpp index ea3738f8..9f99d2fa 100644 --- a/tests/core/domains/interval/codac2_tests_Interval_operations.cpp +++ b/tests/core/domains/interval/codac2_tests_Interval_operations.cpp @@ -7,7 +7,7 @@ * * ---------------------------------------------------------------------------- * \date 2024 - * \author Gilles Chabert, (Simon Rohou) + * \author Gilles Chabert, Simon Rohou * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ diff --git a/tests/core/domains/interval/codac2_tests_Interval_operations.py b/tests/core/domains/interval/codac2_tests_Interval_operations.py index f06e85bb..a091ba25 100644 --- a/tests/core/domains/interval/codac2_tests_Interval_operations.py +++ b/tests/core/domains/interval/codac2_tests_Interval_operations.py @@ -8,7 +8,7 @@ # # ---------------------------------------------------------------------------- # \date 2024 -# \author Gilles Chabert, (Simon Rohou) +# \author Gilles Chabert, Simon Rohou # \copyright Copyright 2024 Codac Team # \license GNU Lesser General Public License (LGPL) From be1f934b182746870e87e9ab1372a92fad18e21f Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 28 Nov 2024 17:47:39 +0100 Subject: [PATCH 071/102] [py] permuting constructors in IntervalMatrix class (corrected bug) --- .../interval/codac2_py_IntervalMatrix.cpp | 16 ++--- .../interval/codac2_tests_IntervalMatrix.cpp | 58 ++++++++++++++++++ .../interval/codac2_tests_IntervalMatrix.py | 60 ++++++++++++++++++- 3 files changed, 124 insertions(+), 10 deletions(-) diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp index d8db8bf7..d27bc63d 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrix.cpp @@ -76,18 +76,10 @@ py::class_ export_IntervalMatrix(py::module& m) DOC_TO_BE_DEFINED, "x"_a) - .def(py::init(), - DOC_TO_BE_DEFINED, - "x"_a) - .def(py::init(), DOC_TO_BE_DEFINED, "x"_a) - .def(py::init(), - DOC_TO_BE_DEFINED, - "x"_a) - .def(py::init&>(), DOC_TO_BE_DEFINED, "x"_a) @@ -110,6 +102,14 @@ py::class_ export_IntervalMatrix(py::module& m) }), DOC_TO_BE_DEFINED, "v"_a) + + .def(py::init(), + DOC_TO_BE_DEFINED, + "x"_a) + + .def(py::init(), + DOC_TO_BE_DEFINED, + "x"_a) .def_static("empty", [](Index_type r, Index_type c) { diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp index 00408843..eaf88e14 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.cpp @@ -672,6 +672,64 @@ TEST_CASE("IntervalMatrix - mixing type") {{21,21},{29,29}} })); } + + { + IntervalMatrix test1 { + { {0,1}, {0,2}, {0,0} } + }; + CHECK(test1.rows() == 1); + CHECK(test1.cols() == 3); + CHECK(test1(0,0) == Interval(0,1)); + CHECK(test1(0,1) == Interval(0,2)); + CHECK(test1(0,2) == Interval(0,0)); + + IntervalMatrix test2 { + {0,1}, + {2,3}, + {4,5} + }; + CHECK(test2.rows() == 3); + CHECK(test2.cols() == 2); + CHECK(test2(0,0) == Interval(0)); + CHECK(test2(0,1) == Interval(1)); + CHECK(test2(1,0) == Interval(2)); + CHECK(test2(1,1) == Interval(3)); + CHECK(test2(2,0) == Interval(4)); + CHECK(test2(2,1) == Interval(5)); + + IntervalMatrix test3 { + {{1,oo},{2,oo}}, + {{3,oo},{4,oo}}, + {{5,oo},{6,oo}} + }; + CHECK(test3.rows() == 3); + CHECK(test3.cols() == 2); + CHECK(test3(0,0) == Interval(1,oo)); + CHECK(test3(0,1) == Interval(2,oo)); + CHECK(test3(1,0) == Interval(3,oo)); + CHECK(test3(1,1) == Interval(4,oo)); + CHECK(test3(2,0) == Interval(5,oo)); + CHECK(test3(2,1) == Interval(6,oo)); + + IntervalMatrix test4 { + {{1,2}}, + {{3,4}}, + {{5,6}} + }; + CHECK(test4.rows() == 3); + CHECK(test4.cols() == 1); + CHECK(test4(0,0) == Interval(1,2)); + CHECK(test4(1,0) == Interval(3,4)); + CHECK(test4(2,0) == Interval(5,6)); + + IntervalVector iv({{1,2},{3,4},{5,6}}); + IntervalMatrix test5(iv); + CHECK(test5.rows() == 3); + CHECK(test5.cols() == 1); + CHECK(test5(0,0) == Interval(1,2)); + CHECK(test5(1,0) == Interval(3,4)); + CHECK(test5(2,0) == Interval(5,6)); + } } #if 0 diff --git a/tests/core/domains/interval/codac2_tests_IntervalMatrix.py b/tests/core/domains/interval/codac2_tests_IntervalMatrix.py index 69862df6..ba46854c 100644 --- a/tests/core/domains/interval/codac2_tests_IntervalMatrix.py +++ b/tests/core/domains/interval/codac2_tests_IntervalMatrix.py @@ -250,8 +250,8 @@ def tests_intervalmatrix(self): self.assertTrue(m1 == m2) self.assertTrue(self.M1().block(0,0,2,3) == self.M1()) - self.assertTrue(self.M1().block(0,0,1,3) == IntervalMatrix([[0,1],[0,2],[0,3]])) - self.assertTrue(self.M1().block(1,0,1,3) == IntervalMatrix([[-1,0],[-2,0],[-3,0]])) + self.assertTrue(self.M1().block(0,0,1,3) == IntervalMatrix([[[0,1],[0,2],[0,3]]])) + self.assertTrue(self.M1().block(1,0,1,3) == IntervalMatrix([[[-1,0],[-2,0],[-3,0]]])) self.assertTrue(self.M1().block(0,0,2,1) == IntervalMatrix([[[0,1]],[[-1,0]]])) self.assertTrue(self.M1().block(0,1,2,1) == IntervalMatrix([[[0,2]],[[-2,0]]])) self.assertTrue(self.M1().block(0,2,2,1) == IntervalMatrix([[[0,3]],[[-3,0]]])) @@ -603,6 +603,62 @@ def tests_intervalmatrix_mixing_type(self): [[21,21],[29,29]] ])) + test1 = IntervalMatrix([ + [ [0,1], [0,2], [0,0] ] + ]) + self.assertTrue(test1.rows() == 1) + self.assertTrue(test1.cols() == 3) + self.assertTrue(test1(0,0) == Interval(0,1)) + self.assertTrue(test1(0,1) == Interval(0,2)) + self.assertTrue(test1(0,2) == Interval(0,0)) + + test2 = IntervalMatrix([ + [0,1], + [2,3], + [4,5] + ]) + self.assertTrue(test2.rows() == 3) + self.assertTrue(test2.cols() == 2) + self.assertTrue(test2(0,0) == Interval(0)) + self.assertTrue(test2(0,1) == Interval(1)) + self.assertTrue(test2(1,0) == Interval(2)) + self.assertTrue(test2(1,1) == Interval(3)) + self.assertTrue(test2(2,0) == Interval(4)) + self.assertTrue(test2(2,1) == Interval(5)) + + test3 = IntervalMatrix([ + [[1,oo],[2,oo]], + [[3,oo],[4,oo]], + [[5,oo],[6,oo]] + ]) + self.assertTrue(test3.rows() == 3) + self.assertTrue(test3.cols() == 2) + self.assertTrue(test3(0,0) == Interval(1,oo)) + self.assertTrue(test3(0,1) == Interval(2,oo)) + self.assertTrue(test3(1,0) == Interval(3,oo)) + self.assertTrue(test3(1,1) == Interval(4,oo)) + self.assertTrue(test3(2,0) == Interval(5,oo)) + self.assertTrue(test3(2,1) == Interval(6,oo)) + + test4 = IntervalMatrix([ + [[1,2]], + [[3,4]], + [[5,6]] + ]) + self.assertTrue(test4.rows() == 3) + self.assertTrue(test4.cols() == 1) + self.assertTrue(test4(0,0) == Interval(1,2)) + self.assertTrue(test4(1,0) == Interval(3,4)) + self.assertTrue(test4(2,0) == Interval(5,6)) + + iv = IntervalVector([[1,2],[3,4],[5,6]]) + test5 = IntervalMatrix(iv) + self.assertTrue(test5.rows() == 3) + self.assertTrue(test5.cols() == 1) + self.assertTrue(test5(0,0) == Interval(1,2)) + self.assertTrue(test5(1,0) == Interval(3,4)) + self.assertTrue(test5(2,0) == Interval(5,6)) + if __name__ == '__main__': unittest.main() \ No newline at end of file From a4788f48db29e787d7e324427f5a610b1b454aa5 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 28 Nov 2024 21:22:05 +0100 Subject: [PATCH 072/102] [mat] revised display of matrix types --- 3rd/eigen | 2 +- src/core/domains/interval/codac2_Interval.cpp | 1 + .../domains/interval/codac2_IntervalMatrix.h | 20 ++++--------------- .../domains/interval/codac2_IntervalRow.h | 8 +++++--- .../domains/interval/codac2_IntervalVector.h | 14 ++++--------- src/core/matrices/codac2_Matrix.h | 6 ++++++ src/core/matrices/codac2_Row.h | 6 ++++++ src/core/matrices/codac2_Vector.h | 6 ++++++ src/core/matrices/codac2_matrices.h | 15 ++++++++++++++ 9 files changed, 48 insertions(+), 30 deletions(-) diff --git a/3rd/eigen b/3rd/eigen index f0955eec..23547192 160000 --- a/3rd/eigen +++ b/3rd/eigen @@ -1 +1 @@ -Subproject commit f0955eec9c80f8ff7c074266ca53000e6a2e91c3 +Subproject commit 2354719271ab49cc92a4f6a8ec3e491d58125273 diff --git a/src/core/domains/interval/codac2_Interval.cpp b/src/core/domains/interval/codac2_Interval.cpp index b0bc9e2d..7f53d83b 100644 --- a/src/core/domains/interval/codac2_Interval.cpp +++ b/src/core/domains/interval/codac2_Interval.cpp @@ -375,6 +375,7 @@ namespace codac2 ostream& operator<<(ostream& os, const Interval& x) { + gaol::interval::precision(os.precision()); ibex::operator<<(os,x); return os; } diff --git a/src/core/domains/interval/codac2_IntervalMatrix.h b/src/core/domains/interval/codac2_IntervalMatrix.h index 5b232ea8..a1fea32a 100644 --- a/src/core/domains/interval/codac2_IntervalMatrix.h +++ b/src/core/domains/interval/codac2_IntervalMatrix.h @@ -19,24 +19,12 @@ namespace codac2 inline std::ostream& operator<<(std::ostream& os, const IntervalMatrix& x) { if(x.is_empty()) - return os << "( empty matrix )"; + return os << "[ empty " << x.rows() << "x" << x.cols() << " mat ]"; else - return operator<<(os, - static_cast&>(x)); - - #if 0 // IBEX style - os << "("; - for(Index i = 0 ; i < x.rows() ; i++) - { - os << (i!=0 ? " " : "") << "("; - for(Index j = 0 ; j < x.cols() ; j++) - os << x(i,j) << (j&>(x)); + { + os << x.format(codac_row_fmt()); + return os; + } } } \ No newline at end of file diff --git a/src/core/domains/interval/codac2_IntervalVector.h b/src/core/domains/interval/codac2_IntervalVector.h index 4ce69cbe..b05ac04b 100644 --- a/src/core/domains/interval/codac2_IntervalVector.h +++ b/src/core/domains/interval/codac2_IntervalVector.h @@ -58,18 +58,12 @@ namespace codac2 inline std::ostream& operator<<(std::ostream& os, const IntervalVector& x) { if(x.is_empty()) - return os << "( empty vector )"; + return os << "[ empty vector ]"; else - return operator<<(os, - static_cast&>(x)); - - #if 0 // IBEX style - os << "("; - for(Index i = 0 ; i < x.size() ; i++) - os << x[i] << (i; + + inline std::ostream& operator<<(std::ostream& os, const Matrix& x) + { + os << x.format(codac_matrix_fmt()); + return os; + } } \ No newline at end of file diff --git a/src/core/matrices/codac2_Row.h b/src/core/matrices/codac2_Row.h index 79429ee4..7703efff 100644 --- a/src/core/matrices/codac2_Row.h +++ b/src/core/matrices/codac2_Row.h @@ -14,4 +14,10 @@ namespace codac2 { using Row = Eigen::Matrix; + + inline std::ostream& operator<<(std::ostream& os, const Row& x) + { + os << x.format(codac_row_fmt()); + return os; + } } \ No newline at end of file diff --git a/src/core/matrices/codac2_Vector.h b/src/core/matrices/codac2_Vector.h index 4926213f..3f4255c7 100644 --- a/src/core/matrices/codac2_Vector.h +++ b/src/core/matrices/codac2_Vector.h @@ -14,4 +14,10 @@ namespace codac2 { using Vector = Eigen::Matrix; + + inline std::ostream& operator<<(std::ostream& os, const Vector& x) + { + os << x.format(codac_vector_fmt()); + return os; + } } \ No newline at end of file diff --git a/src/core/matrices/codac2_matrices.h b/src/core/matrices/codac2_matrices.h index 5158b28c..5053886f 100644 --- a/src/core/matrices/codac2_matrices.h +++ b/src/core/matrices/codac2_matrices.h @@ -122,4 +122,19 @@ namespace codac2 h |= li; return h; } + + inline Eigen::IOFormat codac_row_fmt() + { + return Eigen::IOFormat(Eigen::StreamPrecision, Eigen::DontAlignCols, " ", "", "", "", "[ ", " ]"); + } + + inline Eigen::IOFormat codac_vector_fmt() + { + return Eigen::IOFormat(Eigen::StreamPrecision, Eigen::DontAlignCols, "", " ; ", "", "", "[ ", " ]"); + } + + inline Eigen::IOFormat codac_matrix_fmt() + { + return Eigen::IOFormat(Eigen::StreamPrecision, 0, " , ", "\n", "[ ", " ]", "[", "]"); + } } \ No newline at end of file From 1a27245b5ff8f5ab1d5e9af7d2a444744c1eb2c5 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 28 Nov 2024 23:23:55 +0100 Subject: [PATCH 073/102] [mat] added .min_rad(), .max_rad() --- .../interval/codac2_py_IntervalMatrixBase.h | 6 ++++++ .../codac2_Matrix_addons_IntervalMatrixBase.h | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h index 64b4a53a..1204acb8 100644 --- a/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h +++ b/python/src/core/domains/interval/codac2_py_IntervalMatrixBase.h @@ -61,6 +61,12 @@ void export_IntervalMatrixBase(py::module& m, py::class_& pyclass) .def("diam", [](const S& x) { return x.diam(); }, MATRIXBASE_ADDONS_INTERVALMATRIXBASE_AUTO_DIAM_CONST) + .def("min_rad", [](const S& x) { return x.min_rad(); }, + MATRIX_ADDONS_INTERVALMATRIXBASE_DOUBLE_MIN_RAD_CONST) + + .def("max_rad", [](const S& x) { return x.max_rad(); }, + MATRIX_ADDONS_INTERVALMATRIXBASE_DOUBLE_MAX_RAD_CONST) + .def("min_diam", [](const S& x) { return x.min_diam(); }, MATRIX_ADDONS_INTERVALMATRIXBASE_DOUBLE_MIN_DIAM_CONST) diff --git a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h index 21ed9e54..a5d2c48f 100644 --- a/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h +++ b/src/core/matrices/eigen/Matrix_addons/codac2_Matrix_addons_IntervalMatrixBase.h @@ -65,6 +65,20 @@ inline bool operator==(const MatrixBase& x) const return operator==(x.eval().template cast()); } +template + requires IsIntervalDomain +inline double min_rad() const +{ + return (this->data()+extr_diam_index(true))->rad(); +} + +template + requires IsIntervalDomain +inline double max_rad() const +{ + return (this->data()+extr_diam_index(false))->rad(); +} + template requires IsIntervalDomain inline double min_diam() const From fc8909bbb449a469f549ad7aa5b55294501b6ae6 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 28 Nov 2024 23:26:04 +0100 Subject: [PATCH 074/102] [inv] updates using Eigen's expression templates + factorization --- src/core/matrices/codac2_Inversion.cpp | 109 +------------------------ src/core/matrices/codac2_Inversion.h | 77 ++++++++++++----- 2 files changed, 60 insertions(+), 126 deletions(-) diff --git a/src/core/matrices/codac2_Inversion.cpp b/src/core/matrices/codac2_Inversion.cpp index 2dae4060..aa8044e4 100644 --- a/src/core/matrices/codac2_Inversion.cpp +++ b/src/core/matrices/codac2_Inversion.cpp @@ -18,7 +18,7 @@ namespace codac2 { /** \brief Compute an upper bound of A+A^2+A^3 with A a matrix of intervals * \param A matrix of intervals (supposed around 0) - * \param mrad the maximum radius of the result added (output argument) + * \param mrad the maximum radius of the result added (output argument, not available in Python) * \return the enclosure. May include (-oo,oo) */ IntervalMatrix infinite_sum_enclosure(const IntervalMatrix& A, double &mrad) { @@ -69,112 +69,7 @@ namespace codac2 } return res; } - - /** \brief Correct the approximate inverse of a matrix - * \param A a matrix - * \param B a punctual approximation of its inverse - * \param left use BA - * \return the enclosure - */ - IntervalMatrix inverse_correction(const Matrix &A, const Matrix &B, bool left) { - assert_release(A.is_squared()); - assert_release(B.is_squared()); - Index N = A.rows(); - assert_release(N==B.rows()); - - IntervalMatrix Id = IntervalMatrix::Identity(N,N); - IntervalMatrix erMat = (left ? - IntervalMatrix(-IntervalMatrix(B)*IntervalMatrix(A)+Id) : - IntervalMatrix(-IntervalMatrix(A)*IntervalMatrix(B)+Id)); - - double mrad=0.0; - IntervalMatrix E = infinite_sum_enclosure(erMat,mrad); - IntervalMatrix Ep = Id+erMat*(Id+E); - /* one could use several iterations here, either - using mrad, or directly */ - - IntervalMatrix res(N,N); - if (left) - res = Ep*IntervalMatrix(B); - else - res = IntervalMatrix(B)*Ep; - /* small problem with the matrix product : 0*oo = 0. We correct that - "by hand" (?) */ - if (mrad==oo) { - for (Index c=0;c(A, (A.mid()).fullPivLu().solve(Matrix::Identity(N,N))); } } diff --git a/src/core/matrices/codac2_Inversion.h b/src/core/matrices/codac2_Inversion.h index 27a76e8b..de4bfa2f 100644 --- a/src/core/matrices/codac2_Inversion.h +++ b/src/core/matrices/codac2_Inversion.h @@ -15,6 +15,8 @@ namespace codac2 { + enum LeftOrRightInv { LEFT_INV, RIGHT_INV }; + /** \brief Compute an upper bound of A+A^2+A^3 with A a matrix of intervals * as an "error term" (use only bounds on coefficients) * \param A matrix of intervals (supposed around 0) @@ -24,32 +26,69 @@ namespace codac2 IntervalMatrix infinite_sum_enclosure(const IntervalMatrix& A, double &mrad); /** \brief Correct the approximate inverse of a matrix - * \param A a matrix - * \param B a punctual approximation of its inverse - * \param left use the inverse of BA (otherwise use the inverse of AB, - * true is normally better) + * \tparam O if LEFT_INV, use the inverse of BA (otherwise use the inverse of AB, + * left inverse is normally better) + * \param A_ a matrix expression + * \param B_ a (almost punctual) approximation of its inverse, * \return the enclosure */ - IntervalMatrix inverse_correction(const Matrix &A, const Matrix &B, - bool left=true); + template + inline IntervalMatrix inverse_correction(const Eigen::MatrixBase& A_, const Eigen::MatrixBase& B_) + { + assert_release(A_.is_squared()); + assert_release(B_.is_squared()); - /** \brief Correct the approximate inverse of a matrix - * \param A a matrix - * \param B a (almost punctual) approximation of its inverse, - * \param left use the inverse of BA (otherwise use the inverse of AB, - * left is normally better) - * \return the enclosure - */ - IntervalMatrix inverse_correction(const IntervalMatrix &A, const Matrix &B, - bool left=true); + auto A = A_.template cast(); + auto B = B_.template cast(); + + Index N = A.rows(); + assert_release(N==B.rows()); - /** \brief Enclosure of the inverse of a (non-singular) matrix - * \param A matrix + auto Id = IntervalMatrix::Identity(N,N); + auto erMat = [&]() { if constexpr(O == LEFT_INV) return -B*A+Id; else return -A*B+Id; }(); + + double mrad=0.0; + IntervalMatrix E = infinite_sum_enclosure(erMat,mrad); + IntervalMatrix Ep = Id+erMat*(Id+E); + /* one could use several iterations here, either + using mrad, or directly */ + + auto res = (O == LEFT_INV) ? IntervalMatrix(Ep*B) : IntervalMatrix(B*Ep); + + /* small problem with the matrix product : 0*oo = 0. We correct that + "by hand" (?) */ + if (mrad==oo) { + for (Index c=0;c + inline IntervalMatrix inverse_enclosure(const Eigen::MatrixBase& A) + { + assert_release(A.is_squared()); + Index N=A.rows(); + return inverse_correction(A, + A.fullPivLu().solve(Matrix::Identity(N,N))); + } + + /** \brief Enclosure of the inverse of a matrix of intervals * \param A matrix of intervals * \return the enclosure. Can have (-oo,oo) coefficients if the From e0671fcf6b9f3b5d790a106f5506e91c7970eb8d Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 28 Nov 2024 23:26:27 +0100 Subject: [PATCH 075/102] [inv] updated py-binding + tests --- .../src/core/matrices/codac2_py_Inversion.cpp | 44 +++++++------------ .../core/matrices/codac2_tests_Inversion.cpp | 10 ++++- tests/core/matrices/codac2_tests_Inversion.py | 32 ++++++++++++-- 3 files changed, 54 insertions(+), 32 deletions(-) diff --git a/python/src/core/matrices/codac2_py_Inversion.cpp b/python/src/core/matrices/codac2_py_Inversion.cpp index be0d4da8..d99d732c 100644 --- a/python/src/core/matrices/codac2_py_Inversion.cpp +++ b/python/src/core/matrices/codac2_py_Inversion.cpp @@ -2,7 +2,7 @@ * Inversion of matrices * ---------------------------------------------------------------------------- * \date 2024 - * \author Damien + * \author Damien Massé * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ @@ -24,42 +24,30 @@ using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; -using B = Eigen::Block; -using IB = Eigen::Block; - void export_Inversion(py::module& m) { m - .def("infinite_sum_enclosure", - (IntervalMatrix(*)(const IntervalMatrix&,double&)) - &codac2::infinite_sum_enclosure, + .def("infinite_sum_enclosure", [](const IntervalMatrix& A) { double mrad; return infinite_sum_enclosure(A,mrad); }, INTERVALMATRIX_INFINITE_SUM_ENCLOSURE_CONST_INTERVALMATRIX_REF_DOUBLE_REF, - "A"_a, "mrad"_a) - - .def("inverse_correction", - (IntervalMatrix(*)(const Matrix&,const Matrix&,bool)) - &codac2::inverse_correction, - INTERVALMATRIX_INVERSE_CORRECTION_CONST_MATRIX_REF_CONST_MATRIX_REF_BOOL, - "A"_a, "B"_a, "left"_a) + "A"_a) - .def("inverse_correction", - (IntervalMatrix(*)(const IntervalMatrix&,const Matrix&,bool)) - &codac2::inverse_correction, - INTERVALMATRIX_INVERSE_CORRECTION_CONST_INTERVALMATRIX_REF_CONST_MATRIX_REF_BOOL, - "A"_a, "B"_a, "left"_a) + .def("inverse_correction", [](const IntervalMatrix& A, const IntervalMatrix& B, bool left_inv = true) + { + return left_inv ? inverse_correction(A,B) : inverse_correction(A,B); + }, + INTERVALMATRIX_INVERSE_CORRECTION_CONST_EIGEN_MATRIXBASE_OTHERDERIVED_REF_CONST_EIGEN_MATRIXBASE_OTHERDERIVED__REF, + "A"_a, "B"_a, "left_inv"_a) - .def("inverse_enclosure", - (IntervalMatrix(*)(const Matrix&)) - &codac2::inverse_enclosure, - INTERVALMATRIX_INVERSE_ENCLOSURE_CONST_MATRIX_REF, - "A"_a) + .def("inverse_enclosure", [](const Matrix& A) { return inverse_enclosure(A); }, + INTERVALMATRIX_INVERSE_ENCLOSURE_CONST_EIGEN_MATRIXBASE_OTHERDERIVED_REF, + "A"_a) .def("inverse_enclosure", - (IntervalMatrix(*)(const IntervalMatrix&)) - &codac2::inverse_enclosure, - INTERVALMATRIX_INVERSE_ENCLOSURE_CONST_MATRIX_REF, - "A"_a) + (IntervalMatrix(*)(const IntervalMatrix&)) + &codac2::inverse_enclosure, + INTERVALMATRIX_INVERSE_ENCLOSURE_CONST_INTERVALMATRIX_REF, + "A"_a) ; } diff --git a/tests/core/matrices/codac2_tests_Inversion.cpp b/tests/core/matrices/codac2_tests_Inversion.cpp index 88f9c0d8..26eb6b47 100644 --- a/tests/core/matrices/codac2_tests_Inversion.cpp +++ b/tests/core/matrices/codac2_tests_Inversion.cpp @@ -41,6 +41,14 @@ TEST_CASE("Matrix") }); IntervalMatrix v=inverse_enclosure(u); - CHECK((IntervalMatrix(u)*v).contains(Matrix::Identity(3,3))); + CHECK((u.template cast()*v).contains(Matrix::Identity(3,3))); + Matrix w({ + { 1, 2, 0 }, + { 3, 4, 1 }, + { 0, 1, 0 }, + }); + + y = inverse_enclosure(w); + CHECK((w.template cast()*y).contains(Matrix::Identity(3,3))); } diff --git a/tests/core/matrices/codac2_tests_Inversion.py b/tests/core/matrices/codac2_tests_Inversion.py index a831263a..eabad434 100644 --- a/tests/core/matrices/codac2_tests_Inversion.py +++ b/tests/core/matrices/codac2_tests_Inversion.py @@ -13,7 +13,7 @@ class TestInversion(unittest.TestCase): - def tests_Inversion(self): + def tests_Inversion_1(self): x = Matrix([ [ 1, 2, 0 ], @@ -22,10 +22,36 @@ def tests_Inversion(self): ]) y = inverse_enclosure(x) + self.assertTrue((x*y).contains(Matrix.eye(3,3))) - self.assertTrue((x*y).contains(Matrix.eye(3,3))); + def tests_Inversion_2(self): + + x = IntervalMatrix([ + [ [0.0,0.0], [-0.1,-0.1], [0.2,0.2] ], + [ [0.0,0.0], [-0.2,-0.2], [0.1,0.1] ], + [ [0.1,0.1], [-0.1,-0.1], [0.1,0.1] ] + ]) + + y = infinite_sum_enclosure(x) + #self.assertTrue(Approx(y.max_rad())==Interval(5.0)/Interval(2.0)) + + z = inverse_enclosure(x) + self.assertTrue(z(1,2)==Interval(0)) + self.assertTrue(Approx(z*x)==IntervalMatrix.eye(3,3)) + + + def tests_Inversion_3(self): + + u = Matrix([ + [ 1,2,3 ], + [ 1,3,5 ], + [ 3,4,5 ] + ]) + + v = inverse_enclosure(u) + self.assertTrue((u*v).contains(Matrix.eye(3,3))) if __name__ == '__main__': - unittest.main() + unittest.main() \ No newline at end of file From 25ae46106fd8a34ad1dffeed259917dc2dcd0349 Mon Sep 17 00:00:00 2001 From: godardma Date: Fri, 29 Nov 2024 17:58:52 +0100 Subject: [PATCH 076/102] [graphics] Color variant version, python binding to do --- examples/00_graphics/graphic_examples.py | 18 +-- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 40 ++--- .../3rd/vibes/codac2_Figure2D_VIBes.cpp | 2 +- src/graphics/CMakeLists.txt | 4 +- src/graphics/styles/codac2_Color.cpp | 145 ++++++++++++++---- src/graphics/styles/codac2_Color.h | 38 ++++- 6 files changed, 175 insertions(+), 72 deletions(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index 077c5ecc..aed875bf 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -51,12 +51,12 @@ fig3.set_axes(axis(0,[-1,21]), axis(1,[-0.5,3.5])) fig3.set_window_properties([250,250],[500,500]) -cmap_haxby=ColorMap.HAXBY -cmap_blue_tube=ColorMap.BLUE_TUBE -cmap_red_tube=ColorMap.RED_TUBE - -for i in range (20): - ratio=i/20 - fig3.draw_box([[i,i+1],[0,1]],[Color.black(),cmap_haxby.color(ratio)]) - fig3.draw_box([[i,i+1],[1,2]],[Color.black(),cmap_blue_tube.color(ratio)]) - fig3.draw_box([[i,i+1],[2,3]],[Color.black(),cmap_red_tube.color(ratio)]) \ No newline at end of file +# cmap_haxby=ColorMap.HAXBY +# cmap_blue_tube=ColorMap.BLUE_TUBE +# cmap_red_tube=ColorMap.RED_TUBE + +# for i in range (20): +# ratio=i/20 +# fig3.draw_box([[i,i+1],[0,1]],[Color.black(),cmap_haxby.color(ratio)]) +# fig3.draw_box([[i,i+1],[1,2]],[Color.black(),cmap_blue_tube.color(ratio)]) +# fig3.draw_box([[i,i+1],[2,3]],[Color.black(),cmap_red_tube.color(ratio)]) \ No newline at end of file diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 5dab8020..789cbdc7 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -35,7 +35,7 @@ Figure2D_IPE::Figure2D_IPE(const Figure2D& fig) for(const auto& ci : codac_colors) // substr is needed to remove the "#" at the beginning of hex_str (deprecated by IPE) - _colors.emplace(ci.hex_str.substr(1), ci); + _colors.emplace(ci.hex_str().substr(1), ci); } Figure2D_IPE::~Figure2D_IPE() @@ -78,15 +78,15 @@ void Figure2D_IPE::center_viewbox([[maybe_unused]] const Vector& c, [[maybe_unus void Figure2D_IPE::begin_path(const StyleProperties& s, bool tip=false) { // substr is needed to remove the "#" at the beginning of hex_str (deprecated by IPE) - _colors.emplace(s.stroke_color.hex_str.substr(1), s.stroke_color); - _colors.emplace(s.fill_color.hex_str.substr(1), s.fill_color); + _colors.emplace(s.stroke_color.hex_str().substr(1), s.stroke_color); + _colors.emplace(s.fill_color.hex_str().substr(1), s.fill_color); _f_temp_content << "\n \ "; } @@ -545,7 +545,7 @@ void Figure2D_IPE::print_header_page() for(const auto& [k,c] : _colors) _f << " \n"; + << "value=\"" << c.r() << " " << c.g() << " " << c.b() << "\" /> \n"; _f << " \n \ \n \ diff --git a/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.cpp b/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.cpp index 3b5a9d94..582e5a97 100644 --- a/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.cpp +++ b/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.cpp @@ -144,5 +144,5 @@ void Figure2D_VIBes::draw_AUV(const Vector& x, float size, const StyleProperties string Figure2D_VIBes::to_vibes_style(const StyleProperties& s) { - return s.stroke_color.hex_str + "[" + s.fill_color.hex_str + "]"; + return s.stroke_color.hex_str() + "[" + s.fill_color.hex_str() + "]"; } \ No newline at end of file diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt index c18ba4b8..533e3562 100644 --- a/src/graphics/CMakeLists.txt +++ b/src/graphics/CMakeLists.txt @@ -22,8 +22,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_Color.cpp ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_Color.h - ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.h + # ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.cpp + # ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.h ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_StyleProperties.cpp ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_StyleProperties.h ) diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index a2638c5c..6b69560f 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -12,50 +12,131 @@ using namespace std; using namespace codac2; +std::string DataRGB::to_hex_str() const +{ + stringstream ss; + ss << "#" << hex << setfill('0') << setw(2) << (int)(r*255) << setw(2) << (int)(g*255) << setw(2) << (int)(b*255) << setw(2) << (int)(a*255); + return ss.str(); +} + +DataRGB DataHSV::to_rgb() const +{ + float r = 1., g = 1., b = 1.; + + int i = static_cast(h * 6); + float f = (h * 6) - i; + i = i % 6; + + float p = v * (1 - s); + float q = v * (1 - f * s); + float t = v * (1 - (1 - f) * s); + + switch (i) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } + + return DataRGB{r, g, b, a}; +} + +std::string DataHSV::to_hex_str() const +{ + return to_rgb().to_hex_str(); +} + Color::Color() - : r(1.), g(1.), b(1.), alpha(1.), hex_str("#FFFFFF") + : data("#FFFFFFFF") {} -Color::Color(float r_, float g_, float b_, float alpha_) - : r(r_), g(g_), b(b_), alpha(alpha_), - hex_str([&] - { - std::stringstream s; - s << std::hex << std::setfill('0'); - s << std::setw(2) << (int)(r*255) << std::setw(2) << (int)(g*255) << std::setw(2) << (int)(b*255); - if(alpha != 1.) - s << std::setw(2) << (int)(alpha*255); - return "#"+s.str(); - }()) +Color::Color(float x1, float x2, float x3, float alpha,InterpolMode interpol_mode) { - assert(r_ >= 0. && r_ <= 1. && g_ >= 0. && g_ <= 1. && b_ >= 0. && b_ <= 1. && alpha_ >= 0. && alpha_ <= 1.); + assert(x1 >= 0. && x1 <= 1. && x2 >= 0. && x2 <= 1. && x3 >= 0. && x3 <= 1. && alpha >= 0. && alpha <= 1.); + if(interpol_mode == InterpolMode::RGB) + data = DataRGB{x1, x2, x3, alpha}; + else + data = DataHSV{x1, x2, x3, alpha}; +} + +Color::Color(int x1, int x2, int x3, int alpha,InterpolMode interpol_mode) + : Color((float)(x1/255.), (float)(x2/255.), (float)(x3/255.), (float)(alpha/255.),interpol_mode) +{ + assert(x1 >= 0 && x1 <= 255 && x2 >= 0 && x2 <= 255 && x3 >= 0 && x3 <= 255 && alpha >= 0 && alpha <= 255); } -Color::Color(int r_, int g_, int b_, int alpha_) - : Color((float)(r_/255.), (float)(g_/255.), (float)(b_/255.), (float)(alpha_/255.)) +Color::Color(const std::string& hex_str) + : data(hex_str) { - assert(r_ >= 0 && r_ <= 255 && g_ >= 0 && g_ <= 255 && b_ >= 0 && b_ <= 255 && alpha_ >= 0 && alpha_ <= 255); + assert(hex_str.size() == 7 || hex_str.size() == 9); + assert(hex_str[0] == '#'); } -Color::Color(const std::string& hex_str_) - : hex_str(hex_str_) +std::string Color::hex_str() const { - assert(hex_str_.size() == 7 || hex_str_.size() == 9); - assert(hex_str_[0] == '#'); + switch(data.index()) + { + case 0: return std::get<0>(data); + case 1: return std::get<1>(data).to_hex_str(); + case 2: return std::get<2>(data).to_hex_str(); + } + return ""; +} + +float Color::r() const +{ + switch(data.index()) + { + case 0: + float r; + std::istringstream(std::get<0>(data).substr(1,2)) >> std::hex >> r; + return r/255.; + case 1: return std::get<1>(data).r; + case 2: return std::get<2>(data).to_rgb().r; + } + return 0.; +} + +float Color::g() const +{ + switch(data.index()) + { + case 0: + float g; + std::istringstream(std::get<0>(data).substr(3,2)) >> std::hex >> g; + return g/255.; + case 1: return std::get<1>(data).g; + case 2: return std::get<2>(data).to_rgb().g; + } + return 0.; +} - int red,green,blue,a; - std::istringstream(hex_str_.substr(1,2)) >> std::hex >> red; - std::istringstream(hex_str_.substr(3,2)) >> std::hex >> green; - std::istringstream(hex_str_.substr(5,2)) >> std::hex >> blue; - r = (float)red/255.; - g = (float)green/255.; - b = (float)blue/255.; +float Color::b() const +{ + switch(data.index()) + { + case 0: + float b; + std::istringstream(std::get<0>(data).substr(5,2)) >> std::hex >> b; + return b/255.; + case 1: return std::get<1>(data).b; + case 2: return std::get<2>(data).to_rgb().b; + } + return 0.; +} - // Alpha (transparency) component may be appended to the #hexa notation. - // Value is '1' (max opacity) by default. - if(hex_str_.size() == 9) +float Color::alpha() const +{ + switch(data.index()) { - std::istringstream(hex_str_.substr(7,2)) >> std::hex >> a; - alpha = (float)a/255.; + case 0: + float alpha; + std::istringstream(std::get<0>(data).substr(7,2)) >> std::hex >> alpha; + return alpha/255.; + case 1: return std::get<1>(data).a; + case 2: return std::get<2>(data).a; } + return 0.; } \ No newline at end of file diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index 6d8a992c..9cf18cdb 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -11,26 +11,48 @@ #include #include +#include #include"codac2_assert.h" namespace codac2 { + enum class InterpolMode { RGB, HSV }; /** - * \struct Color + * \struct DataRGB * \brief Represents an RGB value */ + struct DataRGB { + float r, g, b, a; + std::string to_hex_str() const; + }; + /** + * \struct DataHSV + * \brief Represents an HSV value + */ + struct DataHSV { + float h, s, v, a; + DataRGB to_rgb() const; + std::string to_hex_str() const; + }; + /** + * \struct Color + * \brief Represents an html color + */ struct Color { - float r; ///< red, value between 0. and 1. - float g; ///< green, value between 0. and 1. - float b; ///< blue, value between 0. and 1. - float alpha = 1.; ///< opacity, value between 0. (transparent) and 1. (opaque) - std::string hex_str; ///< represents an RGB value in a HTML standard + std::variant< std::string, DataRGB, DataHSV > data; - explicit Color(float r, float g, float b, float alpha = 1.); - explicit Color(int r, int g, int b, int alpha = 255); + explicit Color(); + explicit Color(float x1, float x2, float x3, float alpha = 1.,InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(int x1, int x2, int x3, int alpha = 255,InterpolMode interpol_mode = InterpolMode::RGB); explicit Color(const std::string& hex_str); + std::string hex_str() const; + float r() const; + float g() const; + float b() const; + float alpha() const; + static Color none() { return Color(255, 255, 255, 0 ); }; static Color black(float alpha = 1) { return Color(0, 0, 0, (int)(alpha*255)); }; static Color white(float alpha = 1) { return Color(255, 255, 255, (int)(alpha*255)); }; From 7d691d5dc0e7479968cf330f2b569e1ce69bf0b4 Mon Sep 17 00:00:00 2001 From: godardma Date: Fri, 29 Nov 2024 23:51:08 +0100 Subject: [PATCH 077/102] [graphics] changed Color representation to variant --- examples/00_graphics/graphic_examples.py | 7 +- python/src/graphics/CMakeLists.txt | 2 +- python/src/graphics/codac2_py_graphics.cpp | 4 +- .../src/graphics/styles/codac2_py_Color.cpp | 65 +++++++++++++++---- src/graphics/styles/codac2_Color.cpp | 21 +++--- src/graphics/styles/codac2_Color.h | 6 +- 6 files changed, 77 insertions(+), 28 deletions(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index aed875bf..71625bf2 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -46,10 +46,11 @@ fig2.draw_ellipse([1,1],[0.5,2], 0.2, [Color.blue(),Color.blue(0.3)]) fig2.draw_point([2,2], [Color.red(),Color.yellow(0.5)]) fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) +fig2.draw_box([[2.6,3.1],[2.6,3.1]],[Color(0.305555556,0.9,0.78,interpol_mode=InterpolMode.HSV),Color(0.305555556,0.9,0.78,0.2,InterpolMode.HSV)]) -fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) -fig3.set_axes(axis(0,[-1,21]), axis(1,[-0.5,3.5])) -fig3.set_window_properties([250,250],[500,500]) +# fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) +# fig3.set_axes(axis(0,[-1,21]), axis(1,[-0.5,3.5])) +# fig3.set_window_properties([250,250],[500,500]) # cmap_haxby=ColorMap.HAXBY # cmap_blue_tube=ColorMap.BLUE_TUBE diff --git a/python/src/graphics/CMakeLists.txt b/python/src/graphics/CMakeLists.txt index 8b5add11..b46e24dd 100644 --- a/python/src/graphics/CMakeLists.txt +++ b/python/src/graphics/CMakeLists.txt @@ -12,7 +12,7 @@ paver/codac2_py_drawwhilepaving.cpp styles/codac2_py_Color.cpp - styles/codac2_py_ColorMap.cpp + # styles/codac2_py_ColorMap.cpp styles/codac2_py_StyleProperties.cpp ) diff --git a/python/src/graphics/codac2_py_graphics.cpp b/python/src/graphics/codac2_py_graphics.cpp index c5f9b520..05d37453 100644 --- a/python/src/graphics/codac2_py_graphics.cpp +++ b/python/src/graphics/codac2_py_graphics.cpp @@ -22,7 +22,7 @@ void export_drawwhilepaving(py::module& m); // styles void export_Color(py::module& m); -void export_ColorMap(py::module& m); +// void export_ColorMap(py::module& m); void export_StyleProperties(py::module& m); @@ -32,7 +32,7 @@ PYBIND11_MODULE(_graphics, m) // styles export_Color(m); - export_ColorMap(m); + // export_ColorMap(m); export_StyleProperties(m); // figures diff --git a/python/src/graphics/styles/codac2_py_Color.cpp b/python/src/graphics/styles/codac2_py_Color.cpp index ec541404..b744bd0f 100644 --- a/python/src/graphics/styles/codac2_py_Color.cpp +++ b/python/src/graphics/styles/codac2_py_Color.cpp @@ -19,32 +19,71 @@ using namespace codac2; namespace py = pybind11; using namespace pybind11::literals; + void export_Color(py::module& m) { + py::enum_(m, "InterpolMode") + .value("RGB", InterpolMode::RGB) + .value("HSV", InterpolMode::HSV) + ; + + py::class_ exported_data_rgb(m, "DataRGB", DATARGB_MAIN); + exported_data_rgb + .def_readwrite("r", &DataRGB::r) + .def_readwrite("g", &DataRGB::g) + .def_readwrite("b", &DataRGB::b) + .def_readwrite("a", &DataRGB::a) + .def("to_hex_str", &DataRGB::to_hex_str, STRING_DATARGB_TO_HEX_STR_CONST) + ; + + py::class_ exported_data_hsv(m, "DataHSV", DATAHSV_MAIN); + exported_data_hsv + .def_readwrite("h", &DataHSV::h) + .def_readwrite("s", &DataHSV::s) + .def_readwrite("v", &DataHSV::v) + .def_readwrite("a", &DataHSV::a) + .def("to_rgb", &DataHSV::to_rgb, DATARGB_DATAHSV_TO_RGB_CONST) + .def("to_hex_str", &DataHSV::to_hex_str, STRING_DATAHSV_TO_HEX_STR_CONST) + ; + + py::class_ exported_color(m, "Color", COLOR_MAIN); exported_color - .def_readwrite("r", &Color::r) - .def_readwrite("g", &Color::g) - .def_readwrite("b", &Color::b) - .def_readwrite("alpha", &Color::alpha) - .def_readwrite("hex_str", &Color::hex_str) + .def_readwrite("data", &Color::data, + VARIANT_STRINGDATARGBDATAHSV_COLOR_DATA) - .def(py::init<>(), - COLOR_COLOR) + .def(py::init<>(),COLOR_COLOR) - .def(py::init(), - COLOR_COLOR_INT_INT_INT_INT, - "r"_a, "g"_a, "b"_a, "alpha"_a=255) + .def(py::init(), + COLOR_COLOR_FLOAT_FLOAT_FLOAT_FLOAT_INTERPOLMODE, + "x1"_a, "x2"_a, "x3"_a, "alpha"_a=1., "interpol_mode"_a=InterpolMode::RGB) - .def(py::init(), - COLOR_COLOR_FLOAT_FLOAT_FLOAT_FLOAT, - "r"_a, "g"_a, "b"_a, "alpha"_a=1.) + .def(py::init(), + COLOR_COLOR_INT_INT_INT_INT_INTERPOLMODE, + "x1"_a, "x2"_a, "x3"_a, "alpha"_a=255, "interpol_mode"_a=InterpolMode::RGB) .def(py::init(), COLOR_COLOR_CONST_STRING_REF, "hex_str"_a) + // Properties + + .def("hex_str", &Color::hex_str, + STRING_COLOR_HEX_STR_CONST) + + .def("r", &Color::r, + FLOAT_COLOR_R_CONST) + + .def("g", &Color::g, + FLOAT_COLOR_G_CONST) + + .def("b", &Color::b, + FLOAT_COLOR_B_CONST) + + .def("alpha", &Color::alpha, + FLOAT_COLOR_ALPHA_CONST) + // Predefined colors .def_static("none", &Color::none, diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index 6b69560f..f643f0d4 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -90,9 +90,9 @@ float Color::r() const switch(data.index()) { case 0: - float r; + int r; std::istringstream(std::get<0>(data).substr(1,2)) >> std::hex >> r; - return r/255.; + return (float) r/255.; case 1: return std::get<1>(data).r; case 2: return std::get<2>(data).to_rgb().r; } @@ -104,9 +104,9 @@ float Color::g() const switch(data.index()) { case 0: - float g; + int g; std::istringstream(std::get<0>(data).substr(3,2)) >> std::hex >> g; - return g/255.; + return (float) g/255.; case 1: return std::get<1>(data).g; case 2: return std::get<2>(data).to_rgb().g; } @@ -118,9 +118,9 @@ float Color::b() const switch(data.index()) { case 0: - float b; + int b; std::istringstream(std::get<0>(data).substr(5,2)) >> std::hex >> b; - return b/255.; + return (float) b/255.; case 1: return std::get<1>(data).b; case 2: return std::get<2>(data).to_rgb().b; } @@ -133,8 +133,13 @@ float Color::alpha() const { case 0: float alpha; - std::istringstream(std::get<0>(data).substr(7,2)) >> std::hex >> alpha; - return alpha/255.; + if (std::get<0>(data).size() == 7) + return 1.; + else + { + std::istringstream(std::get<0>(data).substr(7,2)) >> std::hex >> alpha; + return alpha/255.; + } case 1: return std::get<1>(data).a; case 2: return std::get<2>(data).a; } diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index 9cf18cdb..7eb4f7e1 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -16,7 +16,11 @@ namespace codac2 { - enum class InterpolMode { RGB, HSV }; + enum class InterpolMode + { + RGB = 0x01, + HSV = 0x02 + }; /** * \struct DataRGB * \brief Represents an RGB value From be1ced1883045478a87c1893144b3d25f5e6ae7f Mon Sep 17 00:00:00 2001 From: godardma Date: Sat, 30 Nov 2024 01:05:04 +0100 Subject: [PATCH 078/102] [graphics] Colormaps, rainbow and default --- examples/00_graphics/graphic_examples.py | 30 ++++++---- python/src/graphics/CMakeLists.txt | 2 +- python/src/graphics/codac2_py_graphics.cpp | 4 +- .../graphics/styles/codac2_py_ColorMap.cpp | 5 ++ src/graphics/CMakeLists.txt | 4 +- src/graphics/styles/codac2_Color.cpp | 5 +- src/graphics/styles/codac2_ColorMap.cpp | 60 +++++++++++++++++-- src/graphics/styles/codac2_ColorMap.h | 8 ++- 8 files changed, 91 insertions(+), 27 deletions(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index 71625bf2..4d8549bb 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -48,16 +48,20 @@ fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) fig2.draw_box([[2.6,3.1],[2.6,3.1]],[Color(0.305555556,0.9,0.78,interpol_mode=InterpolMode.HSV),Color(0.305555556,0.9,0.78,0.2,InterpolMode.HSV)]) -# fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) -# fig3.set_axes(axis(0,[-1,21]), axis(1,[-0.5,3.5])) -# fig3.set_window_properties([250,250],[500,500]) - -# cmap_haxby=ColorMap.HAXBY -# cmap_blue_tube=ColorMap.BLUE_TUBE -# cmap_red_tube=ColorMap.RED_TUBE - -# for i in range (20): -# ratio=i/20 -# fig3.draw_box([[i,i+1],[0,1]],[Color.black(),cmap_haxby.color(ratio)]) -# fig3.draw_box([[i,i+1],[1,2]],[Color.black(),cmap_blue_tube.color(ratio)]) -# fig3.draw_box([[i,i+1],[2,3]],[Color.black(),cmap_red_tube.color(ratio)]) \ No newline at end of file +fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) +fig3.set_axes(axis(0,[-1,21]), axis(1,[-5.5,0.5])) +fig3.set_window_properties([800,250],[500,500]) + +cmap_haxby=ColorMap.HAXBY +cmap_default=ColorMap.DEFAULT +cmap_blue_tube=ColorMap.BLUE_TUBE +cmap_red_tube=ColorMap.RED_TUBE +cmap_rainbow=ColorMap.RAINBOW + +for i in range (20): + ratio=i/20 + fig3.draw_box([[i,i+1],[-1,0]],[Color.black(),cmap_haxby.color(ratio)]) + fig3.draw_box([[i,i+1],[-2,-1]],[Color.black(),cmap_default.color(ratio)]) + fig3.draw_box([[i,i+1],[-3,-2]],[Color.black(),cmap_blue_tube.color(ratio)]) + fig3.draw_box([[i,i+1],[-4,-3]],[Color.black(),cmap_red_tube.color(ratio)]) + fig3.draw_box([[i,i+1],[-5,-4]],[Color.black(),cmap_rainbow.color(ratio)]) \ No newline at end of file diff --git a/python/src/graphics/CMakeLists.txt b/python/src/graphics/CMakeLists.txt index b46e24dd..8b5add11 100644 --- a/python/src/graphics/CMakeLists.txt +++ b/python/src/graphics/CMakeLists.txt @@ -12,7 +12,7 @@ paver/codac2_py_drawwhilepaving.cpp styles/codac2_py_Color.cpp - # styles/codac2_py_ColorMap.cpp + styles/codac2_py_ColorMap.cpp styles/codac2_py_StyleProperties.cpp ) diff --git a/python/src/graphics/codac2_py_graphics.cpp b/python/src/graphics/codac2_py_graphics.cpp index 05d37453..c5f9b520 100644 --- a/python/src/graphics/codac2_py_graphics.cpp +++ b/python/src/graphics/codac2_py_graphics.cpp @@ -22,7 +22,7 @@ void export_drawwhilepaving(py::module& m); // styles void export_Color(py::module& m); -// void export_ColorMap(py::module& m); +void export_ColorMap(py::module& m); void export_StyleProperties(py::module& m); @@ -32,7 +32,7 @@ PYBIND11_MODULE(_graphics, m) // styles export_Color(m); - // export_ColorMap(m); + export_ColorMap(m); export_StyleProperties(m); // figures diff --git a/python/src/graphics/styles/codac2_py_ColorMap.cpp b/python/src/graphics/styles/codac2_py_ColorMap.cpp index 773b9564..11b66b9d 100644 --- a/python/src/graphics/styles/codac2_py_ColorMap.cpp +++ b/python/src/graphics/styles/codac2_py_ColorMap.cpp @@ -41,12 +41,17 @@ void export_ColorMap(py::module& m) .def_readonly_static("HAXBY", &ColorMap::HAXBY, CONST_COLORMAP_COLORMAP_HAXBY) + .def_readonly_static("DEFAULT", &ColorMap::DEFAULT, + CONST_COLORMAP_COLORMAP_DEFAULT) + .def_readonly_static("BLUE_TUBE", &ColorMap::BLUE_TUBE, CONST_COLORMAP_COLORMAP_BLUE_TUBE) .def_readonly_static("RED_TUBE", &ColorMap::RED_TUBE, CONST_COLORMAP_COLORMAP_RED_TUBE) + .def_readonly_static("RAINBOW", &ColorMap::RAINBOW, + CONST_COLORMAP_COLORMAP_RAINBOW) ; } \ No newline at end of file diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt index 533e3562..c18ba4b8 100644 --- a/src/graphics/CMakeLists.txt +++ b/src/graphics/CMakeLists.txt @@ -22,8 +22,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_Color.cpp ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_Color.h - # ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.cpp - # ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.h + ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_ColorMap.h ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_StyleProperties.cpp ${CMAKE_CURRENT_SOURCE_DIR}/styles/codac2_StyleProperties.h ) diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index f643f0d4..00892b65 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -62,9 +62,12 @@ Color::Color(float x1, float x2, float x3, float alpha,InterpolMode interpol_mod } Color::Color(int x1, int x2, int x3, int alpha,InterpolMode interpol_mode) - : Color((float)(x1/255.), (float)(x2/255.), (float)(x3/255.), (float)(alpha/255.),interpol_mode) { assert(x1 >= 0 && x1 <= 255 && x2 >= 0 && x2 <= 255 && x3 >= 0 && x3 <= 255 && alpha >= 0 && alpha <= 255); + if (interpol_mode == InterpolMode::RGB) + data = DataRGB{(float)x1/255., (float)x2/255., (float)x3/255., (float)alpha/255.}; + else + data = DataHSV{(float)x1/360., (float)x2/100., (float)x3/100., (float)alpha/100.}; } Color::Color(const std::string& hex_str) diff --git a/src/graphics/styles/codac2_ColorMap.cpp b/src/graphics/styles/codac2_ColorMap.cpp index 42ea0410..2b729b9d 100644 --- a/src/graphics/styles/codac2_ColorMap.cpp +++ b/src/graphics/styles/codac2_ColorMap.cpp @@ -41,10 +41,10 @@ Color ColorMap::color(float r) const float local_ratio = (real_index - prev(it_ub)->first) / (it_ub->first - prev(it_ub)->first); - return Color((float)(color_lb.r + (color_ub.r - color_lb.r) * local_ratio), - (float)(color_lb.g + (color_ub.g - color_lb.g) * local_ratio), - (float)(color_lb.b + (color_ub.b - color_lb.b) * local_ratio), - (float)(color_lb.alpha + (color_ub.alpha - color_lb.alpha) * local_ratio)); + return Color((float)(color_lb.r() + (color_ub.r() - color_lb.r()) * local_ratio), + (float)(color_lb.g() + (color_ub.g() - color_lb.g()) * local_ratio), + (float)(color_lb.b() + (color_ub.b() - color_lb.b()) * local_ratio), + (float)(color_lb.alpha() + (color_ub.alpha() - color_lb.alpha()) * local_ratio)); } @@ -76,6 +76,46 @@ ColorMap make_haxby() const ColorMap ColorMap::HAXBY = make_haxby(); +ColorMap make_default() + { + ColorMap map; + map.add_color_point(Color(10,0,121), 0); + map.add_color_point(Color(40,0,150), 1); + map.add_color_point(Color(20,5,175), 2); + map.add_color_point(Color(0,10,200), 3); + map.add_color_point(Color(0,25,212), 4); + map.add_color_point(Color(0,40,224), 5); + map.add_color_point(Color(26,102,240), 6); + map.add_color_point(Color(13,129,248), 7); + map.add_color_point(Color(25,175,255), 8); + map.add_color_point(Color(50,190,255), 9); + map.add_color_point(Color(68,202,255), 10); + map.add_color_point(Color(97,225,240), 11); + map.add_color_point(Color(106,235,225), 12); + map.add_color_point(Color(124,235,200), 13); + map.add_color_point(Color(138,236,174), 14); + map.add_color_point(Color(172,245,168), 15); + map.add_color_point(Color(205,255,162), 16); + map.add_color_point(Color(223,245,141), 17); + map.add_color_point(Color(240,236,121), 18); + map.add_color_point(Color(247,215,104), 19); + map.add_color_point(Color(255,189,87), 20); + map.add_color_point(Color(255,160,69), 21); + map.add_color_point(Color(244,117,75), 22); + map.add_color_point(Color(238,80,78), 23); + map.add_color_point(Color(255,90,90), 24); + map.add_color_point(Color(255,124,124), 25); + map.add_color_point(Color(255,158,158), 26); + map.add_color_point(Color(245,179,174), 27); + map.add_color_point(Color(255,196,196), 28); + map.add_color_point(Color(255,215,215), 29); + map.add_color_point(Color(255,235,235), 31); + map.add_color_point(Color(255,254,253), 32); + return map; + } + + const ColorMap ColorMap::DEFAULT = make_default(); + ColorMap make_blue_tube() { ColorMap map; @@ -94,4 +134,14 @@ ColorMap make_red_tube() return map; } -const ColorMap ColorMap::RED_TUBE = make_red_tube(); \ No newline at end of file +const ColorMap ColorMap::RED_TUBE = make_red_tube(); + +ColorMap make_rainbow() + { + ColorMap map; + for(int h = 300 ; h > 0 ; h-=10) + map.add_color_point(Color(h,100,100,100,InterpolMode::HSV), (300.-h)/300.); + return map; + } + + const ColorMap ColorMap::RAINBOW = make_rainbow(); \ No newline at end of file diff --git a/src/graphics/styles/codac2_ColorMap.h b/src/graphics/styles/codac2_ColorMap.h index e11f2d0a..36d44cd6 100644 --- a/src/graphics/styles/codac2_ColorMap.h +++ b/src/graphics/styles/codac2_ColorMap.h @@ -32,8 +32,10 @@ namespace codac2 Color color (float r) const; - static const ColorMap HAXBY; - static const ColorMap BLUE_TUBE; - static const ColorMap RED_TUBE; + static const ColorMap HAXBY; //!< predefined HAXBY color map (mainly used for DEM) + static const ColorMap DEFAULT; //!< a predefined default color map + static const ColorMap BLUE_TUBE; //!< a predefined color map for tubes + static const ColorMap RED_TUBE; //!< a predefined color map for tubes + static const ColorMap RAINBOW; //!< a predefined color map }; } \ No newline at end of file From 01662b767bd1630edda927bd73e2ec02734704c0 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Sat, 30 Nov 2024 10:58:38 +0100 Subject: [PATCH 079/102] [inv] updated doc --- src/core/matrices/codac2_Inversion.cpp | 11 ------ src/core/matrices/codac2_Inversion.h | 51 +++++++++++++++++--------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/core/matrices/codac2_Inversion.cpp b/src/core/matrices/codac2_Inversion.cpp index aa8044e4..568d68c2 100644 --- a/src/core/matrices/codac2_Inversion.cpp +++ b/src/core/matrices/codac2_Inversion.cpp @@ -16,11 +16,6 @@ using namespace std; namespace codac2 { - /** \brief Compute an upper bound of A+A^2+A^3 with A a matrix of intervals - * \param A matrix of intervals (supposed around 0) - * \param mrad the maximum radius of the result added (output argument, not available in Python) - * \return the enclosure. May include (-oo,oo) - */ IntervalMatrix infinite_sum_enclosure(const IntervalMatrix& A, double &mrad) { assert_release(A.is_squared()); Index N = A.rows(); @@ -70,12 +65,6 @@ namespace codac2 return res; } - - /** \brief Enclosure of the inverse of a matrix of intervals - * \param A matrix of intervals - * \return the enclosure. Can have (-oo,oo) coefficients if the - * inversion "failed" - */ IntervalMatrix inverse_enclosure(const IntervalMatrix &A) { assert_release(A.is_squared()); Index N=A.rows(); diff --git a/src/core/matrices/codac2_Inversion.h b/src/core/matrices/codac2_Inversion.h index de4bfa2f..eca2c2ba 100644 --- a/src/core/matrices/codac2_Inversion.h +++ b/src/core/matrices/codac2_Inversion.h @@ -17,35 +17,46 @@ namespace codac2 { enum LeftOrRightInv { LEFT_INV, RIGHT_INV }; - /** \brief Compute an upper bound of A+A^2+A^3 with A a matrix of intervals + /** \brief Compute an upper bound of A+A^2+A^3+..., with A a matrix of intervals * as an "error term" (use only bounds on coefficients) - * \param A matrix of intervals (supposed around 0) + * + * The function also returns mrad, which gives an idea of the “magnification” of + * the matrix during calculation (in particular, if mrad = oo, then the inversion + * calculation (e.g., performed by Eigen) has somehow failed and some coefficients + * of the output interval matrix are [-oo,+oo]). + * + * \pre A is a square matrix + * + * \param A a matrix of intervals (supposed around 0) * \param mrad the maximum radius of the result added (output argument) * \return the enclosure. May include (-oo,oo) */ IntervalMatrix infinite_sum_enclosure(const IntervalMatrix& A, double &mrad); /** \brief Correct the approximate inverse of a matrix + * + * \pre A and B are square matrices + * * \tparam O if LEFT_INV, use the inverse of BA (otherwise use the inverse of AB, * left inverse is normally better) - * \param A_ a matrix expression - * \param B_ a (almost punctual) approximation of its inverse, + * \param A a matrix expression + * \param B a (almost punctual) approximation of its inverse, * \return the enclosure */ template - inline IntervalMatrix inverse_correction(const Eigen::MatrixBase& A_, const Eigen::MatrixBase& B_) + inline IntervalMatrix inverse_correction(const Eigen::MatrixBase& A, const Eigen::MatrixBase& B) { - assert_release(A_.is_squared()); - assert_release(B_.is_squared()); + assert_release(A.is_squared()); + assert_release(B.is_squared()); - auto A = A_.template cast(); - auto B = B_.template cast(); + auto A_ = A.template cast(); + auto B_ = B.template cast(); - Index N = A.rows(); - assert_release(N==B.rows()); + Index N = A_.rows(); + assert_release(N==B_.rows()); auto Id = IntervalMatrix::Identity(N,N); - auto erMat = [&]() { if constexpr(O == LEFT_INV) return -B*A+Id; else return -A*B+Id; }(); + auto erMat = [&]() { if constexpr(O == LEFT_INV) return -B_*A_+Id; else return -A_*B_+Id; }(); double mrad=0.0; IntervalMatrix E = infinite_sum_enclosure(erMat,mrad); @@ -53,10 +64,10 @@ namespace codac2 /* one could use several iterations here, either using mrad, or directly */ - auto res = (O == LEFT_INV) ? IntervalMatrix(Ep*B) : IntervalMatrix(B*Ep); + auto res = (O == LEFT_INV) ? IntervalMatrix(Ep*B_) : IntervalMatrix(B_*Ep); - /* small problem with the matrix product : 0*oo = 0. We correct that - "by hand" (?) */ + // We want the presence of non-invertible matrices to + // result in coefficients of the form [-oo,+oo]. if (mrad==oo) { for (Index c=0;c Date: Sun, 1 Dec 2024 14:52:02 +0100 Subject: [PATCH 080/102] [doc] empty new manual --- doc/CMakeLists.txt | 49 +++++++++++++++++++ doc/manual/_static/empty.txt | 0 doc/manual/_templates/empty.txt | 0 doc/manual/conf.py.in | 35 +++++++++++++ doc/manual/index.rst | 9 ++++ doc/manual/tmp/empty.txt | 0 .../tutorial-set4most/01-examples/index.rst | 0 .../01-examples/range-only-loc.py | 0 .../doc/tutorial-set4most/01-examples/slam.py | 0 .../01-examples/triskelion.py | 0 .../01-examples/walls-loc.py | 0 .../doc}/doc/tutorial-set4most/index.rst | 0 scripts/CMakeModules/FindSphinx.cmake | 20 ++++++++ 13 files changed, 113 insertions(+) create mode 100644 doc/manual/_static/empty.txt create mode 100644 doc/manual/_templates/empty.txt create mode 100644 doc/manual/conf.py.in create mode 100644 doc/manual/index.rst create mode 100644 doc/manual/tmp/empty.txt rename {doc => prev_versions/v1.5.2/doc}/doc/tutorial-set4most/01-examples/index.rst (100%) rename {doc => prev_versions/v1.5.2/doc}/doc/tutorial-set4most/01-examples/range-only-loc.py (100%) rename {doc => prev_versions/v1.5.2/doc}/doc/tutorial-set4most/01-examples/slam.py (100%) rename {doc => prev_versions/v1.5.2/doc}/doc/tutorial-set4most/01-examples/triskelion.py (100%) rename {doc => prev_versions/v1.5.2/doc}/doc/tutorial-set4most/01-examples/walls-loc.py (100%) rename {doc => prev_versions/v1.5.2/doc}/doc/tutorial-set4most/index.rst (100%) create mode 100644 scripts/CMakeModules/FindSphinx.cmake diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index a305e855..ee4626e4 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -52,4 +52,53 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mathjax_stmaryrd.js endif() + endif() + +# User manual (Sphinx) + + find_package(Sphinx) + + if(NOT SPHINX_FOUND) + + message(STATUS "Sphinx not found, will not be able to generate the manual.") + + else() + + # Includes CMake commands in config file: + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/manual/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/manual/conf.py) + + set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/manual) + set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/manual) + + # Copying _static files of Sphinx to build directories + foreach(static_file ${CMAKE_CURRENT_SOURCE_DIR}/manual/_static/) + file(COPY ${static_file} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/manual/_static/) + endforeach() + + # Copying tmp files + foreach(static_file ${CMAKE_CURRENT_SOURCE_DIR}/manual/tmp/) + file(COPY ${static_file} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/manual/tmp/) + endforeach() + + # todo: the SPHINX_EXECUTABLE is already set by FindSphinx.cmake: + # check that it works without the following overload for Win and Linux: + if(WIN32) + set(SPHINX_EXECUTABLE "sphinx-build") + else() + set(SPHINX_EXECUTABLE "python3" "-msphinx") + endif() + + add_custom_target(manual + COMMAND + ${SPHINX_EXECUTABLE} -b html + # Specifying path to conf.py generated by CMake: + -c ${CMAKE_CURRENT_BINARY_DIR}/manual/ + ${SPHINX_SOURCE} ${SPHINX_BUILD} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating the manual website using Sphinx") + + install(DIRECTORY ${SPHINX_BUILD}/ + DESTINATION share/manual/${CMAKE_PROJECT_NAME} + OPTIONAL) + endif() \ No newline at end of file diff --git a/doc/manual/_static/empty.txt b/doc/manual/_static/empty.txt new file mode 100644 index 00000000..e69de29b diff --git a/doc/manual/_templates/empty.txt b/doc/manual/_templates/empty.txt new file mode 100644 index 00000000..e69de29b diff --git a/doc/manual/conf.py.in b/doc/manual/conf.py.in new file mode 100644 index 00000000..ff821a0e --- /dev/null +++ b/doc/manual/conf.py.in @@ -0,0 +1,35 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'Codac' +copyright = 'Codac Team' +author = 'Codac Team' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'sphinx_rtd_theme', +] + +templates_path = ['_templates'] +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_static_path = ['_static'] +html_theme = "sphinx_rtd_theme" +html_logo = "_static/logos/logo_codac.svg" + + +html_theme_options = { + 'logo_only': True, + 'display_version': True, +} \ No newline at end of file diff --git a/doc/manual/index.rst b/doc/manual/index.rst new file mode 100644 index 00000000..4aa0bdc9 --- /dev/null +++ b/doc/manual/index.rst @@ -0,0 +1,9 @@ +Codac manual +============ + + + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + diff --git a/doc/manual/tmp/empty.txt b/doc/manual/tmp/empty.txt new file mode 100644 index 00000000..e69de29b diff --git a/doc/doc/tutorial-set4most/01-examples/index.rst b/prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/index.rst similarity index 100% rename from doc/doc/tutorial-set4most/01-examples/index.rst rename to prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/index.rst diff --git a/doc/doc/tutorial-set4most/01-examples/range-only-loc.py b/prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/range-only-loc.py similarity index 100% rename from doc/doc/tutorial-set4most/01-examples/range-only-loc.py rename to prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/range-only-loc.py diff --git a/doc/doc/tutorial-set4most/01-examples/slam.py b/prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/slam.py similarity index 100% rename from doc/doc/tutorial-set4most/01-examples/slam.py rename to prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/slam.py diff --git a/doc/doc/tutorial-set4most/01-examples/triskelion.py b/prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/triskelion.py similarity index 100% rename from doc/doc/tutorial-set4most/01-examples/triskelion.py rename to prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/triskelion.py diff --git a/doc/doc/tutorial-set4most/01-examples/walls-loc.py b/prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/walls-loc.py similarity index 100% rename from doc/doc/tutorial-set4most/01-examples/walls-loc.py rename to prev_versions/v1.5.2/doc/doc/tutorial-set4most/01-examples/walls-loc.py diff --git a/doc/doc/tutorial-set4most/index.rst b/prev_versions/v1.5.2/doc/doc/tutorial-set4most/index.rst similarity index 100% rename from doc/doc/tutorial-set4most/index.rst rename to prev_versions/v1.5.2/doc/doc/tutorial-set4most/index.rst diff --git a/scripts/CMakeModules/FindSphinx.cmake b/scripts/CMakeModules/FindSphinx.cmake new file mode 100644 index 00000000..6190fa01 --- /dev/null +++ b/scripts/CMakeModules/FindSphinx.cmake @@ -0,0 +1,20 @@ +include(FindPackageHandleStandardArgs) + +# We are likely to find Sphinx near the Python interpreter +find_package(PythonInterp) +if(PYTHONINTERP_FOUND) + get_filename_component(_PYTHON_DIR "${PYTHON_EXECUTABLE}" DIRECTORY) + set( + _PYTHON_PATHS + "${_PYTHON_DIR}" + "${_PYTHON_DIR}/bin" + "${_PYTHON_DIR}/Scripts") +endif() + +find_program( + SPHINX_EXECUTABLE + NAMES sphinx-build sphinx-build.exe + HINTS ${_PYTHON_PATHS}) +mark_as_advanced(SPHINX_EXECUTABLE) + +find_package_handle_standard_args(Sphinx DEFAULT_MSG SPHINX_EXECUTABLE) \ No newline at end of file From ed288e5c96bb9b44c447ccac9f05629562ade6c4 Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 2 Dec 2024 21:27:08 +0100 Subject: [PATCH 081/102] [graphics] changed Color structure, added tests --- examples/00_graphics/CMakeCache.txt | 381 +++++++++ .../CMakeFiles/3.22.1/CMakeCCompiler.cmake | 72 ++ .../CMakeFiles/3.22.1/CMakeCXXCompiler.cmake | 83 ++ .../3.22.1/CMakeDetermineCompilerABI_C.bin | Bin 0 -> 15968 bytes .../3.22.1/CMakeDetermineCompilerABI_CXX.bin | Bin 0 -> 15992 bytes .../CMakeFiles/3.22.1/CMakeSystem.cmake | 15 + .../3.22.1/CompilerIdC/CMakeCCompilerId.c | 803 ++++++++++++++++++ .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 791 +++++++++++++++++ .../CMakeDirectoryInformation.cmake | 16 + .../00_graphics/CMakeFiles/Makefile.cmake | 121 +++ examples/00_graphics/CMakeFiles/Makefile2 | 86 ++ .../CMakeFiles/TargetDirectories.txt | 2 + .../00_graphics/CMakeFiles/cmake.check_cache | 1 + .../00_graphics/CMakeFiles/progress.marks | 1 + examples/00_graphics/Makefile | 140 +++ examples/00_graphics/cmake_install.cmake | 54 ++ .../src/graphics/styles/codac2_py_Color.cpp | 77 +- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 22 +- src/graphics/styles/codac2_Color.cpp | 253 +++--- src/graphics/styles/codac2_Color.h | 59 +- src/graphics/styles/codac2_ColorMap.cpp | 14 +- .../styles/codac2_StyleProperties.cpp | 6 +- tests/CMakeLists.txt | 2 + tests/graphics/styles/codac2_tests_Color.cpp | 307 +++++++ tests/graphics/styles/codac2_tests_Color.py | 184 ++++ 25 files changed, 3314 insertions(+), 176 deletions(-) create mode 100644 examples/00_graphics/CMakeCache.txt create mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CMakeCCompiler.cmake create mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake create mode 100755 examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_C.bin create mode 100755 examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_CXX.bin create mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CMakeSystem.cmake create mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CompilerIdC/CMakeCCompilerId.c create mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp create mode 100644 examples/00_graphics/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 examples/00_graphics/CMakeFiles/Makefile.cmake create mode 100644 examples/00_graphics/CMakeFiles/Makefile2 create mode 100644 examples/00_graphics/CMakeFiles/TargetDirectories.txt create mode 100644 examples/00_graphics/CMakeFiles/cmake.check_cache create mode 100644 examples/00_graphics/CMakeFiles/progress.marks create mode 100644 examples/00_graphics/Makefile create mode 100644 examples/00_graphics/cmake_install.cmake create mode 100644 tests/graphics/styles/codac2_tests_Color.cpp create mode 100644 tests/graphics/styles/codac2_tests_Color.py diff --git a/examples/00_graphics/CMakeCache.txt b/examples/00_graphics/CMakeCache.txt new file mode 100644 index 00000000..e13e7fa5 --- /dev/null +++ b/examples/00_graphics/CMakeCache.txt @@ -0,0 +1,381 @@ +# This is the CMakeCache file. +# For build in directory: /home/neo/codac/examples/00_graphics +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//No help, variable specified on the command line. +BUILD_TESTS:UNINITIALIZED=ON + +//Path to a program. +CMAKE_ADDR2LINE:FILEPATH=/usr/bin/addr2line + +//Path to a program. +CMAKE_AR:FILEPATH=/usr/bin/ar + +//Choose the type of build, options are: None Debug Release RelWithDebInfo +// MinSizeRel ... +CMAKE_BUILD_TYPE:STRING=Release + +//Enable/Disable color output during build. +CMAKE_COLOR_MAKEFILE:BOOL=ON + +//CXX compiler +CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-11 + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-11 + +//Flags used by the CXX compiler during all build types. +CMAKE_CXX_FLAGS:STRING=-fPIC + +//Flags used by the CXX compiler during DEBUG builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=-g + +//Flags used by the CXX compiler during MINSIZEREL builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the CXX compiler during RELEASE builds. +CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the CXX compiler during RELWITHDEBINFO builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//C compiler +CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-11 + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-11 + +//Flags used by the C compiler during all build types. +CMAKE_C_FLAGS:STRING=-fPIC + +//Flags used by the C compiler during DEBUG builds. +CMAKE_C_FLAGS_DEBUG:STRING=-g + +//Flags used by the C compiler during MINSIZEREL builds. +CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the C compiler during RELEASE builds. +CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the C compiler during RELWITHDEBINFO builds. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//Path to a program. +CMAKE_DLLTOOL:FILEPATH=CMAKE_DLLTOOL-NOTFOUND + +//Flags used by the linker during all build types. +CMAKE_EXE_LINKER_FLAGS:STRING= + +//Flags used by the linker during DEBUG builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during MINSIZEREL builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during RELEASE builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during RELWITHDEBINFO builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Enable/Disable output of compile commands during generation. +CMAKE_EXPORT_COMPILE_COMMANDS:BOOL= + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=/home/neo/codac/build_install + +//Path to a program. +CMAKE_LINKER:FILEPATH=/usr/bin/ld + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/gmake + +//Flags used by the linker during the creation of modules during +// all build types. +CMAKE_MODULE_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of modules during +// DEBUG builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of modules during +// MINSIZEREL builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of modules during +// RELEASE builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of modules during +// RELWITHDEBINFO builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=/usr/bin/nm + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump + +//Value Computed by CMake +CMAKE_PROJECT_DESCRIPTION:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_HOMEPAGE_URL:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=Project + +//Path to a program. +CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib + +//Path to a program. +CMAKE_READELF:FILEPATH=/usr/bin/readelf + +//Flags used by the linker during the creation of shared libraries +// during all build types. +CMAKE_SHARED_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of shared libraries +// during DEBUG builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of shared libraries +// during MINSIZEREL builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELEASE builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELWITHDEBINFO builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Flags used by the linker during the creation of static libraries +// during all build types. +CMAKE_STATIC_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of static libraries +// during DEBUG builds. +CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of static libraries +// during MINSIZEREL builds. +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELEASE builds. +CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELWITHDEBINFO builds. +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_STRIP:FILEPATH=/usr/bin/strip + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//No help, variable specified on the command line. +FAST_RELEASE:UNINITIALIZED=1 + +//Value Computed by CMake +Project_BINARY_DIR:STATIC=/home/neo/codac/examples/00_graphics + +//Value Computed by CMake +Project_IS_TOP_LEVEL:STATIC=ON + +//Value Computed by CMake +Project_SOURCE_DIR:STATIC=/home/neo/codac/examples + +//No help, variable specified on the command line. +TEST_EXAMPLES:UNINITIALIZED=ON + +//No help, variable specified on the command line. +WITH_PYTHON:UNINITIALIZED=ON + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: CMAKE_ADDR2LINE +CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/home/neo/codac/examples/00_graphics +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=22 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=1 +//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//ADVANCED property for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR +CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB +CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_AR +CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB +CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_DLLTOOL +CMAKE_DLLTOOL-ADVANCED:INTERNAL=1 +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS +CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL= +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Unix Makefiles +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/home/neo/codac/examples +//Install .so files without execute permission. +CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 +//ADVANCED property for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_READELF +CMAKE_READELF-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.22 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS +CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG +CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE +CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//uname command +CMAKE_UNAME:INTERNAL=/usr/bin/uname +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 + diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CMakeCCompiler.cmake b/examples/00_graphics/CMakeFiles/3.22.1/CMakeCCompiler.cmake new file mode 100644 index 00000000..488ad375 --- /dev/null +++ b/examples/00_graphics/CMakeFiles/3.22.1/CMakeCCompiler.cmake @@ -0,0 +1,72 @@ +set(CMAKE_C_COMPILER "/usr/bin/cc") +set(CMAKE_C_COMPILER_ARG1 "") +set(CMAKE_C_COMPILER_ID "GNU") +set(CMAKE_C_COMPILER_VERSION "11.4.0") +set(CMAKE_C_COMPILER_VERSION_INTERNAL "") +set(CMAKE_C_COMPILER_WRAPPER "") +set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "17") +set(CMAKE_C_EXTENSIONS_COMPUTED_DEFAULT "ON") +set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert;c_std_17;c_std_23") +set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes") +set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros") +set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert") +set(CMAKE_C17_COMPILE_FEATURES "c_std_17") +set(CMAKE_C23_COMPILE_FEATURES "c_std_23") + +set(CMAKE_C_PLATFORM_ID "Linux") +set(CMAKE_C_SIMULATE_ID "") +set(CMAKE_C_COMPILER_FRONTEND_VARIANT "") +set(CMAKE_C_SIMULATE_VERSION "") + + + + +set(CMAKE_AR "/usr/bin/ar") +set(CMAKE_C_COMPILER_AR "/usr/bin/gcc-ar-11") +set(CMAKE_RANLIB "/usr/bin/ranlib") +set(CMAKE_C_COMPILER_RANLIB "/usr/bin/gcc-ranlib-11") +set(CMAKE_LINKER "/usr/bin/ld") +set(CMAKE_MT "") +set(CMAKE_COMPILER_IS_GNUCC 1) +set(CMAKE_C_COMPILER_LOADED 1) +set(CMAKE_C_COMPILER_WORKS TRUE) +set(CMAKE_C_ABI_COMPILED TRUE) + +set(CMAKE_C_COMPILER_ENV_VAR "CC") + +set(CMAKE_C_COMPILER_ID_RUN 1) +set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m) +set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) +set(CMAKE_C_LINKER_PREFERENCE 10) + +# Save compiler ABI information. +set(CMAKE_C_SIZEOF_DATA_PTR "8") +set(CMAKE_C_COMPILER_ABI "ELF") +set(CMAKE_C_BYTE_ORDER "LITTLE_ENDIAN") +set(CMAKE_C_LIBRARY_ARCHITECTURE "x86_64-linux-gnu") + +if(CMAKE_C_SIZEOF_DATA_PTR) + set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}") +endif() + +if(CMAKE_C_COMPILER_ABI) + set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}") +endif() + +if(CMAKE_C_LIBRARY_ARCHITECTURE) + set(CMAKE_LIBRARY_ARCHITECTURE "x86_64-linux-gnu") +endif() + +set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "") +if(CMAKE_C_CL_SHOWINCLUDES_PREFIX) + set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}") +endif() + + + + + +set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/11/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include") +set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "gcc;gcc_s;c;gcc;gcc_s") +set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/11;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib") +set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake b/examples/00_graphics/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake new file mode 100644 index 00000000..345e9307 --- /dev/null +++ b/examples/00_graphics/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake @@ -0,0 +1,83 @@ +set(CMAKE_CXX_COMPILER "/usr/bin/c++") +set(CMAKE_CXX_COMPILER_ARG1 "") +set(CMAKE_CXX_COMPILER_ID "GNU") +set(CMAKE_CXX_COMPILER_VERSION "11.4.0") +set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "") +set(CMAKE_CXX_COMPILER_WRAPPER "") +set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "17") +set(CMAKE_CXX_EXTENSIONS_COMPUTED_DEFAULT "ON") +set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20;cxx_std_23") +set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters") +set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates") +set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates") +set(CMAKE_CXX17_COMPILE_FEATURES "cxx_std_17") +set(CMAKE_CXX20_COMPILE_FEATURES "cxx_std_20") +set(CMAKE_CXX23_COMPILE_FEATURES "cxx_std_23") + +set(CMAKE_CXX_PLATFORM_ID "Linux") +set(CMAKE_CXX_SIMULATE_ID "") +set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "") +set(CMAKE_CXX_SIMULATE_VERSION "") + + + + +set(CMAKE_AR "/usr/bin/ar") +set(CMAKE_CXX_COMPILER_AR "/usr/bin/gcc-ar-11") +set(CMAKE_RANLIB "/usr/bin/ranlib") +set(CMAKE_CXX_COMPILER_RANLIB "/usr/bin/gcc-ranlib-11") +set(CMAKE_LINKER "/usr/bin/ld") +set(CMAKE_MT "") +set(CMAKE_COMPILER_IS_GNUCXX 1) +set(CMAKE_CXX_COMPILER_LOADED 1) +set(CMAKE_CXX_COMPILER_WORKS TRUE) +set(CMAKE_CXX_ABI_COMPILED TRUE) + +set(CMAKE_CXX_COMPILER_ENV_VAR "CXX") + +set(CMAKE_CXX_COMPILER_ID_RUN 1) +set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm) +set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) + +foreach (lang C OBJC OBJCXX) + if (CMAKE_${lang}_COMPILER_ID_RUN) + foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS) + list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension}) + endforeach() + endif() +endforeach() + +set(CMAKE_CXX_LINKER_PREFERENCE 30) +set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1) + +# Save compiler ABI information. +set(CMAKE_CXX_SIZEOF_DATA_PTR "8") +set(CMAKE_CXX_COMPILER_ABI "ELF") +set(CMAKE_CXX_BYTE_ORDER "LITTLE_ENDIAN") +set(CMAKE_CXX_LIBRARY_ARCHITECTURE "x86_64-linux-gnu") + +if(CMAKE_CXX_SIZEOF_DATA_PTR) + set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}") +endif() + +if(CMAKE_CXX_COMPILER_ABI) + set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}") +endif() + +if(CMAKE_CXX_LIBRARY_ARCHITECTURE) + set(CMAKE_LIBRARY_ARCHITECTURE "x86_64-linux-gnu") +endif() + +set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "") +if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX) + set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}") +endif() + + + + + +set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "/usr/include/c++/11;/usr/include/x86_64-linux-gnu/c++/11;/usr/include/c++/11/backward;/usr/lib/gcc/x86_64-linux-gnu/11/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include") +set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "stdc++;m;gcc_s;gcc;c;gcc_s;gcc") +set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/11;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib") +set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_C.bin b/examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_C.bin new file mode 100755 index 0000000000000000000000000000000000000000..a8dc0758bdd947d6c1b6426579ede08176cb0ecb GIT binary patch literal 15968 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 literal 0 HcmV?d00001 diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_CXX.bin b/examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_CXX.bin new file mode 100755 index 0000000000000000000000000000000000000000..cfa527b53452d63fe64b6a8e2d060ddc5e29a3a6 GIT binary patch literal 15992 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 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__WATCOMC__) +# define COMPILER_ID "OpenWatcom" + /* __WATCOMC__ = VVRP + 1100 */ +# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__SUNPRO_C) +# define COMPILER_ID "SunPro" +# if __SUNPRO_C >= 0x5100 + /* __SUNPRO_C = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) +# endif + +#elif defined(__HP_cc) +# define COMPILER_ID "HP" + /* __HP_cc = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_cc % 100) + +#elif defined(__DECC) +# define COMPILER_ID "Compaq" + /* __DECC_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECC_VER % 10000) + +#elif defined(__IBMC__) && defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) + +#elif defined(__ibmxl__) && defined(__clang__) +# define COMPILER_ID "XLClang" +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) + + +#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800 +# define COMPILER_ID "XL" + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) + +#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ < 800 +# define COMPILER_ID "VisualAge" + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) + +#elif defined(__NVCOMPILER) +# define COMPILER_ID "NVHPC" +# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__) +# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__) +# if defined(__NVCOMPILER_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__) +# endif + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__CLANG_FUJITSU) +# define COMPILER_ID "FujitsuClang" +# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) +# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) +# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) +# define COMPILER_VERSION_INTERNAL_STR __clang_version__ + + +#elif defined(__FUJITSU) +# define COMPILER_ID "Fujitsu" +# if defined(__FCC_version__) +# define COMPILER_VERSION __FCC_version__ +# elif defined(__FCC_major__) +# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) +# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) +# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) +# endif +# if defined(__fcc_version) +# define COMPILER_VERSION_INTERNAL DEC(__fcc_version) +# elif defined(__FCC_VERSION) +# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION) +# endif + + +#elif defined(__ghs__) +# define COMPILER_ID "GHS" +/* __GHS_VERSION_NUMBER = VVVVRP */ +# ifdef __GHS_VERSION_NUMBER +# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100) +# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10) +# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10) +# endif + +#elif defined(__TINYC__) +# define COMPILER_ID "TinyCC" + +#elif defined(__BCC__) +# define COMPILER_ID "Bruce" + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__ARMCC_VERSION) && !defined(__clang__) +# define COMPILER_ID "ARMCC" +#if __ARMCC_VERSION >= 1000000 + /* __ARMCC_VERSION = VRRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#else + /* __ARMCC_VERSION = VRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#endif + + +#elif defined(__clang__) && defined(__apple_build_version__) +# define COMPILER_ID "AppleClang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) + +#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION) +# define COMPILER_ID "ARMClang" + # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000) +# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION) + +#elif defined(__clang__) +# define COMPILER_ID "Clang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__GNUC__) +# define COMPILER_ID "GNU" +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# if defined(__GNUC_MINOR__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" +#if defined(__VISUALDSPVERSION__) + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) +#endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" +# if defined(__VER__) && defined(__ICCARM__) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) +# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) +# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__)) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100) +# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100)) +# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# endif + +#elif defined(__SDCC_VERSION_MAJOR) || defined(SDCC) +# define COMPILER_ID "SDCC" +# if defined(__SDCC_VERSION_MAJOR) +# define COMPILER_VERSION_MAJOR DEC(__SDCC_VERSION_MAJOR) +# define COMPILER_VERSION_MINOR DEC(__SDCC_VERSION_MINOR) +# define COMPILER_VERSION_PATCH DEC(__SDCC_VERSION_PATCH) +# else + /* SDCC = VRP */ +# define COMPILER_VERSION_MAJOR DEC(SDCC/100) +# define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10) +# define COMPILER_VERSION_PATCH DEC(SDCC % 10) +# endif + + +/* These compilers are either not known or too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) +char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; +#endif + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__MSYS__) +# define PLATFORM_ID "MSYS" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#elif defined(__WATCOMC__) +# if defined(__LINUX__) +# define PLATFORM_ID "Linux" + +# elif defined(__DOS__) +# define PLATFORM_ID "DOS" + +# elif defined(__OS2__) +# define PLATFORM_ID "OS2" + +# elif defined(__WINDOWS__) +# define PLATFORM_ID "Windows3x" + +# elif defined(__VXWORKS__) +# define PLATFORM_ID "VxWorks" + +# else /* unknown platform */ +# define PLATFORM_ID +# endif + +#elif defined(__INTEGRITY) +# if defined(INT_178B) +# define PLATFORM_ID "Integrity178" + +# else /* regular Integrity */ +# define PLATFORM_ID "Integrity" +# endif + +#else /* unknown platform */ +# define PLATFORM_ID + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_ARM64EC) +# define ARCHITECTURE_ID "ARM64EC" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM64) +# define ARCHITECTURE_ID "ARM64" + +# elif defined(_M_ARM) +# if _M_ARM == 4 +# define ARCHITECTURE_ID "ARMV4I" +# elif _M_ARM == 5 +# define ARCHITECTURE_ID "ARMV5I" +# else +# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) +# endif + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__WATCOMC__) +# if defined(_M_I86) +# define ARCHITECTURE_ID "I86" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# if defined(__ICCARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__ICCRX__) +# define ARCHITECTURE_ID "RX" + +# elif defined(__ICCRH850__) +# define ARCHITECTURE_ID "RH850" + +# elif defined(__ICCRL78__) +# define ARCHITECTURE_ID "RL78" + +# elif defined(__ICCRISCV__) +# define ARCHITECTURE_ID "RISCV" + +# elif defined(__ICCAVR__) +# define ARCHITECTURE_ID "AVR" + +# elif defined(__ICC430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__ICCV850__) +# define ARCHITECTURE_ID "V850" + +# elif defined(__ICC8051__) +# define ARCHITECTURE_ID "8051" + +# elif defined(__ICCSTM8__) +# define ARCHITECTURE_ID "STM8" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__ghs__) +# if defined(__PPC64__) +# define ARCHITECTURE_ID "PPC64" + +# elif defined(__ppc__) +# define ARCHITECTURE_ID "PPC" + +# elif defined(__ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__x86_64__) +# define ARCHITECTURE_ID "x64" + +# elif defined(__i386__) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__TI_COMPILER_VERSION__) +# if defined(__TI_ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__MSP430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__TMS320C28XX__) +# define ARCHITECTURE_ID "TMS320C28x" + +# elif defined(__TMS320C6X__) || defined(_TMS320C6X) +# define ARCHITECTURE_ID "TMS320C6x" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#else +# define ARCHITECTURE_ID +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number. */ +#ifdef COMPILER_VERSION +char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]"; + +/* Construct a string literal encoding the version number components. */ +#elif defined(COMPILER_VERSION_MAJOR) +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct a string literal encoding the internal version number. */ +#ifdef COMPILER_VERSION_INTERNAL +char const info_version_internal[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', + 'i','n','t','e','r','n','a','l','[', + COMPILER_VERSION_INTERNAL,']','\0'}; +#elif defined(COMPILER_VERSION_INTERNAL_STR) +char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]"; +#endif + +/* Construct a string literal encoding the version number components. */ +#ifdef SIMULATE_VERSION_MAJOR +char const info_simulate_version[] = { + 'I', 'N', 'F', 'O', ':', + 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', + SIMULATE_VERSION_MAJOR, +# ifdef SIMULATE_VERSION_MINOR + '.', SIMULATE_VERSION_MINOR, +# ifdef SIMULATE_VERSION_PATCH + '.', SIMULATE_VERSION_PATCH, +# ifdef SIMULATE_VERSION_TWEAK + '.', SIMULATE_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + +#if !defined(__STDC__) && !defined(__clang__) +# if defined(_MSC_VER) || defined(__ibmxl__) || defined(__IBMC__) +# define C_VERSION "90" +# else +# define C_VERSION +# endif +#elif __STDC_VERSION__ > 201710L +# define C_VERSION "23" +#elif __STDC_VERSION__ >= 201710L +# define C_VERSION "17" +#elif __STDC_VERSION__ >= 201000L +# define C_VERSION "11" +#elif __STDC_VERSION__ >= 199901L +# define C_VERSION "99" +#else +# define C_VERSION "90" +#endif +const char* info_language_standard_default = + "INFO" ":" "standard_default[" C_VERSION "]"; + +const char* info_language_extensions_default = "INFO" ":" "extensions_default[" +/* !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode. */ +#if (defined(__clang__) || defined(__GNUC__) || \ + defined(__TI_COMPILER_VERSION__)) && \ + !defined(__STRICT_ANSI__) && !defined(_MSC_VER) + "ON" +#else + "OFF" +#endif +"]"; + +/*--------------------------------------------------------------------------*/ + +#ifdef ID_VOID_MAIN +void main() {} +#else +# if defined(__CLASSIC_C__) +int main(argc, argv) int argc; char *argv[]; +# else +int main(int argc, char* argv[]) +# endif +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; + require += info_arch[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif +#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) + require += info_cray[argc]; +#endif + require += info_language_standard_default[argc]; + require += info_language_extensions_default[argc]; + (void)argv; + return require; +} +#endif diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp b/examples/00_graphics/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp new file mode 100644 index 00000000..25c62a8c --- /dev/null +++ b/examples/00_graphics/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp @@ -0,0 +1,791 @@ +/* This source file must have a .cpp extension so that all C++ compilers + recognize the extension without flags. Borland does not know .cxx for + example. */ +#ifndef __cplusplus +# error "A C compiler has been selected for C++." +#endif + +#if !defined(__has_include) +/* If the compiler does not have __has_include, pretend the answer is + always no. */ +# define __has_include(x) 0 +#endif + + +/* Version number components: V=Version, R=Revision, P=Patch + Version date components: YYYY=Year, MM=Month, DD=Day */ + +#if defined(__COMO__) +# define COMPILER_ID "Comeau" + /* __COMO_VERSION__ = VRR */ +# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100) +# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100) + +#elif defined(__INTEL_COMPILER) || defined(__ICC) +# define COMPILER_ID "Intel" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# if defined(__GNUC__) +# define SIMULATE_ID "GNU" +# endif + /* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later, + except that a few beta releases use the old format with V=2021. */ +# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111 +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) +# if defined(__INTEL_COMPILER_UPDATE) +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) +# else +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) +# endif +# else +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE) + /* The third version component from --version is an update index, + but no macro is provided for it. */ +# define COMPILER_VERSION_PATCH DEC(0) +# endif +# if defined(__INTEL_COMPILER_BUILD_DATE) + /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ +# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) +# endif +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# if defined(__GNUC__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) +# elif defined(__GNUG__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER) +# define COMPILER_ID "IntelLLVM" +#if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +#endif +#if defined(__GNUC__) +# define SIMULATE_ID "GNU" +#endif +/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and + * later. Look for 6 digit vs. 8 digit version number to decide encoding. + * VVVV is no smaller than the current year when a version is released. + */ +#if __INTEL_LLVM_COMPILER < 1000000L +# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 10) +#else +# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000) +# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 100) +#endif +#if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +#endif +#if defined(__GNUC__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) +#elif defined(__GNUG__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) +#endif +#if defined(__GNUC_MINOR__) +# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) +#endif +#if defined(__GNUC_PATCHLEVEL__) +# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +#endif + +#elif defined(__PATHCC__) +# define COMPILER_ID "PathScale" +# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) +# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) +# if defined(__PATHCC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) +# endif + +#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) +# define COMPILER_ID "Embarcadero" +# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__WATCOMC__) +# define COMPILER_ID "OpenWatcom" + /* __WATCOMC__ = VVRP + 1100 */ +# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__SUNPRO_CC) +# define COMPILER_ID "SunPro" +# if __SUNPRO_CC >= 0x5100 + /* __SUNPRO_CC = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# endif + +#elif defined(__HP_aCC) +# define COMPILER_ID "HP" + /* __HP_aCC = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) + +#elif defined(__DECCXX) +# define COMPILER_ID "Compaq" + /* __DECCXX_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) + +#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__ibmxl__) && defined(__clang__) +# define COMPILER_ID "XLClang" +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) + + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800 +# define COMPILER_ID "XL" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800 +# define COMPILER_ID "VisualAge" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__NVCOMPILER) +# define COMPILER_ID "NVHPC" +# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__) +# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__) +# if defined(__NVCOMPILER_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__) +# endif + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__CLANG_FUJITSU) +# define COMPILER_ID "FujitsuClang" +# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) +# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) +# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) +# define COMPILER_VERSION_INTERNAL_STR __clang_version__ + + +#elif defined(__FUJITSU) +# define COMPILER_ID "Fujitsu" +# if defined(__FCC_version__) +# define COMPILER_VERSION __FCC_version__ +# elif defined(__FCC_major__) +# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) +# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) +# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) +# endif +# if defined(__fcc_version) +# define COMPILER_VERSION_INTERNAL DEC(__fcc_version) +# elif defined(__FCC_VERSION) +# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION) +# endif + + +#elif defined(__ghs__) +# define COMPILER_ID "GHS" +/* __GHS_VERSION_NUMBER = VVVVRP */ +# ifdef __GHS_VERSION_NUMBER +# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100) +# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10) +# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10) +# endif + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__ARMCC_VERSION) && !defined(__clang__) +# define COMPILER_ID "ARMCC" +#if __ARMCC_VERSION >= 1000000 + /* __ARMCC_VERSION = VRRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#else + /* __ARMCC_VERSION = VRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#endif + + +#elif defined(__clang__) && defined(__apple_build_version__) +# define COMPILER_ID "AppleClang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) + +#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION) +# define COMPILER_ID "ARMClang" + # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000) +# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION) + +#elif defined(__clang__) +# define COMPILER_ID "Clang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__GNUC__) || defined(__GNUG__) +# define COMPILER_ID "GNU" +# if defined(__GNUC__) +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# else +# define COMPILER_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" +#if defined(__VISUALDSPVERSION__) + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) +#endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" +# if defined(__VER__) && defined(__ICCARM__) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) +# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) +# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__)) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100) +# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100)) +# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# endif + + +/* These compilers are either not known or too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) +char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; +#endif + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__MSYS__) +# define PLATFORM_ID "MSYS" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#elif defined(__WATCOMC__) +# if defined(__LINUX__) +# define PLATFORM_ID "Linux" + +# elif defined(__DOS__) +# define PLATFORM_ID "DOS" + +# elif defined(__OS2__) +# define PLATFORM_ID "OS2" + +# elif defined(__WINDOWS__) +# define PLATFORM_ID "Windows3x" + +# elif defined(__VXWORKS__) +# define PLATFORM_ID "VxWorks" + +# else /* unknown platform */ +# define PLATFORM_ID +# endif + +#elif defined(__INTEGRITY) +# if defined(INT_178B) +# define PLATFORM_ID "Integrity178" + +# else /* regular Integrity */ +# define PLATFORM_ID "Integrity" +# endif + +#else /* unknown platform */ +# define PLATFORM_ID + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_ARM64EC) +# define ARCHITECTURE_ID "ARM64EC" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM64) +# define ARCHITECTURE_ID "ARM64" + +# elif defined(_M_ARM) +# if _M_ARM == 4 +# define ARCHITECTURE_ID "ARMV4I" +# elif _M_ARM == 5 +# define ARCHITECTURE_ID "ARMV5I" +# else +# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) +# endif + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__WATCOMC__) +# if defined(_M_I86) +# define ARCHITECTURE_ID "I86" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# if defined(__ICCARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__ICCRX__) +# define ARCHITECTURE_ID "RX" + +# elif defined(__ICCRH850__) +# define ARCHITECTURE_ID "RH850" + +# elif defined(__ICCRL78__) +# define ARCHITECTURE_ID "RL78" + +# elif defined(__ICCRISCV__) +# define ARCHITECTURE_ID "RISCV" + +# elif defined(__ICCAVR__) +# define ARCHITECTURE_ID "AVR" + +# elif defined(__ICC430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__ICCV850__) +# define ARCHITECTURE_ID "V850" + +# elif defined(__ICC8051__) +# define ARCHITECTURE_ID "8051" + +# elif defined(__ICCSTM8__) +# define ARCHITECTURE_ID "STM8" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__ghs__) +# if defined(__PPC64__) +# define ARCHITECTURE_ID "PPC64" + +# elif defined(__ppc__) +# define ARCHITECTURE_ID "PPC" + +# elif defined(__ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__x86_64__) +# define ARCHITECTURE_ID "x64" + +# elif defined(__i386__) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__TI_COMPILER_VERSION__) +# if defined(__TI_ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__MSP430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__TMS320C28XX__) +# define ARCHITECTURE_ID "TMS320C28x" + +# elif defined(__TMS320C6X__) || defined(_TMS320C6X) +# define ARCHITECTURE_ID "TMS320C6x" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#else +# define ARCHITECTURE_ID +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number. */ +#ifdef COMPILER_VERSION +char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]"; + +/* Construct a string literal encoding the version number components. */ +#elif defined(COMPILER_VERSION_MAJOR) +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct a string literal encoding the internal version number. */ +#ifdef COMPILER_VERSION_INTERNAL +char const info_version_internal[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', + 'i','n','t','e','r','n','a','l','[', + COMPILER_VERSION_INTERNAL,']','\0'}; +#elif defined(COMPILER_VERSION_INTERNAL_STR) +char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]"; +#endif + +/* Construct a string literal encoding the version number components. */ +#ifdef SIMULATE_VERSION_MAJOR +char const info_simulate_version[] = { + 'I', 'N', 'F', 'O', ':', + 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', + SIMULATE_VERSION_MAJOR, +# ifdef SIMULATE_VERSION_MINOR + '.', SIMULATE_VERSION_MINOR, +# ifdef SIMULATE_VERSION_PATCH + '.', SIMULATE_VERSION_PATCH, +# ifdef SIMULATE_VERSION_TWEAK + '.', SIMULATE_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + +#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L +# if defined(__INTEL_CXX11_MODE__) +# if defined(__cpp_aggregate_nsdmi) +# define CXX_STD 201402L +# else +# define CXX_STD 201103L +# endif +# else +# define CXX_STD 199711L +# endif +#elif defined(_MSC_VER) && defined(_MSVC_LANG) +# define CXX_STD _MSVC_LANG +#else +# define CXX_STD __cplusplus +#endif + +const char* info_language_standard_default = "INFO" ":" "standard_default[" +#if CXX_STD > 202002L + "23" +#elif CXX_STD > 201703L + "20" +#elif CXX_STD >= 201703L + "17" +#elif CXX_STD >= 201402L + "14" +#elif CXX_STD >= 201103L + "11" +#else + "98" +#endif +"]"; + +const char* info_language_extensions_default = "INFO" ":" "extensions_default[" +/* !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode. */ +#if (defined(__clang__) || defined(__GNUC__) || \ + defined(__TI_COMPILER_VERSION__)) && \ + !defined(__STRICT_ANSI__) && !defined(_MSC_VER) + "ON" +#else + "OFF" +#endif +"]"; + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif +#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) + require += info_cray[argc]; +#endif + require += info_language_standard_default[argc]; + require += info_language_extensions_default[argc]; + (void)argv; + return require; +} diff --git a/examples/00_graphics/CMakeFiles/CMakeDirectoryInformation.cmake b/examples/00_graphics/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 00000000..c92a10b9 --- /dev/null +++ b/examples/00_graphics/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.22 + +# Relative path conversion top directories. +set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/neo/codac/examples") +set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/neo/codac/examples/00_graphics") + +# Force unix paths in dependencies. +set(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/examples/00_graphics/CMakeFiles/Makefile.cmake b/examples/00_graphics/CMakeFiles/Makefile.cmake new file mode 100644 index 00000000..fbd61b2d --- /dev/null +++ b/examples/00_graphics/CMakeFiles/Makefile.cmake @@ -0,0 +1,121 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.22 + +# The generator used is: +set(CMAKE_DEPENDS_GENERATOR "Unix Makefiles") + +# The top level Makefile was generated from the following files: +set(CMAKE_MAKEFILE_DEPENDS + "CMakeCache.txt" + "CMakeFiles/3.22.1/CMakeCCompiler.cmake" + "CMakeFiles/3.22.1/CMakeCXXCompiler.cmake" + "CMakeFiles/3.22.1/CMakeSystem.cmake" + "../CMakeLists.txt" + "/usr/share/cmake-3.22/Modules/CMakeCCompiler.cmake.in" + "/usr/share/cmake-3.22/Modules/CMakeCCompilerABI.c" + "/usr/share/cmake-3.22/Modules/CMakeCInformation.cmake" + "/usr/share/cmake-3.22/Modules/CMakeCXXCompiler.cmake.in" + "/usr/share/cmake-3.22/Modules/CMakeCXXCompilerABI.cpp" + "/usr/share/cmake-3.22/Modules/CMakeCXXInformation.cmake" + "/usr/share/cmake-3.22/Modules/CMakeCommonLanguageInclude.cmake" + "/usr/share/cmake-3.22/Modules/CMakeCompilerIdDetection.cmake" + "/usr/share/cmake-3.22/Modules/CMakeDetermineCCompiler.cmake" + "/usr/share/cmake-3.22/Modules/CMakeDetermineCXXCompiler.cmake" + "/usr/share/cmake-3.22/Modules/CMakeDetermineCompileFeatures.cmake" + "/usr/share/cmake-3.22/Modules/CMakeDetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/CMakeDetermineCompilerABI.cmake" + "/usr/share/cmake-3.22/Modules/CMakeDetermineCompilerId.cmake" + "/usr/share/cmake-3.22/Modules/CMakeDetermineSystem.cmake" + "/usr/share/cmake-3.22/Modules/CMakeFindBinUtils.cmake" + "/usr/share/cmake-3.22/Modules/CMakeGenericSystem.cmake" + "/usr/share/cmake-3.22/Modules/CMakeInitializeConfigs.cmake" + "/usr/share/cmake-3.22/Modules/CMakeLanguageInformation.cmake" + "/usr/share/cmake-3.22/Modules/CMakeParseImplicitIncludeInfo.cmake" + "/usr/share/cmake-3.22/Modules/CMakeParseImplicitLinkInfo.cmake" + "/usr/share/cmake-3.22/Modules/CMakeParseLibraryArchitecture.cmake" + "/usr/share/cmake-3.22/Modules/CMakeSystem.cmake.in" + "/usr/share/cmake-3.22/Modules/CMakeSystemSpecificInformation.cmake" + "/usr/share/cmake-3.22/Modules/CMakeSystemSpecificInitialize.cmake" + "/usr/share/cmake-3.22/Modules/CMakeTestCCompiler.cmake" + "/usr/share/cmake-3.22/Modules/CMakeTestCXXCompiler.cmake" + "/usr/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake" + "/usr/share/cmake-3.22/Modules/CMakeUnixFindMake.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/ADSP-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/ARMCC-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/ARMClang-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/AppleClang-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Borland-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Bruce-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/CMakeCommonCompilerMacros.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Comeau-CXX-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Compaq-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Cray-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Embarcadero-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Fujitsu-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/GHS-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/GNU-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/GNU-C.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/GNU-CXX.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/GNU-FindBinUtils.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/GNU.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/HP-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/HP-CXX-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/IAR-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Intel-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/MSVC-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/NVHPC-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/NVIDIA-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/PGI-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/PathScale-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/SCO-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/SDCC-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/SunPro-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/TI-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/Watcom-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/XL-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/XL-CXX-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/XLClang-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/zOS-C-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake" + "/usr/share/cmake-3.22/Modules/Internal/FeatureTesting.cmake" + "/usr/share/cmake-3.22/Modules/Platform/Linux-Determine-CXX.cmake" + "/usr/share/cmake-3.22/Modules/Platform/Linux-GNU-C.cmake" + "/usr/share/cmake-3.22/Modules/Platform/Linux-GNU-CXX.cmake" + "/usr/share/cmake-3.22/Modules/Platform/Linux-GNU.cmake" + "/usr/share/cmake-3.22/Modules/Platform/Linux.cmake" + "/usr/share/cmake-3.22/Modules/Platform/UnixPaths.cmake" + ) + +# The corresponding makefile is: +set(CMAKE_MAKEFILE_OUTPUTS + "Makefile" + "CMakeFiles/cmake.check_cache" + ) + +# Byproducts of CMake generate step: +set(CMAKE_MAKEFILE_PRODUCTS + "CMakeFiles/3.22.1/CMakeSystem.cmake" + "CMakeFiles/3.22.1/CMakeCCompiler.cmake" + "CMakeFiles/3.22.1/CMakeCXXCompiler.cmake" + "CMakeFiles/3.22.1/CMakeCCompiler.cmake" + "CMakeFiles/3.22.1/CMakeCXXCompiler.cmake" + "CMakeFiles/CMakeDirectoryInformation.cmake" + ) + +# Dependency information for all targets: +set(CMAKE_DEPEND_INFO_FILES + ) diff --git a/examples/00_graphics/CMakeFiles/Makefile2 b/examples/00_graphics/CMakeFiles/Makefile2 new file mode 100644 index 00000000..51210666 --- /dev/null +++ b/examples/00_graphics/CMakeFiles/Makefile2 @@ -0,0 +1,86 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.22 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/neo/codac/examples + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/neo/codac/examples/00_graphics + +#============================================================================= +# Directory level rules for the build root directory + +# The main recursive "all" target. +all: +.PHONY : all + +# The main recursive "preinstall" target. +preinstall: +.PHONY : preinstall + +# The main recursive "clean" target. +clean: +.PHONY : clean + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/examples/00_graphics/CMakeFiles/TargetDirectories.txt b/examples/00_graphics/CMakeFiles/TargetDirectories.txt new file mode 100644 index 00000000..68996981 --- /dev/null +++ b/examples/00_graphics/CMakeFiles/TargetDirectories.txt @@ -0,0 +1,2 @@ +/home/neo/codac/examples/00_graphics/CMakeFiles/edit_cache.dir +/home/neo/codac/examples/00_graphics/CMakeFiles/rebuild_cache.dir diff --git a/examples/00_graphics/CMakeFiles/cmake.check_cache b/examples/00_graphics/CMakeFiles/cmake.check_cache new file mode 100644 index 00000000..3dccd731 --- /dev/null +++ b/examples/00_graphics/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/examples/00_graphics/CMakeFiles/progress.marks b/examples/00_graphics/CMakeFiles/progress.marks new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/examples/00_graphics/CMakeFiles/progress.marks @@ -0,0 +1 @@ +0 diff --git a/examples/00_graphics/Makefile b/examples/00_graphics/Makefile new file mode 100644 index 00000000..093c9a05 --- /dev/null +++ b/examples/00_graphics/Makefile @@ -0,0 +1,140 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.22 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/neo/codac/examples + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/neo/codac/examples/00_graphics + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/neo/codac/examples/00_graphics/CMakeFiles /home/neo/codac/examples/00_graphics//CMakeFiles/progress.marks + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /home/neo/codac/examples/00_graphics/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... rebuild_cache" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/examples/00_graphics/cmake_install.cmake b/examples/00_graphics/cmake_install.cmake new file mode 100644 index 00000000..92777670 --- /dev/null +++ b/examples/00_graphics/cmake_install.cmake @@ -0,0 +1,54 @@ +# Install script for directory: /home/neo/codac/examples + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/home/neo/codac/build_install") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "Release") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Install shared libraries without execute permission? +if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + set(CMAKE_INSTALL_SO_NO_EXE "1") +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +# Set default install directory permissions. +if(NOT DEFINED CMAKE_OBJDUMP) + set(CMAKE_OBJDUMP "/usr/bin/objdump") +endif() + +if(CMAKE_INSTALL_COMPONENT) + set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt") +else() + set(CMAKE_INSTALL_MANIFEST "install_manifest.txt") +endif() + +string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT + "${CMAKE_INSTALL_MANIFEST_FILES}") +file(WRITE "/home/neo/codac/examples/00_graphics/${CMAKE_INSTALL_MANIFEST}" + "${CMAKE_INSTALL_MANIFEST_CONTENT}") diff --git a/python/src/graphics/styles/codac2_py_Color.cpp b/python/src/graphics/styles/codac2_py_Color.cpp index b744bd0f..2ff64ecc 100644 --- a/python/src/graphics/styles/codac2_py_Color.cpp +++ b/python/src/graphics/styles/codac2_py_Color.cpp @@ -27,62 +27,77 @@ void export_Color(py::module& m) .value("HSV", InterpolMode::HSV) ; - py::class_ exported_data_rgb(m, "DataRGB", DATARGB_MAIN); - exported_data_rgb - .def_readwrite("r", &DataRGB::r) - .def_readwrite("g", &DataRGB::g) - .def_readwrite("b", &DataRGB::b) - .def_readwrite("a", &DataRGB::a) - .def("to_hex_str", &DataRGB::to_hex_str, STRING_DATARGB_TO_HEX_STR_CONST) - ; - - py::class_ exported_data_hsv(m, "DataHSV", DATAHSV_MAIN); - exported_data_hsv - .def_readwrite("h", &DataHSV::h) - .def_readwrite("s", &DataHSV::s) - .def_readwrite("v", &DataHSV::v) - .def_readwrite("a", &DataHSV::a) - .def("to_rgb", &DataHSV::to_rgb, DATARGB_DATAHSV_TO_RGB_CONST) - .def("to_hex_str", &DataHSV::to_hex_str, STRING_DATAHSV_TO_HEX_STR_CONST) - ; - - py::class_ exported_color(m, "Color", COLOR_MAIN); exported_color .def_readwrite("data", &Color::data, - VARIANT_STRINGDATARGBDATAHSV_COLOR_DATA) + ARRAY_FLOAT4_COLOR_DATA) + + .def_readwrite("interpol_mode", &Color::interpol_mode, + INTERPOLMODE_COLOR_INTERPOL_MODE) .def(py::init<>(),COLOR_COLOR) .def(py::init(), COLOR_COLOR_FLOAT_FLOAT_FLOAT_FLOAT_INTERPOLMODE, - "x1"_a, "x2"_a, "x3"_a, "alpha"_a=1., "interpol_mode"_a=InterpolMode::RGB) + "x1"_a, "x2"_a, "x3"_a, "alpha"_a, "interpol_mode"_a=InterpolMode::RGB) + + .def(py::init(), + COLOR_COLOR_FLOAT_FLOAT_FLOAT_INTERPOLMODE, + "x1"_a, "x2"_a, "x3"_a, "interpol_mode"_a=InterpolMode::RGB) + + .def(py::init&,InterpolMode>(), + COLOR_COLOR_CONST_ARRAY_FLOAT3_REF_INTERPOLMODE, + "xyz"_a, "interpol_mode"_a=InterpolMode::RGB) + + .def(py::init&,InterpolMode>(), + COLOR_COLOR_CONST_ARRAY_FLOAT4_REF_INTERPOLMODE, + "xyza"_a, "interpol_mode"_a=InterpolMode::RGB) .def(py::init(), COLOR_COLOR_INT_INT_INT_INT_INTERPOLMODE, - "x1"_a, "x2"_a, "x3"_a, "alpha"_a=255, "interpol_mode"_a=InterpolMode::RGB) + "x1"_a, "x2"_a, "x3"_a, "alpha"_a, "interpol_mode"_a=InterpolMode::RGB) + + .def(py::init(), + COLOR_COLOR_INT_INT_INT_INTERPOLMODE, + "x1"_a, "x2"_a, "x3"_a, "interpol_mode"_a=InterpolMode::RGB) + + .def(py::init&,InterpolMode>(), + COLOR_COLOR_CONST_ARRAY_INT3_REF_INTERPOLMODE, + "xyz"_a, "interpol_mode"_a=InterpolMode::RGB) + + .def(py::init&,InterpolMode>(), + COLOR_COLOR_CONST_ARRAY_INT4_REF_INTERPOLMODE, + "xyza"_a, "interpol_mode"_a=InterpolMode::RGB) .def(py::init(), COLOR_COLOR_CONST_STRING_REF, "hex_str"_a) + // Conversions + + .def("toRGB", &Color::toRGB, + COLOR_COLOR_TORGB_CONST) + + .def("toHSV", &Color::toHSV, + COLOR_COLOR_TOHSV_CONST) + // Properties .def("hex_str", &Color::hex_str, STRING_COLOR_HEX_STR_CONST) - .def("r", &Color::r, - FLOAT_COLOR_R_CONST) + .def("rgb", &Color::rgb, + ARRAY_INT3_COLOR_RGB_CONST) - .def("g", &Color::g, - FLOAT_COLOR_G_CONST) + .def("rgba", &Color::rgba, + ARRAY_INT3_COLOR_RGB_CONST) - .def("b", &Color::b, - FLOAT_COLOR_B_CONST) + .def("hsv", &Color::hsv, + ARRAY_INT3_COLOR_RGB_CONST) - .def("alpha", &Color::alpha, - FLOAT_COLOR_ALPHA_CONST) + .def("hsva", &Color::hsva, + ARRAY_INT3_COLOR_RGB_CONST) // Predefined colors diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 789cbdc7..9da1d086 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -85,8 +85,8 @@ void Figure2D_IPE::begin_path(const StyleProperties& s, bool tip=false) "; } @@ -543,9 +543,13 @@ void Figure2D_IPE::print_header_page() \n \ \n"; - for(const auto& [k,c] : _colors) - _f << " \n"; + for(auto& [k,c] : _colors) + { + if (c.interpol_mode == InterpolMode::HSV) + c = c.toRGB(); + _f << " \n"; + } _f << " \n \ \n \ diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index 00892b65..7590234f 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -12,139 +12,194 @@ using namespace std; using namespace codac2; -std::string DataRGB::to_hex_str() const -{ - stringstream ss; - ss << "#" << hex << setfill('0') << setw(2) << (int)(r*255) << setw(2) << (int)(g*255) << setw(2) << (int)(b*255) << setw(2) << (int)(a*255); - return ss.str(); -} - -DataRGB DataHSV::to_rgb() const -{ - float r = 1., g = 1., b = 1.; - - int i = static_cast(h * 6); - float f = (h * 6) - i; - i = i % 6; - - float p = v * (1 - s); - float q = v * (1 - f * s); - float t = v * (1 - (1 - f) * s); - - switch (i) { - case 0: r = v; g = t; b = p; break; - case 1: r = q; g = v; b = p; break; - case 2: r = p; g = v; b = t; break; - case 3: r = p; g = q; b = v; break; - case 4: r = t; g = p; b = v; break; - case 5: r = v; g = p; b = q; break; - } - - return DataRGB{r, g, b, a}; -} - -std::string DataHSV::to_hex_str() const -{ - return to_rgb().to_hex_str(); -} - Color::Color() - : data("#FFFFFFFF") -{} +{ } Color::Color(float x1, float x2, float x3, float alpha,InterpolMode interpol_mode) + :data({x1,x2,x3,alpha}), interpol_mode(interpol_mode) { assert(x1 >= 0. && x1 <= 1. && x2 >= 0. && x2 <= 1. && x3 >= 0. && x3 <= 1. && alpha >= 0. && alpha <= 1.); - if(interpol_mode == InterpolMode::RGB) - data = DataRGB{x1, x2, x3, alpha}; - else - data = DataHSV{x1, x2, x3, alpha}; } +Color::Color(double x1, double x2, double x3, double alpha, InterpolMode interpol_mode) + : Color((float)x1, (float)x2, (float)x3, (float)alpha, interpol_mode) +{ } + +Color::Color(float x1, float x2, float x3, InterpolMode interpol_mode) + : Color(x1, x2, x3, (float) 1., interpol_mode) +{ } + +Color::Color(double x1, double x2, double x3, InterpolMode interpol_mode) + : Color((float)x1, (float)x2, (float) x3, (float) 1., interpol_mode) +{ } + +Color::Color(const std::array& xyz, InterpolMode interpol_mode) + : Color(xyz[0], xyz[1], xyz[2],(float) 1., interpol_mode) +{ } + +Color::Color(const std::array& xyza, InterpolMode interpol_mode) + : Color(xyza[0], xyza[1], xyza[2], xyza[3], interpol_mode) +{ } + Color::Color(int x1, int x2, int x3, int alpha,InterpolMode interpol_mode) +: Color(interpol_mode == InterpolMode::RGB ? (float) (x1/255.) : (float) (x1/360.), + interpol_mode == InterpolMode::RGB ? (float) (x2/255.) : (float) (x2/100.), + interpol_mode == InterpolMode::RGB ? (float) (x3/255.) : (float) (x3/100.), + interpol_mode == InterpolMode::RGB ? (float) (alpha/255.) : (float) (alpha/100.), + interpol_mode) { - assert(x1 >= 0 && x1 <= 255 && x2 >= 0 && x2 <= 255 && x3 >= 0 && x3 <= 255 && alpha >= 0 && alpha <= 255); if (interpol_mode == InterpolMode::RGB) - data = DataRGB{(float)x1/255., (float)x2/255., (float)x3/255., (float)alpha/255.}; + { + assert(x1 >= 0 && x1 <= 255 && x2 >= 0 && x2 <= 255 && x3 >= 0 && x3 <= 255 && alpha >= 0 && alpha <= 255); + } else - data = DataHSV{(float)x1/360., (float)x2/100., (float)x3/100., (float)alpha/100.}; + { + assert(x1 >= 0 && x1 <= 360 && x2 >= 0 && x2 <= 100 && x3 >= 0 && x3 <= 100 && alpha >= 0 && alpha <= 100); + } + } +Color::Color(int x1, int x2, int x3, InterpolMode interpol_mode) + : Color(x1, x2, x3,interpol_mode == InterpolMode::RGB ? 255 : 100, interpol_mode) +{ } + +Color::Color(const std::array& xyz, InterpolMode interpol_mode) + : Color(xyz[0], xyz[1], xyz[2], interpol_mode == InterpolMode::RGB ? 255 : 100, interpol_mode) +{ } + +Color::Color(const std::array& xyza, InterpolMode interpol_mode) + : Color(xyza[0], xyza[1], xyza[2], xyza[3], interpol_mode) +{ } + Color::Color(const std::string& hex_str) - : data(hex_str) { assert(hex_str.size() == 7 || hex_str.size() == 9); assert(hex_str[0] == '#'); -} -std::string Color::hex_str() const -{ - switch(data.index()) + interpol_mode = InterpolMode::RGB; + + int red,green,blue,a; + std::istringstream(hex_str.substr(1,2)) >> std::hex >> red; + std::istringstream(hex_str.substr(3,2)) >> std::hex >> green; + std::istringstream(hex_str.substr(5,2)) >> std::hex >> blue; + data[0] = (float) (red/255.); + data[1] = (float) (green/255.); + data[2] = (float) (blue/255.); + + // Alpha (transparency) component may be appended to the #hexa notation. + // Value is '1' (max opacity) by default. + if(hex_str.size() == 9) { - case 0: return std::get<0>(data); - case 1: return std::get<1>(data).to_hex_str(); - case 2: return std::get<2>(data).to_hex_str(); + std::istringstream(hex_str.substr(7,2)) >> std::hex >> a; + data[3] = (float) (a/255.); } - return ""; } -float Color::r() const +Color Color::toRGB() const { - switch(data.index()) + if (interpol_mode==InterpolMode::RGB) + return *this; + else { - case 0: - int r; - std::istringstream(std::get<0>(data).substr(1,2)) >> std::hex >> r; - return (float) r/255.; - case 1: return std::get<1>(data).r; - case 2: return std::get<2>(data).to_rgb().r; + float r = 1., g = 1., b = 1.; + + int i = static_cast(data[0] * 6); + float f = (data[0] * 6) - i; + i = i % 6; + + float p = data[2] * (1 - data[1]); + float q = data[2] * (1 - f * data[1]); + float t = data[2] * (1 - (1 - f) * data[1]); + + switch (i) { + case 0: r = data[2]; g = t; b = p; break; + case 1: r = q; g = data[2]; b = p; break; + case 2: r = p; g = data[2]; b = t; break; + case 3: r = p; g = q; b = data[2]; break; + case 4: r = t; g = p; b = data[2]; break; + case 5: r = data[2]; g = p; b = q; break; + } + + return Color(r, g, b, data[3],InterpolMode::RGB); } - return 0.; } -float Color::g() const +Color Color::toHSV() const { - switch(data.index()) + if (interpol_mode==InterpolMode::HSV) + return *this; + else { - case 0: - int g; - std::istringstream(std::get<0>(data).substr(3,2)) >> std::hex >> g; - return (float) g/255.; - case 1: return std::get<1>(data).g; - case 2: return std::get<2>(data).to_rgb().g; + float c_max = std::max({data[0], data[1], data[2]}); + float c_min = std::min({data[0], data[1], data[2]}); + float delta = c_max - c_min; + + float h = 0.0; + if (delta != 0) { + if (c_max == data[0]) { + h = fmod((data[1] - data[2]) / delta, 6.0); + } else if (c_max == data[1]) { + h = (data[2] - data[0]) / delta + 2.0; + } else if (c_max == data[2]) { + h = (data[0] - data[1]) / delta + 4.0; + } + h /= 6.0; + if (h < 0) { + h += 1.0; + } + } + + float s = (c_max == 0) ? 0 : (delta / c_max); + + float v = c_max; + + return Color(h, s, v, data[3],InterpolMode::HSV); } - return 0.; } -float Color::b() const +std::string Color::hex_str() const { - switch(data.index()) - { - case 0: - int b; - std::istringstream(std::get<0>(data).substr(5,2)) >> std::hex >> b; - return (float) b/255.; - case 1: return std::get<1>(data).b; - case 2: return std::get<2>(data).to_rgb().b; - } - return 0.; + if (interpol_mode == InterpolMode::RGB) + { + std::stringstream s; + s << std::hex << std::setfill('0'); + s << std::setw(2) << (int)(data[0]*255) << std::setw(2) << (int)(data[1]*255) << std::setw(2) << (int)(data[2]*255); + if(data[3] != 1.) + s << std::setw(2) << (int)(data[3]*255); + return "#"+s.str(); + } + else + return toRGB().hex_str(); } -float Color::alpha() const +std::array Color::rgb() const { - switch(data.index()) - { - case 0: - float alpha; - if (std::get<0>(data).size() == 7) - return 1.; - else - { - std::istringstream(std::get<0>(data).substr(7,2)) >> std::hex >> alpha; - return alpha/255.; - } - case 1: return std::get<1>(data).a; - case 2: return std::get<2>(data).a; - } - return 0.; + if (interpol_mode == InterpolMode::RGB) + return { (int)(data[0]*255), (int)(data[1]*255), (int)(data[2]*255) }; + else + return toRGB().rgb(); +} + +std::array Color::rgba() const +{ + if (interpol_mode == InterpolMode::RGB) + return { (int)(data[0]*255), (int)(data[1]*255), (int)(data[2]*255), (int)(data[3]*255) }; + else + return toRGB().rgba(); +} + +std::array Color::hsv() const +{ + if (interpol_mode == InterpolMode::HSV) + return { (int)(data[0]*360), (int)(data[1]*100), (int)(data[2]*100) }; + else + return toHSV().hsv(); +} + +std::array Color::hsva() const +{ + if (interpol_mode == InterpolMode::HSV) + return { (int)(data[0]*360), (int)(data[1]*100), (int)(data[2]*100), (int)(data[3]*100) }; + else + return toHSV().hsva(); } \ No newline at end of file diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index 7eb4f7e1..fbdd7d41 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -11,9 +11,10 @@ #include #include -#include +#include #include"codac2_assert.h" + namespace codac2 { enum class InterpolMode @@ -21,41 +22,41 @@ namespace codac2 RGB = 0x01, HSV = 0x02 }; - /** - * \struct DataRGB - * \brief Represents an RGB value - */ - struct DataRGB { - float r, g, b, a; - std::string to_hex_str() const; - }; - /** - * \struct DataHSV - * \brief Represents an HSV value - */ - struct DataHSV { - float h, s, v, a; - DataRGB to_rgb() const; - std::string to_hex_str() const; - }; - /** - * \struct Color - * \brief Represents an html color - */ + struct Color { - std::variant< std::string, DataRGB, DataHSV > data; + std::array data = {0.,0.,0.,1.0}; // RGB or HSV values + alpha, between 0 and 1 + InterpolMode interpol_mode = InterpolMode::RGB;//RGB or HSV + + // Constructors explicit Color(); - explicit Color(float x1, float x2, float x3, float alpha = 1.,InterpolMode interpol_mode = InterpolMode::RGB); - explicit Color(int x1, int x2, int x3, int alpha = 255,InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(float x1, float x2, float x3, float alpha, InterpolMode interpol_mode = InterpolMode::RGB); // RGBA constructor + explicit Color(double x1, double x2, double x3, double alpha, InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(float x1, float x2, float x3, InterpolMode interpol_mode = InterpolMode::RGB); // RGB constructor + explicit Color(double x1, double x2, double x3, InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(const std::array& xyz, InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(const std::array& xyza, InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(int x1, int x2, int x3, int alpha,InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(int x1, int x2, int x3, InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(const std::array& xyz, InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(const std::array& xyza, InterpolMode interpol_mode = InterpolMode::RGB); explicit Color(const std::string& hex_str); + //Conversions + + Color toRGB() const; + Color toHSV() const; + + // Properties + std::string hex_str() const; - float r() const; - float g() const; - float b() const; - float alpha() const; + std::array rgb() const; + std::array rgba() const; + std::array hsv() const; + std::array hsva() const; + + // Predefined colors static Color none() { return Color(255, 255, 255, 0 ); }; static Color black(float alpha = 1) { return Color(0, 0, 0, (int)(alpha*255)); }; diff --git a/src/graphics/styles/codac2_ColorMap.cpp b/src/graphics/styles/codac2_ColorMap.cpp index 2b729b9d..bbc7ea4f 100644 --- a/src/graphics/styles/codac2_ColorMap.cpp +++ b/src/graphics/styles/codac2_ColorMap.cpp @@ -26,7 +26,7 @@ Color ColorMap::color(float r) const { assert (colormap.size() >= 2); if(std::isnan(r)) // undefined ratio - return Color((float)0.5, 0.5, 0.5); + return Color(0.5, 0.5, 0.5); assert(Interval(0.,1.).contains(r)); Interval map_domain = Interval(colormap.begin()->first,prev(colormap.end())->first); @@ -36,15 +36,15 @@ Color ColorMap::color(float r) const { typename map::const_iterator it_ub; it_ub = colormap.lower_bound(real_index); - Color color_lb = prev(it_ub)->second; - Color color_ub = it_ub->second; + Color color_lb = prev(it_ub)->second.toRGB(); + Color color_ub = it_ub->second.toRGB(); float local_ratio = (real_index - prev(it_ub)->first) / (it_ub->first - prev(it_ub)->first); - return Color((float)(color_lb.r() + (color_ub.r() - color_lb.r()) * local_ratio), - (float)(color_lb.g() + (color_ub.g() - color_lb.g()) * local_ratio), - (float)(color_lb.b() + (color_ub.b() - color_lb.b()) * local_ratio), - (float)(color_lb.alpha() + (color_ub.alpha() - color_lb.alpha()) * local_ratio)); + return Color((float)(color_lb.data[0] + (color_ub.data[0] - color_lb.data[0]) * local_ratio), + (float)(color_lb.data[1] + (color_ub.data[1] - color_lb.data[1]) * local_ratio), + (float)(color_lb.data[2] + (color_ub.data[2] - color_lb.data[2]) * local_ratio), + (float)(color_lb.data[3] + (color_ub.data[3] - color_lb.data[3]) * local_ratio)); } diff --git a/src/graphics/styles/codac2_StyleProperties.cpp b/src/graphics/styles/codac2_StyleProperties.cpp index 38e15389..d6b42b8b 100644 --- a/src/graphics/styles/codac2_StyleProperties.cpp +++ b/src/graphics/styles/codac2_StyleProperties.cpp @@ -20,9 +20,13 @@ StyleProperties::StyleProperties(const Color& stroke_color_) { } StyleProperties::StyleProperties(std::initializer_list colors) - : stroke_color(*colors.begin()), fill_color(*std::prev(colors.end())) + : stroke_color(*colors.begin()) { assert(colors.size() <= 2); + if (colors.size() == 1) + fill_color = Color::none(); + else + fill_color = *std::prev(colors.end()); } StyleProperties StyleProperties::inside() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0ac83aa7..1b6c4607 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -78,6 +78,8 @@ list(APPEND SRC_TESTS # listing files without extension core/tools/codac2_tests_Approx + graphics/styles/codac2_tests_Color + ) diff --git a/tests/graphics/styles/codac2_tests_Color.cpp b/tests/graphics/styles/codac2_tests_Color.cpp new file mode 100644 index 00000000..9b356716 --- /dev/null +++ b/tests/graphics/styles/codac2_tests_Color.cpp @@ -0,0 +1,307 @@ +/** + * Codac tests + * ---------------------------------------------------------------------------- + * \date 2024 + * \author Simon Rohou, Maël Godard + * \copyright Copyright 2024 Codac Team + * \license GNU Lesser General Public License (LGPL) + */ + +#include +#include +#include + +using namespace std; +using namespace codac2; + +// Custom Matchers to manage tolerate errors + +// array matcher + +class Array4MatcherWithTolerance : public Catch::Matchers::MatcherBase> { + std::array m_expected; + int m_tolerance; + +public: + Array4MatcherWithTolerance(const std::array& expected, int tolerance) + : m_expected(expected), m_tolerance(tolerance) {} + + bool match(const std::array& actual) const override { + for (size_t i = 0; i < m_expected.size(); ++i) { + if (std::abs(actual[i] - m_expected[i]) > m_tolerance) { + return false; + } + } + return true; + } + + std::string describe() const override { + std::ostringstream oss; + oss << "is close to { "; + for (size_t i = 0; i < m_expected.size(); ++i) { + oss << m_expected[i]; + if (i < m_expected.size() - 1) oss << ", "; + } + oss << " } with tolerance " << m_tolerance; + return oss.str(); + } +}; + +// array matcher + +class Array3MatcherWithTolerance : public Catch::Matchers::MatcherBase> { + std::array m_expected; + int m_tolerance; + +public: + Array3MatcherWithTolerance(const std::array& expected, int tolerance) + : m_expected(expected), m_tolerance(tolerance) {} + + bool match(const std::array& actual) const override { + for (size_t i = 0; i < m_expected.size(); ++i) { + if (std::abs(actual[i] - m_expected[i]) > m_tolerance) { + return false; + } + } + return true; + } + + std::string describe() const override { + std::ostringstream oss; + oss << "is close to { "; + for (size_t i = 0; i < m_expected.size(); ++i) { + oss << m_expected[i]; + if (i < m_expected.size() - 1) oss << ", "; + } + oss << " } with tolerance " << m_tolerance; + return oss.str(); + } +}; + +// HTML color matcher + +class HtmlColorMatcherWithTolerance : public Catch::Matchers::MatcherBase { + std::string m_expected; + int m_tolerance; + + // Helper to convert a hex color to RGB + static std::array hexToRgb(const std::string& hex) { + assert(hex.size() == 7 && hex[0] == '#'); // Ensure format is #RRGGBB + return { + std::stoi(hex.substr(1, 2), nullptr, 16), + std::stoi(hex.substr(3, 2), nullptr, 16), + std::stoi(hex.substr(5, 2), nullptr, 16) + }; + } + +public: + HtmlColorMatcherWithTolerance(const std::string& expected, int tolerance) + : m_expected(expected), m_tolerance(tolerance) { + assert(m_expected.size() == 7 && m_expected[0] == '#'); // Ensure format is #RRGGBB + } + + bool match(const std::string& actual) const override { + if (actual.size() != 7 || actual[0] != '#') { + return false; // Invalid format + } + + auto expectedRgb = hexToRgb(m_expected); + auto actualRgb = hexToRgb(actual); + + for (size_t i = 0; i < 3; ++i) { + if (std::abs(actualRgb[i] - expectedRgb[i]) > m_tolerance) { + return false; + } + } + return true; + } + + std::string describe() const override { + std::ostringstream oss; + oss << "is close to " << m_expected << " with tolerance " << m_tolerance; + return oss.str(); + } +}; + +// RGBA HTML color matcher + +class HtmlColorMatcherWithToleranceRGBA : public Catch::Matchers::MatcherBase { + std::string m_expected; + int m_tolerance; + + // Helper to convert a hex color to RGBA + static std::array hexToRgba(const std::string& hex) { + assert(hex.size() == 9 && hex[0] == '#'); // Ensure format is #RRGGBBAA + return { + std::stoi(hex.substr(1, 2), nullptr, 16), + std::stoi(hex.substr(3, 2), nullptr, 16), + std::stoi(hex.substr(5, 2), nullptr, 16), + std::stoi(hex.substr(7, 2), nullptr, 16) + }; + } + +public: + HtmlColorMatcherWithToleranceRGBA(const std::string& expected, int tolerance) + : m_expected(expected), m_tolerance(tolerance) { + assert(m_expected.size() == 9 && m_expected[0] == '#'); // Ensure format is #RRGGBBAA + } + + bool match(const std::string& actual) const override { + if (actual.size() != 9 || actual[0] != '#') { + return false; // Invalid format + } + + auto expectedRgba = hexToRgba(m_expected); + auto actualRgba = hexToRgba(actual); + + for (size_t i = 0; i < 4; ++i) { + if (std::abs(actualRgba[i] - expectedRgba[i]) > m_tolerance) { + return false; + } + } + return true; + } + + std::string describe() const override { + std::ostringstream oss; + oss << "is close to " << m_expected << " with tolerance " << m_tolerance; + return oss.str(); + } +}; + +inline Array4MatcherWithTolerance IsCloseTo(const std::array& expected, int tolerance = 1) { + return Array4MatcherWithTolerance(expected, tolerance); +} + +inline Array3MatcherWithTolerance IsCloseTo(const std::array& expected, int tolerance = 1) { + return Array3MatcherWithTolerance(expected, tolerance); +} + +inline HtmlColorMatcherWithTolerance IsCloseToHtmlColor(const std::string& expected, int tolerance = 1) { + return HtmlColorMatcherWithTolerance(expected, tolerance); +} + +inline HtmlColorMatcherWithToleranceRGBA IsCloseToHtmlColorRGBA(const std::string& expected, int tolerance = 1) { + return HtmlColorMatcherWithToleranceRGBA(expected, tolerance); +} + + +TEST_CASE("Color") +{ + { + // Red + + std::array d_rgb { 255,0,0 }; + std::array d_rgba { 255,0,0,255 }; + std::array d_hsv { 0,100,100 }; + std::array d_hsva { 0,100,100,100 }; + std::array d_rgb_f { 1.0,0.0,0.0 }; + std::array d_rgba_f { 1.0,0.0,0.0,1.0 }; + std::array d_hsv_f { 0.0,1.0,1.0 }; + std::array d_hsva_f { 0.0,1.0,1.0,1.0 }; + + vector v { + Color(d_rgb, InterpolMode::RGB /* InterpolMode::RGB is default */), + Color(d_rgba, InterpolMode::RGB), + Color(255,0,0, InterpolMode::RGB), + Color(255,0,0,255, InterpolMode::RGB), + Color(d_hsv, InterpolMode::HSV), + Color(d_hsva, InterpolMode::HSV), + Color(0,100,100, InterpolMode::HSV), + Color(0,100,100,100, InterpolMode::HSV), + Color(d_rgb_f, InterpolMode::RGB), + Color(d_rgba_f, InterpolMode::RGB), + Color( 1.0, 0.0, 0.0, InterpolMode::RGB), + Color( 1.0, 0.0, 0.0, 1.0, InterpolMode::RGB), + Color(d_hsv_f, InterpolMode::HSV), + Color(d_hsva_f, InterpolMode::HSV), + Color( 0.0, 1.0, 1.0, InterpolMode::HSV), + Color( 0.0, 1.0, 1.0, 1.0, InterpolMode::HSV), + Color("#FF0000") + }; + + for(const auto& c : v) + { + CHECK_THAT(c.hex_str(), IsCloseToHtmlColor("#ff0000")); + CHECK_THAT(c.rgb(), IsCloseTo(std::array{ 255,0,0})); // return std::array + CHECK_THAT(c.rgba(), IsCloseTo(std::array{ 255,0,0,255})); // return std::array + CHECK_THAT(c.hsv(), IsCloseTo(std::array{ 0,100,100})); // return std::array + CHECK_THAT(c.hsva(), IsCloseTo(std::array{ 0,100,100,100})); // return std::array + } + } + + { + // Pink full opacity + + int a = 255; + std::array d_rgb { 229,128,255 }; + std::array d_rgba { 229,128,255,a }; + std::array d_hsv { 288,50,100 }; + std::array d_hsva { 288,50,100,100}; + std::array d_rgb_f {(float) (229./255.), (float) (128./255.), (float) (255./255.)}; + std::array d_rgba_f {(float) (229./255.), (float) (128./255.), (float) (255./255.), 1.0}; + std::array d_hsv_f {(float) (288./360.), (float) (50./100.), (float) (100./100.)}; + std::array d_hsva_f {(float) (288./360.), (float) (50./100.), (float) (100./100.), 1.0}; + + + vector v { + Color(d_rgb, InterpolMode::RGB /* InterpolMode::RGB is default */), + Color(d_rgba, InterpolMode::RGB), + Color(229,128,255, InterpolMode::RGB), + Color(229,128,255,a, InterpolMode::RGB), + Color(d_hsv, InterpolMode::HSV), + Color(d_hsva, InterpolMode::HSV), + Color(288,50,100, InterpolMode::HSV), + Color(288,50,100,100, InterpolMode::HSV), + Color(d_rgb_f, InterpolMode::RGB), + Color(d_rgba_f, InterpolMode::RGB), + Color( 229./255., 128./255., 255./255., InterpolMode::RGB), + Color( 229./255., 128./255., 255./255., 1.0, InterpolMode::RGB), + Color(d_hsv_f, InterpolMode::HSV), + Color(d_hsva_f, InterpolMode::HSV), + Color( 288./360., 50./100., 100./100., InterpolMode::HSV), + Color( 288./360.,50./100., 100./100., 1.0, InterpolMode::HSV), + Color("#e580ff") + }; + + for(const auto& c : v) + { + CHECK_THAT(c.hex_str(), IsCloseToHtmlColor("#e580ff")); + CHECK_THAT(c.rgb(), IsCloseTo(std::array{ 229,128,255})); // return std::array + CHECK_THAT(c.rgba(), IsCloseTo(std::array{ 229,128,255,a})); // return std::array + CHECK_THAT(c.hsv(), IsCloseTo(std::array{ 288,50,100})); // return std::array + CHECK_THAT(c.hsva(), IsCloseTo(std::array{ 288,50,100,100})); // return std::array + } + } + + { + // Pink 40% opacity + + int a = 0.4*255; + std::array d_rgba { 229,128,255,a }; + std::array d_hsva { 288,50,100,40 }; + std::array d_rgba_f {(float) (229./255.), (float) (128./255.), (float) (255./255.),(float) 0.4}; + std::array d_hsva_f {(float) (288./360.), (float) (50./100.), (float) (100./100.), (float) 0.4}; + + vector v { + Color(d_rgba, InterpolMode::RGB), + Color(229,128,255,a, InterpolMode::RGB), + Color(d_hsva, InterpolMode::HSV), + Color(288,50,100,40, InterpolMode::HSV), + Color(d_rgba_f, InterpolMode::RGB), + Color( 229./255., 128./255., 255./255., 0.4, InterpolMode::RGB), + Color(d_hsva_f, InterpolMode::HSV), + Color( 288./360.,50./100., 100./100., 0.4, InterpolMode::HSV), + Color("#e580ff66") + }; + + for(const auto& c : v) + { + CHECK_THAT(c.hex_str(), IsCloseToHtmlColorRGBA("#e580ff66")); + CHECK_THAT(c.rgb(), IsCloseTo(std::array{ 229,128,255})); // return std::array + CHECK_THAT(c.rgba(), IsCloseTo(std::array{ 229,128,255,a})); // return std::array + CHECK_THAT(c.hsv(), IsCloseTo(std::array{ 288,50,100})); // return std::array + CHECK_THAT(c.hsva(), IsCloseTo(std::array{ 288,50,100,40})); // return std::array + } + } +} \ No newline at end of file diff --git a/tests/graphics/styles/codac2_tests_Color.py b/tests/graphics/styles/codac2_tests_Color.py new file mode 100644 index 00000000..d47baf66 --- /dev/null +++ b/tests/graphics/styles/codac2_tests_Color.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python + +# Codac tests +# ---------------------------------------------------------------------------- +# \date 2024 +# \author Simon Rohou, Maël GODARD +# \copyright Copyright 2024 Codac Team +# \license GNU Lesser General Public License (LGPL) + +import unittest +from codac import * + +class ArrayMatcherWithTolerance: + def __init__(self, expected, tolerance=1): + self.expected = expected + self.tolerance = tolerance + + def match(self, actual): + if len(actual) != len(self.expected): + return False + for i in range(len(self.expected)): + if abs(actual[i] - self.expected[i]).mid() > self.tolerance: + return False + return True + + def describe(self): + return f'is close to {self.expected} with tolerance {self.tolerance}' + + +import re + +class HtmlColorMatcherWithTolerance: + def __init__(self, expected: str, tolerance: int = 1): + assert self._is_valid_color(expected), f"Invalid color format: {expected}" + self.expected = expected + self.tolerance = tolerance + + def _is_valid_color(self, color: str) -> bool: + """Validate the color format as #RRGGBBAA or #RRGGBB.""" + return bool(re.match(r"^#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$", color)) + + def _hex_to_components(self, hex_color: str): + """Convert a #RRGGBBAA or #RRGGBB color to a tuple of integers.""" + if len(hex_color) == 7: # #RRGGBB + return tuple(int(hex_color[i:i+2], 16) for i in range(1, 7, 2)) + elif len(hex_color) == 9: # #RRGGBBAA + return tuple(int(hex_color[i:i+2], 16) for i in range(1, 9, 2)) + + def match(self, actual: str) -> bool: + """Check if the actual color matches the expected color within the tolerance.""" + if not self._is_valid_color(actual): + return False + + expected_components = self._hex_to_components(self.expected) + actual_components = self._hex_to_components(actual) + + if len(expected_components) != len(actual_components): + return False + + return all(abs(e - a).mid() <= self.tolerance for e, a in zip(expected_components, actual_components)) + + def describe(self) -> str: + """Provide a description of the matcher.""" + return f"is close to {self.expected} with tolerance {self.tolerance}" + + +def is_close_to(expected, tolerance=1): + return ArrayMatcherWithTolerance(expected, tolerance) + +def is_close_to_html_color(expected, tolerance=1): + return HtmlColorMatcherWithTolerance(expected, tolerance) + +class TestColor(unittest.TestCase): + + def test_Color(self): + # Red + + d_rgb = [255, 0, 0] + d_rgba = [255, 0, 0, 255] + d_hsv = [0, 100, 100] + d_hsva = [0, 100, 100, 100] + d_rgb_f= [1.0, 0.0, 0.0] + d_rgba_f= [1.0, 0.0, 0.0, 1.0] + d_hsv_f= [0.0, 1.0, 1.0] + d_hsva_f= [0.0, 1.0, 1.0, 1.0] + + + colors = [ + Color(d_rgb, InterpolMode.RGB), + Color(d_rgba, InterpolMode.RGB), + Color(255, 0, 0, interpol_mode=InterpolMode.RGB), + Color(255, 0, 0, 255, InterpolMode.RGB), + Color(d_hsv, InterpolMode.HSV), + Color(d_hsva, InterpolMode.HSV), + Color(0, 100, 100, interpol_mode=InterpolMode.HSV), + Color(0, 100, 100, 100, InterpolMode.HSV), + Color(d_rgb_f, InterpolMode.RGB), + Color(d_rgba_f, InterpolMode.RGB), + Color(1.0, 0.0, 0.0, interpol_mode=InterpolMode.RGB), + Color(1.0, 0.0, 0.0, 1.0, InterpolMode.RGB), + Color(d_hsv_f, InterpolMode.HSV), + Color(d_hsva_f, InterpolMode.HSV), + Color(0.0, 1.0, 1.0, interpol_mode=InterpolMode.HSV), + Color(0.0, 1.0, 1.0, 1.0, InterpolMode.HSV), + Color("#FF0000") + ] + + for c in colors: + self.assertTrue(is_close_to_html_color("#FF0000").match(c.hex_str())) + self.assertTrue(is_close_to([255, 0, 0]).match(c.rgb())) + self.assertTrue(is_close_to([255, 0, 0, 255]).match(c.rgba())) + self.assertTrue(is_close_to([0, 100, 100]).match(c.hsv())) + self.assertTrue(is_close_to([0, 100, 100, 100]).match(c.hsva())) + + # Pink full opacity + + d_rgb = [229,128,255] + d_rgba = [229,128,255,255] + d_hsv = [288,50,100] + d_hsva = [288,50,100,100] + d_rgb_f = [229.0/255.0, 128.0/255.0, 255.0/255.0] + d_rgba_f = [229.0/255.0, 128.0/255.0, 255.0/255.0, 1.0] + d_hsv_f = [288.0/360.0, 50.0/100.0, 100.0/100.0] + d_hsva_f = [288.0/360.0, 50.0/100.0, 100.0/100.0, 1.0] + + colors = [ + Color(d_rgb, InterpolMode.RGB), + Color(d_rgba, InterpolMode.RGB), + Color(229,128,255, interpol_mode=InterpolMode.RGB), + Color(229,128,255,255, InterpolMode.RGB), + Color(d_hsv, InterpolMode.HSV), + Color(d_hsva, InterpolMode.HSV), + Color(288,50,100, interpol_mode=InterpolMode.HSV), + Color(288,50,100,100, InterpolMode.HSV), + Color(d_rgb_f, InterpolMode.RGB), + Color(d_rgba_f, InterpolMode.RGB), + Color(229.0/255.0, 128.0/255.0, 255.0/255.0, interpol_mode=InterpolMode.RGB), + Color(229.0/255.0, 128.0/255.0, 255.0/255.0, 1.0, InterpolMode.RGB), + Color(d_hsv_f, InterpolMode.HSV), + Color(d_hsva_f, InterpolMode.HSV), + Color(288.0/360.0, 50.0/100.0, 100.0/100.0, interpol_mode=InterpolMode.HSV), + Color(288.0/360.0, 50.0/100.0, 100.0/100.0, 1.0, InterpolMode.HSV), + Color("#E580FF") + ] + + for c in colors: + self.assertTrue(is_close_to_html_color("#E580FF").match(c.hex_str())) + self.assertTrue(is_close_to([229,128,255]).match(c.rgb())) + self.assertTrue(is_close_to([229,128,255,255]).match(c.rgba())) + self.assertTrue(is_close_to([288,50,100]).match(c.hsv())) + self.assertTrue(is_close_to([288,50,100,100]).match(c.hsva())) + + # Pink 40% opacity + + a_rgb=102 + a_hsv=40 + d_rgba = [229,128,255,a_rgb] + d_hsva = [288,50,100,a_hsv] + d_rgba_f = [229.0/255.0, 128.0/255.0, 255.0/255.0, 102.0/255.0] + d_hsva_f = [288.0/360.0, 50.0/100.0, 100.0/100.0, 40.0/100.0] + + colors = [ + Color(d_rgba, InterpolMode.RGB), + Color(229,128,255,a_rgb, InterpolMode.RGB), + Color(d_hsva, InterpolMode.HSV), + Color(288,50,100,a_hsv, InterpolMode.HSV), + Color(d_rgba_f, InterpolMode.RGB), + Color(229.0/255.0, 128.0/255.0, 255.0/255.0, 102.0/255.0, InterpolMode.RGB), + Color(d_hsva_f, InterpolMode.HSV), + Color(288.0/360.0, 50.0/100.0, 100.0/100.0, 40.0/100.0, InterpolMode.HSV), + Color("#E580FF66") + ] + for c in colors: + self.assertTrue(is_close_to_html_color("#E580FF66").match(c.hex_str())) + self.assertTrue(is_close_to([229,128,255]).match(c.rgb())) + self.assertTrue(is_close_to([229,128,255,a_rgb]).match(c.rgba())) + self.assertTrue(is_close_to([288,50,100]).match(c.hsv())) + self.assertTrue(is_close_to([288,50,100,a_hsv]).match(c.hsva())) + + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file From 501f91d08f7b5e0c9af7dea7ad7af519b433473f Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 2 Dec 2024 21:30:20 +0100 Subject: [PATCH 082/102] minor correction --- examples/00_graphics/CMakeCache.txt | 381 --------- .../CMakeFiles/3.22.1/CMakeCCompiler.cmake | 72 -- .../CMakeFiles/3.22.1/CMakeCXXCompiler.cmake | 83 -- .../3.22.1/CMakeDetermineCompilerABI_C.bin | Bin 15968 -> 0 bytes .../3.22.1/CMakeDetermineCompilerABI_CXX.bin | Bin 15992 -> 0 bytes .../CMakeFiles/3.22.1/CMakeSystem.cmake | 15 - .../3.22.1/CompilerIdC/CMakeCCompilerId.c | 803 ------------------ .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 791 ----------------- .../CMakeDirectoryInformation.cmake | 16 - .../00_graphics/CMakeFiles/Makefile.cmake | 121 --- examples/00_graphics/CMakeFiles/Makefile2 | 86 -- .../CMakeFiles/TargetDirectories.txt | 2 - .../00_graphics/CMakeFiles/cmake.check_cache | 1 - .../00_graphics/CMakeFiles/progress.marks | 1 - examples/00_graphics/Makefile | 140 --- examples/00_graphics/cmake_install.cmake | 54 -- 16 files changed, 2566 deletions(-) delete mode 100644 examples/00_graphics/CMakeCache.txt delete mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CMakeCCompiler.cmake delete mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake delete mode 100755 examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_C.bin delete mode 100755 examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_CXX.bin delete mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CMakeSystem.cmake delete mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CompilerIdC/CMakeCCompilerId.c delete mode 100644 examples/00_graphics/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp delete mode 100644 examples/00_graphics/CMakeFiles/CMakeDirectoryInformation.cmake delete mode 100644 examples/00_graphics/CMakeFiles/Makefile.cmake delete mode 100644 examples/00_graphics/CMakeFiles/Makefile2 delete mode 100644 examples/00_graphics/CMakeFiles/TargetDirectories.txt delete mode 100644 examples/00_graphics/CMakeFiles/cmake.check_cache delete mode 100644 examples/00_graphics/CMakeFiles/progress.marks delete mode 100644 examples/00_graphics/Makefile delete mode 100644 examples/00_graphics/cmake_install.cmake diff --git a/examples/00_graphics/CMakeCache.txt b/examples/00_graphics/CMakeCache.txt deleted file mode 100644 index e13e7fa5..00000000 --- a/examples/00_graphics/CMakeCache.txt +++ /dev/null @@ -1,381 +0,0 @@ -# This is the CMakeCache file. -# For build in directory: /home/neo/codac/examples/00_graphics -# It was generated by CMake: /usr/bin/cmake -# You can edit this file to change values found and used by cmake. -# If you do not want to change any of the values, simply exit the editor. -# If you do want to change a value, simply edit, save, and exit the editor. -# The syntax for the file is as follows: -# KEY:TYPE=VALUE -# KEY is the name of a variable in the cache. -# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. -# VALUE is the current value for the KEY. - -######################## -# EXTERNAL cache entries -######################## - -//No help, variable specified on the command line. -BUILD_TESTS:UNINITIALIZED=ON - -//Path to a program. -CMAKE_ADDR2LINE:FILEPATH=/usr/bin/addr2line - -//Path to a program. -CMAKE_AR:FILEPATH=/usr/bin/ar - -//Choose the type of build, options are: None Debug Release RelWithDebInfo -// MinSizeRel ... -CMAKE_BUILD_TYPE:STRING=Release - -//Enable/Disable color output during build. -CMAKE_COLOR_MAKEFILE:BOOL=ON - -//CXX compiler -CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ - -//A wrapper around 'ar' adding the appropriate '--plugin' option -// for the GCC compiler -CMAKE_CXX_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-11 - -//A wrapper around 'ranlib' adding the appropriate '--plugin' option -// for the GCC compiler -CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-11 - -//Flags used by the CXX compiler during all build types. -CMAKE_CXX_FLAGS:STRING=-fPIC - -//Flags used by the CXX compiler during DEBUG builds. -CMAKE_CXX_FLAGS_DEBUG:STRING=-g - -//Flags used by the CXX compiler during MINSIZEREL builds. -CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG - -//Flags used by the CXX compiler during RELEASE builds. -CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG - -//Flags used by the CXX compiler during RELWITHDEBINFO builds. -CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG - -//C compiler -CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc - -//A wrapper around 'ar' adding the appropriate '--plugin' option -// for the GCC compiler -CMAKE_C_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-11 - -//A wrapper around 'ranlib' adding the appropriate '--plugin' option -// for the GCC compiler -CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-11 - -//Flags used by the C compiler during all build types. -CMAKE_C_FLAGS:STRING=-fPIC - -//Flags used by the C compiler during DEBUG builds. -CMAKE_C_FLAGS_DEBUG:STRING=-g - -//Flags used by the C compiler during MINSIZEREL builds. -CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG - -//Flags used by the C compiler during RELEASE builds. -CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG - -//Flags used by the C compiler during RELWITHDEBINFO builds. -CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG - -//Path to a program. -CMAKE_DLLTOOL:FILEPATH=CMAKE_DLLTOOL-NOTFOUND - -//Flags used by the linker during all build types. -CMAKE_EXE_LINKER_FLAGS:STRING= - -//Flags used by the linker during DEBUG builds. -CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during MINSIZEREL builds. -CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during RELEASE builds. -CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during RELWITHDEBINFO builds. -CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Enable/Disable output of compile commands during generation. -CMAKE_EXPORT_COMPILE_COMMANDS:BOOL= - -//Install path prefix, prepended onto install directories. -CMAKE_INSTALL_PREFIX:PATH=/home/neo/codac/build_install - -//Path to a program. -CMAKE_LINKER:FILEPATH=/usr/bin/ld - -//Path to a program. -CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/gmake - -//Flags used by the linker during the creation of modules during -// all build types. -CMAKE_MODULE_LINKER_FLAGS:STRING= - -//Flags used by the linker during the creation of modules during -// DEBUG builds. -CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during the creation of modules during -// MINSIZEREL builds. -CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during the creation of modules during -// RELEASE builds. -CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during the creation of modules during -// RELWITHDEBINFO builds. -CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Path to a program. -CMAKE_NM:FILEPATH=/usr/bin/nm - -//Path to a program. -CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy - -//Path to a program. -CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump - -//Value Computed by CMake -CMAKE_PROJECT_DESCRIPTION:STATIC= - -//Value Computed by CMake -CMAKE_PROJECT_HOMEPAGE_URL:STATIC= - -//Value Computed by CMake -CMAKE_PROJECT_NAME:STATIC=Project - -//Path to a program. -CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib - -//Path to a program. -CMAKE_READELF:FILEPATH=/usr/bin/readelf - -//Flags used by the linker during the creation of shared libraries -// during all build types. -CMAKE_SHARED_LINKER_FLAGS:STRING= - -//Flags used by the linker during the creation of shared libraries -// during DEBUG builds. -CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during the creation of shared libraries -// during MINSIZEREL builds. -CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during the creation of shared libraries -// during RELEASE builds. -CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during the creation of shared libraries -// during RELWITHDEBINFO builds. -CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//If set, runtime paths are not added when installing shared libraries, -// but are added when building. -CMAKE_SKIP_INSTALL_RPATH:BOOL=NO - -//If set, runtime paths are not added when using shared libraries. -CMAKE_SKIP_RPATH:BOOL=NO - -//Flags used by the linker during the creation of static libraries -// during all build types. -CMAKE_STATIC_LINKER_FLAGS:STRING= - -//Flags used by the linker during the creation of static libraries -// during DEBUG builds. -CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= - -//Flags used by the linker during the creation of static libraries -// during MINSIZEREL builds. -CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= - -//Flags used by the linker during the creation of static libraries -// during RELEASE builds. -CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= - -//Flags used by the linker during the creation of static libraries -// during RELWITHDEBINFO builds. -CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= - -//Path to a program. -CMAKE_STRIP:FILEPATH=/usr/bin/strip - -//If this value is on, makefiles will be generated without the -// .SILENT directive, and all commands will be echoed to the console -// during the make. This is useful for debugging only. With Visual -// Studio IDE projects all commands are done without /nologo. -CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE - -//No help, variable specified on the command line. -FAST_RELEASE:UNINITIALIZED=1 - -//Value Computed by CMake -Project_BINARY_DIR:STATIC=/home/neo/codac/examples/00_graphics - -//Value Computed by CMake -Project_IS_TOP_LEVEL:STATIC=ON - -//Value Computed by CMake -Project_SOURCE_DIR:STATIC=/home/neo/codac/examples - -//No help, variable specified on the command line. -TEST_EXAMPLES:UNINITIALIZED=ON - -//No help, variable specified on the command line. -WITH_PYTHON:UNINITIALIZED=ON - - -######################## -# INTERNAL cache entries -######################## - -//ADVANCED property for variable: CMAKE_ADDR2LINE -CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_AR -CMAKE_AR-ADVANCED:INTERNAL=1 -//This is the directory where this CMakeCache.txt was created -CMAKE_CACHEFILE_DIR:INTERNAL=/home/neo/codac/examples/00_graphics -//Major version of cmake used to create the current loaded cache -CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 -//Minor version of cmake used to create the current loaded cache -CMAKE_CACHE_MINOR_VERSION:INTERNAL=22 -//Patch version of cmake used to create the current loaded cache -CMAKE_CACHE_PATCH_VERSION:INTERNAL=1 -//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE -CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 -//Path to CMake executable. -CMAKE_COMMAND:INTERNAL=/usr/bin/cmake -//Path to cpack program executable. -CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack -//Path to ctest program executable. -CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest -//ADVANCED property for variable: CMAKE_CXX_COMPILER -CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR -CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB -CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS -CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG -CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL -CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE -CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO -CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_COMPILER -CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_COMPILER_AR -CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB -CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS -CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG -CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL -CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE -CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO -CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_DLLTOOL -CMAKE_DLLTOOL-ADVANCED:INTERNAL=1 -//Executable file format -CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS -CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG -CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL -CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE -CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS -CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 -//Name of external makefile project generator. -CMAKE_EXTRA_GENERATOR:INTERNAL= -//Name of generator. -CMAKE_GENERATOR:INTERNAL=Unix Makefiles -//Generator instance identifier. -CMAKE_GENERATOR_INSTANCE:INTERNAL= -//Name of generator platform. -CMAKE_GENERATOR_PLATFORM:INTERNAL= -//Name of generator toolset. -CMAKE_GENERATOR_TOOLSET:INTERNAL= -//Source directory with the top level CMakeLists.txt file for this -// project -CMAKE_HOME_DIRECTORY:INTERNAL=/home/neo/codac/examples -//Install .so files without execute permission. -CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 -//ADVANCED property for variable: CMAKE_LINKER -CMAKE_LINKER-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MAKE_PROGRAM -CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS -CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG -CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL -CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE -CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_NM -CMAKE_NM-ADVANCED:INTERNAL=1 -//number of local generators -CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 -//ADVANCED property for variable: CMAKE_OBJCOPY -CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_OBJDUMP -CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 -//Platform information initialized -CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_RANLIB -CMAKE_RANLIB-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_READELF -CMAKE_READELF-ADVANCED:INTERNAL=1 -//Path to CMake installation. -CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.22 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS -CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG -CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL -CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE -CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH -CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_SKIP_RPATH -CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS -CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG -CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL -CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE -CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO -CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 -//ADVANCED property for variable: CMAKE_STRIP -CMAKE_STRIP-ADVANCED:INTERNAL=1 -//uname command -CMAKE_UNAME:INTERNAL=/usr/bin/uname -//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE -CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 - diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CMakeCCompiler.cmake b/examples/00_graphics/CMakeFiles/3.22.1/CMakeCCompiler.cmake deleted file mode 100644 index 488ad375..00000000 --- a/examples/00_graphics/CMakeFiles/3.22.1/CMakeCCompiler.cmake +++ /dev/null @@ -1,72 +0,0 @@ -set(CMAKE_C_COMPILER "/usr/bin/cc") -set(CMAKE_C_COMPILER_ARG1 "") -set(CMAKE_C_COMPILER_ID "GNU") -set(CMAKE_C_COMPILER_VERSION "11.4.0") -set(CMAKE_C_COMPILER_VERSION_INTERNAL "") -set(CMAKE_C_COMPILER_WRAPPER "") -set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "17") -set(CMAKE_C_EXTENSIONS_COMPUTED_DEFAULT "ON") -set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert;c_std_17;c_std_23") -set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes") -set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros") -set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert") -set(CMAKE_C17_COMPILE_FEATURES "c_std_17") -set(CMAKE_C23_COMPILE_FEATURES "c_std_23") - -set(CMAKE_C_PLATFORM_ID "Linux") -set(CMAKE_C_SIMULATE_ID "") -set(CMAKE_C_COMPILER_FRONTEND_VARIANT "") -set(CMAKE_C_SIMULATE_VERSION "") - - - - -set(CMAKE_AR "/usr/bin/ar") -set(CMAKE_C_COMPILER_AR "/usr/bin/gcc-ar-11") -set(CMAKE_RANLIB "/usr/bin/ranlib") -set(CMAKE_C_COMPILER_RANLIB "/usr/bin/gcc-ranlib-11") -set(CMAKE_LINKER "/usr/bin/ld") -set(CMAKE_MT "") -set(CMAKE_COMPILER_IS_GNUCC 1) -set(CMAKE_C_COMPILER_LOADED 1) -set(CMAKE_C_COMPILER_WORKS TRUE) -set(CMAKE_C_ABI_COMPILED TRUE) - -set(CMAKE_C_COMPILER_ENV_VAR "CC") - -set(CMAKE_C_COMPILER_ID_RUN 1) -set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m) -set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) -set(CMAKE_C_LINKER_PREFERENCE 10) - -# Save compiler ABI information. -set(CMAKE_C_SIZEOF_DATA_PTR "8") -set(CMAKE_C_COMPILER_ABI "ELF") -set(CMAKE_C_BYTE_ORDER "LITTLE_ENDIAN") -set(CMAKE_C_LIBRARY_ARCHITECTURE "x86_64-linux-gnu") - -if(CMAKE_C_SIZEOF_DATA_PTR) - set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}") -endif() - -if(CMAKE_C_COMPILER_ABI) - set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}") -endif() - -if(CMAKE_C_LIBRARY_ARCHITECTURE) - set(CMAKE_LIBRARY_ARCHITECTURE "x86_64-linux-gnu") -endif() - -set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "") -if(CMAKE_C_CL_SHOWINCLUDES_PREFIX) - set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}") -endif() - - - - - -set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/11/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include") -set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "gcc;gcc_s;c;gcc;gcc_s") -set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/11;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib") -set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake b/examples/00_graphics/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake deleted file mode 100644 index 345e9307..00000000 --- a/examples/00_graphics/CMakeFiles/3.22.1/CMakeCXXCompiler.cmake +++ /dev/null @@ -1,83 +0,0 @@ -set(CMAKE_CXX_COMPILER "/usr/bin/c++") -set(CMAKE_CXX_COMPILER_ARG1 "") -set(CMAKE_CXX_COMPILER_ID "GNU") -set(CMAKE_CXX_COMPILER_VERSION "11.4.0") -set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "") -set(CMAKE_CXX_COMPILER_WRAPPER "") -set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "17") -set(CMAKE_CXX_EXTENSIONS_COMPUTED_DEFAULT "ON") -set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20;cxx_std_23") -set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters") -set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates") -set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates") -set(CMAKE_CXX17_COMPILE_FEATURES "cxx_std_17") -set(CMAKE_CXX20_COMPILE_FEATURES "cxx_std_20") -set(CMAKE_CXX23_COMPILE_FEATURES "cxx_std_23") - -set(CMAKE_CXX_PLATFORM_ID "Linux") -set(CMAKE_CXX_SIMULATE_ID "") -set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "") -set(CMAKE_CXX_SIMULATE_VERSION "") - - - - -set(CMAKE_AR "/usr/bin/ar") -set(CMAKE_CXX_COMPILER_AR "/usr/bin/gcc-ar-11") -set(CMAKE_RANLIB "/usr/bin/ranlib") -set(CMAKE_CXX_COMPILER_RANLIB "/usr/bin/gcc-ranlib-11") -set(CMAKE_LINKER "/usr/bin/ld") -set(CMAKE_MT "") -set(CMAKE_COMPILER_IS_GNUCXX 1) -set(CMAKE_CXX_COMPILER_LOADED 1) -set(CMAKE_CXX_COMPILER_WORKS TRUE) -set(CMAKE_CXX_ABI_COMPILED TRUE) - -set(CMAKE_CXX_COMPILER_ENV_VAR "CXX") - -set(CMAKE_CXX_COMPILER_ID_RUN 1) -set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm) -set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) - -foreach (lang C OBJC OBJCXX) - if (CMAKE_${lang}_COMPILER_ID_RUN) - foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS) - list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension}) - endforeach() - endif() -endforeach() - -set(CMAKE_CXX_LINKER_PREFERENCE 30) -set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1) - -# Save compiler ABI information. -set(CMAKE_CXX_SIZEOF_DATA_PTR "8") -set(CMAKE_CXX_COMPILER_ABI "ELF") -set(CMAKE_CXX_BYTE_ORDER "LITTLE_ENDIAN") -set(CMAKE_CXX_LIBRARY_ARCHITECTURE "x86_64-linux-gnu") - -if(CMAKE_CXX_SIZEOF_DATA_PTR) - set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}") -endif() - -if(CMAKE_CXX_COMPILER_ABI) - set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}") -endif() - -if(CMAKE_CXX_LIBRARY_ARCHITECTURE) - set(CMAKE_LIBRARY_ARCHITECTURE "x86_64-linux-gnu") -endif() - -set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "") -if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX) - set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}") -endif() - - - - - -set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "/usr/include/c++/11;/usr/include/x86_64-linux-gnu/c++/11;/usr/include/c++/11/backward;/usr/lib/gcc/x86_64-linux-gnu/11/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include") -set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "stdc++;m;gcc_s;gcc;c;gcc_s;gcc") -set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/11;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib") -set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_C.bin b/examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_C.bin deleted file mode 100755 index a8dc0758bdd947d6c1b6426579ede08176cb0ecb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15968 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 diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_CXX.bin b/examples/00_graphics/CMakeFiles/3.22.1/CMakeDetermineCompilerABI_CXX.bin deleted file mode 100755 index cfa527b53452d63fe64b6a8e2d060ddc5e29a3a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15992 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 & 0x00FF) -# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) -# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) - -#elif defined(__BORLANDC__) -# define COMPILER_ID "Borland" - /* __BORLANDC__ = 0xVRR */ -# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) -# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) - -#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 -# define COMPILER_ID "Watcom" - /* __WATCOMC__ = VVRR */ -# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) -# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) -# if (__WATCOMC__ % 10) > 0 -# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) -# endif - -#elif defined(__WATCOMC__) -# define COMPILER_ID "OpenWatcom" - /* __WATCOMC__ = VVRP + 1100 */ -# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) -# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) -# if (__WATCOMC__ % 10) > 0 -# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) -# endif - -#elif defined(__SUNPRO_C) -# define COMPILER_ID "SunPro" -# if __SUNPRO_C >= 0x5100 - /* __SUNPRO_C = 0xVRRP */ -# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>12) -# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xFF) -# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) -# else - /* __SUNPRO_CC = 0xVRP */ -# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>8) -# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xF) -# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) -# endif - -#elif defined(__HP_cc) -# define COMPILER_ID "HP" - /* __HP_cc = VVRRPP */ -# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000) -# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100) -# define COMPILER_VERSION_PATCH DEC(__HP_cc % 100) - -#elif defined(__DECC) -# define COMPILER_ID "Compaq" - /* __DECC_VER = VVRRTPPPP */ -# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000) -# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000 % 100) -# define COMPILER_VERSION_PATCH DEC(__DECC_VER % 10000) - -#elif defined(__IBMC__) && defined(__COMPILER_VER__) -# define COMPILER_ID "zOS" - /* __IBMC__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) - -#elif defined(__ibmxl__) && defined(__clang__) -# define COMPILER_ID "XLClang" -# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) -# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) -# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) -# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) - - -#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800 -# define COMPILER_ID "XL" - /* __IBMC__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) - -#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ < 800 -# define COMPILER_ID "VisualAge" - /* __IBMC__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) - -#elif defined(__NVCOMPILER) -# define COMPILER_ID "NVHPC" -# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__) -# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__) -# if defined(__NVCOMPILER_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__) -# endif - -#elif defined(__PGI) -# define COMPILER_ID "PGI" -# define COMPILER_VERSION_MAJOR DEC(__PGIC__) -# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) -# if defined(__PGIC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) -# endif - -#elif defined(_CRAYC) -# define COMPILER_ID "Cray" -# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) -# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) - -#elif defined(__TI_COMPILER_VERSION__) -# define COMPILER_ID "TI" - /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ -# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) -# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) -# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) - -#elif defined(__CLANG_FUJITSU) -# define COMPILER_ID "FujitsuClang" -# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) -# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) -# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) -# define COMPILER_VERSION_INTERNAL_STR __clang_version__ - - -#elif defined(__FUJITSU) -# define COMPILER_ID "Fujitsu" -# if defined(__FCC_version__) -# define COMPILER_VERSION __FCC_version__ -# elif defined(__FCC_major__) -# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) -# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) -# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) -# endif -# if defined(__fcc_version) -# define COMPILER_VERSION_INTERNAL DEC(__fcc_version) -# elif defined(__FCC_VERSION) -# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION) -# endif - - -#elif defined(__ghs__) -# define COMPILER_ID "GHS" -/* __GHS_VERSION_NUMBER = VVVVRP */ -# ifdef __GHS_VERSION_NUMBER -# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100) -# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10) -# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10) -# endif - -#elif defined(__TINYC__) -# define COMPILER_ID "TinyCC" - -#elif defined(__BCC__) -# define COMPILER_ID "Bruce" - -#elif defined(__SCO_VERSION__) -# define COMPILER_ID "SCO" - -#elif defined(__ARMCC_VERSION) && !defined(__clang__) -# define COMPILER_ID "ARMCC" -#if __ARMCC_VERSION >= 1000000 - /* __ARMCC_VERSION = VRRPPPP */ - # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) - # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) - # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) -#else - /* __ARMCC_VERSION = VRPPPP */ - # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) - # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) - # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) -#endif - - -#elif defined(__clang__) && defined(__apple_build_version__) -# define COMPILER_ID "AppleClang" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif -# define COMPILER_VERSION_MAJOR DEC(__clang_major__) -# define COMPILER_VERSION_MINOR DEC(__clang_minor__) -# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif -# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) - -#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION) -# define COMPILER_ID "ARMClang" - # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000) - # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100) - # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000) -# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION) - -#elif defined(__clang__) -# define COMPILER_ID "Clang" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif -# define COMPILER_VERSION_MAJOR DEC(__clang_major__) -# define COMPILER_VERSION_MINOR DEC(__clang_minor__) -# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif - -#elif defined(__GNUC__) -# define COMPILER_ID "GNU" -# define COMPILER_VERSION_MAJOR DEC(__GNUC__) -# if defined(__GNUC_MINOR__) -# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) -# endif -# if defined(__GNUC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) -# endif - -#elif defined(_MSC_VER) -# define COMPILER_ID "MSVC" - /* _MSC_VER = VVRR */ -# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) -# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) -# if defined(_MSC_FULL_VER) -# if _MSC_VER >= 1400 - /* _MSC_FULL_VER = VVRRPPPPP */ -# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) -# else - /* _MSC_FULL_VER = VVRRPPPP */ -# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) -# endif -# endif -# if defined(_MSC_BUILD) -# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) -# endif - -#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) -# define COMPILER_ID "ADSP" -#if defined(__VISUALDSPVERSION__) - /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ -# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) -# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) -# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) -#endif - -#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) -# define COMPILER_ID "IAR" -# if defined(__VER__) && defined(__ICCARM__) -# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) -# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) -# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) -# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) -# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__)) -# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100) -# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100)) -# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__) -# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) -# endif - -#elif defined(__SDCC_VERSION_MAJOR) || defined(SDCC) -# define COMPILER_ID "SDCC" -# if defined(__SDCC_VERSION_MAJOR) -# define COMPILER_VERSION_MAJOR DEC(__SDCC_VERSION_MAJOR) -# define COMPILER_VERSION_MINOR DEC(__SDCC_VERSION_MINOR) -# define COMPILER_VERSION_PATCH DEC(__SDCC_VERSION_PATCH) -# else - /* SDCC = VRP */ -# define COMPILER_VERSION_MAJOR DEC(SDCC/100) -# define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10) -# define COMPILER_VERSION_PATCH DEC(SDCC % 10) -# endif - - -/* These compilers are either not known or too old to define an - identification macro. Try to identify the platform and guess that - it is the native compiler. */ -#elif defined(__hpux) || defined(__hpua) -# define COMPILER_ID "HP" - -#else /* unknown compiler */ -# define COMPILER_ID "" -#endif - -/* Construct the string literal in pieces to prevent the source from - getting matched. Store it in a pointer rather than an array - because some compilers will just produce instructions to fill the - array rather than assigning a pointer to a static array. */ -char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; -#ifdef SIMULATE_ID -char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; -#endif - -#ifdef __QNXNTO__ -char const* qnxnto = "INFO" ":" "qnxnto[]"; -#endif - -#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) -char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; -#endif - -#define STRINGIFY_HELPER(X) #X -#define STRINGIFY(X) STRINGIFY_HELPER(X) - -/* Identify known platforms by name. */ -#if defined(__linux) || defined(__linux__) || defined(linux) -# define PLATFORM_ID "Linux" - -#elif defined(__MSYS__) -# define PLATFORM_ID "MSYS" - -#elif defined(__CYGWIN__) -# define PLATFORM_ID "Cygwin" - -#elif defined(__MINGW32__) -# define PLATFORM_ID "MinGW" - -#elif defined(__APPLE__) -# define PLATFORM_ID "Darwin" - -#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) -# define PLATFORM_ID "Windows" - -#elif defined(__FreeBSD__) || defined(__FreeBSD) -# define PLATFORM_ID "FreeBSD" - -#elif defined(__NetBSD__) || defined(__NetBSD) -# define PLATFORM_ID "NetBSD" - -#elif defined(__OpenBSD__) || defined(__OPENBSD) -# define PLATFORM_ID "OpenBSD" - -#elif defined(__sun) || defined(sun) -# define PLATFORM_ID "SunOS" - -#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) -# define PLATFORM_ID "AIX" - -#elif defined(__hpux) || defined(__hpux__) -# define PLATFORM_ID "HP-UX" - -#elif defined(__HAIKU__) -# define PLATFORM_ID "Haiku" - -#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) -# define PLATFORM_ID "BeOS" - -#elif defined(__QNX__) || defined(__QNXNTO__) -# define PLATFORM_ID "QNX" - -#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) -# define PLATFORM_ID "Tru64" - -#elif defined(__riscos) || defined(__riscos__) -# define PLATFORM_ID "RISCos" - -#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) -# define PLATFORM_ID "SINIX" - -#elif defined(__UNIX_SV__) -# define PLATFORM_ID "UNIX_SV" - -#elif defined(__bsdos__) -# define PLATFORM_ID "BSDOS" - -#elif defined(_MPRAS) || defined(MPRAS) -# define PLATFORM_ID "MP-RAS" - -#elif defined(__osf) || defined(__osf__) -# define PLATFORM_ID "OSF1" - -#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) -# define PLATFORM_ID "SCO_SV" - -#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) -# define PLATFORM_ID "ULTRIX" - -#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) -# define PLATFORM_ID "Xenix" - -#elif defined(__WATCOMC__) -# if defined(__LINUX__) -# define PLATFORM_ID "Linux" - -# elif defined(__DOS__) -# define PLATFORM_ID "DOS" - -# elif defined(__OS2__) -# define PLATFORM_ID "OS2" - -# elif defined(__WINDOWS__) -# define PLATFORM_ID "Windows3x" - -# elif defined(__VXWORKS__) -# define PLATFORM_ID "VxWorks" - -# else /* unknown platform */ -# define PLATFORM_ID -# endif - -#elif defined(__INTEGRITY) -# if defined(INT_178B) -# define PLATFORM_ID "Integrity178" - -# else /* regular Integrity */ -# define PLATFORM_ID "Integrity" -# endif - -#else /* unknown platform */ -# define PLATFORM_ID - -#endif - -/* For windows compilers MSVC and Intel we can determine - the architecture of the compiler being used. This is because - the compilers do not have flags that can change the architecture, - but rather depend on which compiler is being used -*/ -#if defined(_WIN32) && defined(_MSC_VER) -# if defined(_M_IA64) -# define ARCHITECTURE_ID "IA64" - -# elif defined(_M_ARM64EC) -# define ARCHITECTURE_ID "ARM64EC" - -# elif defined(_M_X64) || defined(_M_AMD64) -# define ARCHITECTURE_ID "x64" - -# elif defined(_M_IX86) -# define ARCHITECTURE_ID "X86" - -# elif defined(_M_ARM64) -# define ARCHITECTURE_ID "ARM64" - -# elif defined(_M_ARM) -# if _M_ARM == 4 -# define ARCHITECTURE_ID "ARMV4I" -# elif _M_ARM == 5 -# define ARCHITECTURE_ID "ARMV5I" -# else -# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) -# endif - -# elif defined(_M_MIPS) -# define ARCHITECTURE_ID "MIPS" - -# elif defined(_M_SH) -# define ARCHITECTURE_ID "SHx" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__WATCOMC__) -# if defined(_M_I86) -# define ARCHITECTURE_ID "I86" - -# elif defined(_M_IX86) -# define ARCHITECTURE_ID "X86" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) -# if defined(__ICCARM__) -# define ARCHITECTURE_ID "ARM" - -# elif defined(__ICCRX__) -# define ARCHITECTURE_ID "RX" - -# elif defined(__ICCRH850__) -# define ARCHITECTURE_ID "RH850" - -# elif defined(__ICCRL78__) -# define ARCHITECTURE_ID "RL78" - -# elif defined(__ICCRISCV__) -# define ARCHITECTURE_ID "RISCV" - -# elif defined(__ICCAVR__) -# define ARCHITECTURE_ID "AVR" - -# elif defined(__ICC430__) -# define ARCHITECTURE_ID "MSP430" - -# elif defined(__ICCV850__) -# define ARCHITECTURE_ID "V850" - -# elif defined(__ICC8051__) -# define ARCHITECTURE_ID "8051" - -# elif defined(__ICCSTM8__) -# define ARCHITECTURE_ID "STM8" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__ghs__) -# if defined(__PPC64__) -# define ARCHITECTURE_ID "PPC64" - -# elif defined(__ppc__) -# define ARCHITECTURE_ID "PPC" - -# elif defined(__ARM__) -# define ARCHITECTURE_ID "ARM" - -# elif defined(__x86_64__) -# define ARCHITECTURE_ID "x64" - -# elif defined(__i386__) -# define ARCHITECTURE_ID "X86" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__TI_COMPILER_VERSION__) -# if defined(__TI_ARM__) -# define ARCHITECTURE_ID "ARM" - -# elif defined(__MSP430__) -# define ARCHITECTURE_ID "MSP430" - -# elif defined(__TMS320C28XX__) -# define ARCHITECTURE_ID "TMS320C28x" - -# elif defined(__TMS320C6X__) || defined(_TMS320C6X) -# define ARCHITECTURE_ID "TMS320C6x" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#else -# define ARCHITECTURE_ID -#endif - -/* Convert integer to decimal digit literals. */ -#define DEC(n) \ - ('0' + (((n) / 10000000)%10)), \ - ('0' + (((n) / 1000000)%10)), \ - ('0' + (((n) / 100000)%10)), \ - ('0' + (((n) / 10000)%10)), \ - ('0' + (((n) / 1000)%10)), \ - ('0' + (((n) / 100)%10)), \ - ('0' + (((n) / 10)%10)), \ - ('0' + ((n) % 10)) - -/* Convert integer to hex digit literals. */ -#define HEX(n) \ - ('0' + ((n)>>28 & 0xF)), \ - ('0' + ((n)>>24 & 0xF)), \ - ('0' + ((n)>>20 & 0xF)), \ - ('0' + ((n)>>16 & 0xF)), \ - ('0' + ((n)>>12 & 0xF)), \ - ('0' + ((n)>>8 & 0xF)), \ - ('0' + ((n)>>4 & 0xF)), \ - ('0' + ((n) & 0xF)) - -/* Construct a string literal encoding the version number. */ -#ifdef COMPILER_VERSION -char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]"; - -/* Construct a string literal encoding the version number components. */ -#elif defined(COMPILER_VERSION_MAJOR) -char const info_version[] = { - 'I', 'N', 'F', 'O', ':', - 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', - COMPILER_VERSION_MAJOR, -# ifdef COMPILER_VERSION_MINOR - '.', COMPILER_VERSION_MINOR, -# ifdef COMPILER_VERSION_PATCH - '.', COMPILER_VERSION_PATCH, -# ifdef COMPILER_VERSION_TWEAK - '.', COMPILER_VERSION_TWEAK, -# endif -# endif -# endif - ']','\0'}; -#endif - -/* Construct a string literal encoding the internal version number. */ -#ifdef COMPILER_VERSION_INTERNAL -char const info_version_internal[] = { - 'I', 'N', 'F', 'O', ':', - 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', - 'i','n','t','e','r','n','a','l','[', - COMPILER_VERSION_INTERNAL,']','\0'}; -#elif defined(COMPILER_VERSION_INTERNAL_STR) -char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]"; -#endif - -/* Construct a string literal encoding the version number components. */ -#ifdef SIMULATE_VERSION_MAJOR -char const info_simulate_version[] = { - 'I', 'N', 'F', 'O', ':', - 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', - SIMULATE_VERSION_MAJOR, -# ifdef SIMULATE_VERSION_MINOR - '.', SIMULATE_VERSION_MINOR, -# ifdef SIMULATE_VERSION_PATCH - '.', SIMULATE_VERSION_PATCH, -# ifdef SIMULATE_VERSION_TWEAK - '.', SIMULATE_VERSION_TWEAK, -# endif -# endif -# endif - ']','\0'}; -#endif - -/* Construct the string literal in pieces to prevent the source from - getting matched. Store it in a pointer rather than an array - because some compilers will just produce instructions to fill the - array rather than assigning a pointer to a static array. */ -char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; -char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; - - - -#if !defined(__STDC__) && !defined(__clang__) -# if defined(_MSC_VER) || defined(__ibmxl__) || defined(__IBMC__) -# define C_VERSION "90" -# else -# define C_VERSION -# endif -#elif __STDC_VERSION__ > 201710L -# define C_VERSION "23" -#elif __STDC_VERSION__ >= 201710L -# define C_VERSION "17" -#elif __STDC_VERSION__ >= 201000L -# define C_VERSION "11" -#elif __STDC_VERSION__ >= 199901L -# define C_VERSION "99" -#else -# define C_VERSION "90" -#endif -const char* info_language_standard_default = - "INFO" ":" "standard_default[" C_VERSION "]"; - -const char* info_language_extensions_default = "INFO" ":" "extensions_default[" -/* !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode. */ -#if (defined(__clang__) || defined(__GNUC__) || \ - defined(__TI_COMPILER_VERSION__)) && \ - !defined(__STRICT_ANSI__) && !defined(_MSC_VER) - "ON" -#else - "OFF" -#endif -"]"; - -/*--------------------------------------------------------------------------*/ - -#ifdef ID_VOID_MAIN -void main() {} -#else -# if defined(__CLASSIC_C__) -int main(argc, argv) int argc; char *argv[]; -# else -int main(int argc, char* argv[]) -# endif -{ - int require = 0; - require += info_compiler[argc]; - require += info_platform[argc]; - require += info_arch[argc]; -#ifdef COMPILER_VERSION_MAJOR - require += info_version[argc]; -#endif -#ifdef COMPILER_VERSION_INTERNAL - require += info_version_internal[argc]; -#endif -#ifdef SIMULATE_ID - require += info_simulate[argc]; -#endif -#ifdef SIMULATE_VERSION_MAJOR - require += info_simulate_version[argc]; -#endif -#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) - require += info_cray[argc]; -#endif - require += info_language_standard_default[argc]; - require += info_language_extensions_default[argc]; - (void)argv; - return require; -} -#endif diff --git a/examples/00_graphics/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp b/examples/00_graphics/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp deleted file mode 100644 index 25c62a8c..00000000 --- a/examples/00_graphics/CMakeFiles/3.22.1/CompilerIdCXX/CMakeCXXCompilerId.cpp +++ /dev/null @@ -1,791 +0,0 @@ -/* This source file must have a .cpp extension so that all C++ compilers - recognize the extension without flags. Borland does not know .cxx for - example. */ -#ifndef __cplusplus -# error "A C compiler has been selected for C++." -#endif - -#if !defined(__has_include) -/* If the compiler does not have __has_include, pretend the answer is - always no. */ -# define __has_include(x) 0 -#endif - - -/* Version number components: V=Version, R=Revision, P=Patch - Version date components: YYYY=Year, MM=Month, DD=Day */ - -#if defined(__COMO__) -# define COMPILER_ID "Comeau" - /* __COMO_VERSION__ = VRR */ -# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100) -# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100) - -#elif defined(__INTEL_COMPILER) || defined(__ICC) -# define COMPILER_ID "Intel" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif -# if defined(__GNUC__) -# define SIMULATE_ID "GNU" -# endif - /* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later, - except that a few beta releases use the old format with V=2021. */ -# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111 -# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) -# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) -# if defined(__INTEL_COMPILER_UPDATE) -# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) -# else -# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) -# endif -# else -# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER) -# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE) - /* The third version component from --version is an update index, - but no macro is provided for it. */ -# define COMPILER_VERSION_PATCH DEC(0) -# endif -# if defined(__INTEL_COMPILER_BUILD_DATE) - /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ -# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) -# endif -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif -# if defined(__GNUC__) -# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) -# elif defined(__GNUG__) -# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) -# endif -# if defined(__GNUC_MINOR__) -# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) -# endif -# if defined(__GNUC_PATCHLEVEL__) -# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) -# endif - -#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER) -# define COMPILER_ID "IntelLLVM" -#if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -#endif -#if defined(__GNUC__) -# define SIMULATE_ID "GNU" -#endif -/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and - * later. Look for 6 digit vs. 8 digit version number to decide encoding. - * VVVV is no smaller than the current year when a version is released. - */ -#if __INTEL_LLVM_COMPILER < 1000000L -# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100) -# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 10) -#else -# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000) -# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100) -# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER % 100) -#endif -#if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -#endif -#if defined(__GNUC__) -# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) -#elif defined(__GNUG__) -# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) -#endif -#if defined(__GNUC_MINOR__) -# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) -#endif -#if defined(__GNUC_PATCHLEVEL__) -# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) -#endif - -#elif defined(__PATHCC__) -# define COMPILER_ID "PathScale" -# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) -# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) -# if defined(__PATHCC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) -# endif - -#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) -# define COMPILER_ID "Embarcadero" -# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) -# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) -# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) - -#elif defined(__BORLANDC__) -# define COMPILER_ID "Borland" - /* __BORLANDC__ = 0xVRR */ -# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) -# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) - -#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 -# define COMPILER_ID "Watcom" - /* __WATCOMC__ = VVRR */ -# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) -# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) -# if (__WATCOMC__ % 10) > 0 -# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) -# endif - -#elif defined(__WATCOMC__) -# define COMPILER_ID "OpenWatcom" - /* __WATCOMC__ = VVRP + 1100 */ -# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) -# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) -# if (__WATCOMC__ % 10) > 0 -# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) -# endif - -#elif defined(__SUNPRO_CC) -# define COMPILER_ID "SunPro" -# if __SUNPRO_CC >= 0x5100 - /* __SUNPRO_CC = 0xVRRP */ -# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) -# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) -# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) -# else - /* __SUNPRO_CC = 0xVRP */ -# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) -# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) -# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) -# endif - -#elif defined(__HP_aCC) -# define COMPILER_ID "HP" - /* __HP_aCC = VVRRPP */ -# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) -# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) -# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) - -#elif defined(__DECCXX) -# define COMPILER_ID "Compaq" - /* __DECCXX_VER = VVRRTPPPP */ -# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) -# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) -# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) - -#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) -# define COMPILER_ID "zOS" - /* __IBMCPP__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) - -#elif defined(__ibmxl__) && defined(__clang__) -# define COMPILER_ID "XLClang" -# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) -# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) -# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) -# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) - - -#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800 -# define COMPILER_ID "XL" - /* __IBMCPP__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) - -#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800 -# define COMPILER_ID "VisualAge" - /* __IBMCPP__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) - -#elif defined(__NVCOMPILER) -# define COMPILER_ID "NVHPC" -# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__) -# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__) -# if defined(__NVCOMPILER_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__) -# endif - -#elif defined(__PGI) -# define COMPILER_ID "PGI" -# define COMPILER_VERSION_MAJOR DEC(__PGIC__) -# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) -# if defined(__PGIC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) -# endif - -#elif defined(_CRAYC) -# define COMPILER_ID "Cray" -# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) -# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) - -#elif defined(__TI_COMPILER_VERSION__) -# define COMPILER_ID "TI" - /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ -# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) -# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) -# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) - -#elif defined(__CLANG_FUJITSU) -# define COMPILER_ID "FujitsuClang" -# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) -# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) -# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) -# define COMPILER_VERSION_INTERNAL_STR __clang_version__ - - -#elif defined(__FUJITSU) -# define COMPILER_ID "Fujitsu" -# if defined(__FCC_version__) -# define COMPILER_VERSION __FCC_version__ -# elif defined(__FCC_major__) -# define COMPILER_VERSION_MAJOR DEC(__FCC_major__) -# define COMPILER_VERSION_MINOR DEC(__FCC_minor__) -# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__) -# endif -# if defined(__fcc_version) -# define COMPILER_VERSION_INTERNAL DEC(__fcc_version) -# elif defined(__FCC_VERSION) -# define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION) -# endif - - -#elif defined(__ghs__) -# define COMPILER_ID "GHS" -/* __GHS_VERSION_NUMBER = VVVVRP */ -# ifdef __GHS_VERSION_NUMBER -# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100) -# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10) -# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10) -# endif - -#elif defined(__SCO_VERSION__) -# define COMPILER_ID "SCO" - -#elif defined(__ARMCC_VERSION) && !defined(__clang__) -# define COMPILER_ID "ARMCC" -#if __ARMCC_VERSION >= 1000000 - /* __ARMCC_VERSION = VRRPPPP */ - # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) - # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) - # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) -#else - /* __ARMCC_VERSION = VRPPPP */ - # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) - # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) - # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) -#endif - - -#elif defined(__clang__) && defined(__apple_build_version__) -# define COMPILER_ID "AppleClang" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif -# define COMPILER_VERSION_MAJOR DEC(__clang_major__) -# define COMPILER_VERSION_MINOR DEC(__clang_minor__) -# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif -# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) - -#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION) -# define COMPILER_ID "ARMClang" - # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000) - # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100) - # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000) -# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION) - -#elif defined(__clang__) -# define COMPILER_ID "Clang" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif -# define COMPILER_VERSION_MAJOR DEC(__clang_major__) -# define COMPILER_VERSION_MINOR DEC(__clang_minor__) -# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif - -#elif defined(__GNUC__) || defined(__GNUG__) -# define COMPILER_ID "GNU" -# if defined(__GNUC__) -# define COMPILER_VERSION_MAJOR DEC(__GNUC__) -# else -# define COMPILER_VERSION_MAJOR DEC(__GNUG__) -# endif -# if defined(__GNUC_MINOR__) -# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) -# endif -# if defined(__GNUC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) -# endif - -#elif defined(_MSC_VER) -# define COMPILER_ID "MSVC" - /* _MSC_VER = VVRR */ -# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) -# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) -# if defined(_MSC_FULL_VER) -# if _MSC_VER >= 1400 - /* _MSC_FULL_VER = VVRRPPPPP */ -# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) -# else - /* _MSC_FULL_VER = VVRRPPPP */ -# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) -# endif -# endif -# if defined(_MSC_BUILD) -# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) -# endif - -#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) -# define COMPILER_ID "ADSP" -#if defined(__VISUALDSPVERSION__) - /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ -# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) -# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) -# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) -#endif - -#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) -# define COMPILER_ID "IAR" -# if defined(__VER__) && defined(__ICCARM__) -# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) -# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) -# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) -# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) -# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__)) -# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100) -# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100)) -# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__) -# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) -# endif - - -/* These compilers are either not known or too old to define an - identification macro. Try to identify the platform and guess that - it is the native compiler. */ -#elif defined(__hpux) || defined(__hpua) -# define COMPILER_ID "HP" - -#else /* unknown compiler */ -# define COMPILER_ID "" -#endif - -/* Construct the string literal in pieces to prevent the source from - getting matched. Store it in a pointer rather than an array - because some compilers will just produce instructions to fill the - array rather than assigning a pointer to a static array. */ -char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; -#ifdef SIMULATE_ID -char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; -#endif - -#ifdef __QNXNTO__ -char const* qnxnto = "INFO" ":" "qnxnto[]"; -#endif - -#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) -char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; -#endif - -#define STRINGIFY_HELPER(X) #X -#define STRINGIFY(X) STRINGIFY_HELPER(X) - -/* Identify known platforms by name. */ -#if defined(__linux) || defined(__linux__) || defined(linux) -# define PLATFORM_ID "Linux" - -#elif defined(__MSYS__) -# define PLATFORM_ID "MSYS" - -#elif defined(__CYGWIN__) -# define PLATFORM_ID "Cygwin" - -#elif defined(__MINGW32__) -# define PLATFORM_ID "MinGW" - -#elif defined(__APPLE__) -# define PLATFORM_ID "Darwin" - -#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) -# define PLATFORM_ID "Windows" - -#elif defined(__FreeBSD__) || defined(__FreeBSD) -# define PLATFORM_ID "FreeBSD" - -#elif defined(__NetBSD__) || defined(__NetBSD) -# define PLATFORM_ID "NetBSD" - -#elif defined(__OpenBSD__) || defined(__OPENBSD) -# define PLATFORM_ID "OpenBSD" - -#elif defined(__sun) || defined(sun) -# define PLATFORM_ID "SunOS" - -#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) -# define PLATFORM_ID "AIX" - -#elif defined(__hpux) || defined(__hpux__) -# define PLATFORM_ID "HP-UX" - -#elif defined(__HAIKU__) -# define PLATFORM_ID "Haiku" - -#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) -# define PLATFORM_ID "BeOS" - -#elif defined(__QNX__) || defined(__QNXNTO__) -# define PLATFORM_ID "QNX" - -#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) -# define PLATFORM_ID "Tru64" - -#elif defined(__riscos) || defined(__riscos__) -# define PLATFORM_ID "RISCos" - -#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) -# define PLATFORM_ID "SINIX" - -#elif defined(__UNIX_SV__) -# define PLATFORM_ID "UNIX_SV" - -#elif defined(__bsdos__) -# define PLATFORM_ID "BSDOS" - -#elif defined(_MPRAS) || defined(MPRAS) -# define PLATFORM_ID "MP-RAS" - -#elif defined(__osf) || defined(__osf__) -# define PLATFORM_ID "OSF1" - -#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) -# define PLATFORM_ID "SCO_SV" - -#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) -# define PLATFORM_ID "ULTRIX" - -#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) -# define PLATFORM_ID "Xenix" - -#elif defined(__WATCOMC__) -# if defined(__LINUX__) -# define PLATFORM_ID "Linux" - -# elif defined(__DOS__) -# define PLATFORM_ID "DOS" - -# elif defined(__OS2__) -# define PLATFORM_ID "OS2" - -# elif defined(__WINDOWS__) -# define PLATFORM_ID "Windows3x" - -# elif defined(__VXWORKS__) -# define PLATFORM_ID "VxWorks" - -# else /* unknown platform */ -# define PLATFORM_ID -# endif - -#elif defined(__INTEGRITY) -# if defined(INT_178B) -# define PLATFORM_ID "Integrity178" - -# else /* regular Integrity */ -# define PLATFORM_ID "Integrity" -# endif - -#else /* unknown platform */ -# define PLATFORM_ID - -#endif - -/* For windows compilers MSVC and Intel we can determine - the architecture of the compiler being used. This is because - the compilers do not have flags that can change the architecture, - but rather depend on which compiler is being used -*/ -#if defined(_WIN32) && defined(_MSC_VER) -# if defined(_M_IA64) -# define ARCHITECTURE_ID "IA64" - -# elif defined(_M_ARM64EC) -# define ARCHITECTURE_ID "ARM64EC" - -# elif defined(_M_X64) || defined(_M_AMD64) -# define ARCHITECTURE_ID "x64" - -# elif defined(_M_IX86) -# define ARCHITECTURE_ID "X86" - -# elif defined(_M_ARM64) -# define ARCHITECTURE_ID "ARM64" - -# elif defined(_M_ARM) -# if _M_ARM == 4 -# define ARCHITECTURE_ID "ARMV4I" -# elif _M_ARM == 5 -# define ARCHITECTURE_ID "ARMV5I" -# else -# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) -# endif - -# elif defined(_M_MIPS) -# define ARCHITECTURE_ID "MIPS" - -# elif defined(_M_SH) -# define ARCHITECTURE_ID "SHx" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__WATCOMC__) -# if defined(_M_I86) -# define ARCHITECTURE_ID "I86" - -# elif defined(_M_IX86) -# define ARCHITECTURE_ID "X86" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) -# if defined(__ICCARM__) -# define ARCHITECTURE_ID "ARM" - -# elif defined(__ICCRX__) -# define ARCHITECTURE_ID "RX" - -# elif defined(__ICCRH850__) -# define ARCHITECTURE_ID "RH850" - -# elif defined(__ICCRL78__) -# define ARCHITECTURE_ID "RL78" - -# elif defined(__ICCRISCV__) -# define ARCHITECTURE_ID "RISCV" - -# elif defined(__ICCAVR__) -# define ARCHITECTURE_ID "AVR" - -# elif defined(__ICC430__) -# define ARCHITECTURE_ID "MSP430" - -# elif defined(__ICCV850__) -# define ARCHITECTURE_ID "V850" - -# elif defined(__ICC8051__) -# define ARCHITECTURE_ID "8051" - -# elif defined(__ICCSTM8__) -# define ARCHITECTURE_ID "STM8" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__ghs__) -# if defined(__PPC64__) -# define ARCHITECTURE_ID "PPC64" - -# elif defined(__ppc__) -# define ARCHITECTURE_ID "PPC" - -# elif defined(__ARM__) -# define ARCHITECTURE_ID "ARM" - -# elif defined(__x86_64__) -# define ARCHITECTURE_ID "x64" - -# elif defined(__i386__) -# define ARCHITECTURE_ID "X86" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__TI_COMPILER_VERSION__) -# if defined(__TI_ARM__) -# define ARCHITECTURE_ID "ARM" - -# elif defined(__MSP430__) -# define ARCHITECTURE_ID "MSP430" - -# elif defined(__TMS320C28XX__) -# define ARCHITECTURE_ID "TMS320C28x" - -# elif defined(__TMS320C6X__) || defined(_TMS320C6X) -# define ARCHITECTURE_ID "TMS320C6x" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#else -# define ARCHITECTURE_ID -#endif - -/* Convert integer to decimal digit literals. */ -#define DEC(n) \ - ('0' + (((n) / 10000000)%10)), \ - ('0' + (((n) / 1000000)%10)), \ - ('0' + (((n) / 100000)%10)), \ - ('0' + (((n) / 10000)%10)), \ - ('0' + (((n) / 1000)%10)), \ - ('0' + (((n) / 100)%10)), \ - ('0' + (((n) / 10)%10)), \ - ('0' + ((n) % 10)) - -/* Convert integer to hex digit literals. */ -#define HEX(n) \ - ('0' + ((n)>>28 & 0xF)), \ - ('0' + ((n)>>24 & 0xF)), \ - ('0' + ((n)>>20 & 0xF)), \ - ('0' + ((n)>>16 & 0xF)), \ - ('0' + ((n)>>12 & 0xF)), \ - ('0' + ((n)>>8 & 0xF)), \ - ('0' + ((n)>>4 & 0xF)), \ - ('0' + ((n) & 0xF)) - -/* Construct a string literal encoding the version number. */ -#ifdef COMPILER_VERSION -char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]"; - -/* Construct a string literal encoding the version number components. */ -#elif defined(COMPILER_VERSION_MAJOR) -char const info_version[] = { - 'I', 'N', 'F', 'O', ':', - 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', - COMPILER_VERSION_MAJOR, -# ifdef COMPILER_VERSION_MINOR - '.', COMPILER_VERSION_MINOR, -# ifdef COMPILER_VERSION_PATCH - '.', COMPILER_VERSION_PATCH, -# ifdef COMPILER_VERSION_TWEAK - '.', COMPILER_VERSION_TWEAK, -# endif -# endif -# endif - ']','\0'}; -#endif - -/* Construct a string literal encoding the internal version number. */ -#ifdef COMPILER_VERSION_INTERNAL -char const info_version_internal[] = { - 'I', 'N', 'F', 'O', ':', - 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', - 'i','n','t','e','r','n','a','l','[', - COMPILER_VERSION_INTERNAL,']','\0'}; -#elif defined(COMPILER_VERSION_INTERNAL_STR) -char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]"; -#endif - -/* Construct a string literal encoding the version number components. */ -#ifdef SIMULATE_VERSION_MAJOR -char const info_simulate_version[] = { - 'I', 'N', 'F', 'O', ':', - 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', - SIMULATE_VERSION_MAJOR, -# ifdef SIMULATE_VERSION_MINOR - '.', SIMULATE_VERSION_MINOR, -# ifdef SIMULATE_VERSION_PATCH - '.', SIMULATE_VERSION_PATCH, -# ifdef SIMULATE_VERSION_TWEAK - '.', SIMULATE_VERSION_TWEAK, -# endif -# endif -# endif - ']','\0'}; -#endif - -/* Construct the string literal in pieces to prevent the source from - getting matched. Store it in a pointer rather than an array - because some compilers will just produce instructions to fill the - array rather than assigning a pointer to a static array. */ -char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; -char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; - - - -#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L -# if defined(__INTEL_CXX11_MODE__) -# if defined(__cpp_aggregate_nsdmi) -# define CXX_STD 201402L -# else -# define CXX_STD 201103L -# endif -# else -# define CXX_STD 199711L -# endif -#elif defined(_MSC_VER) && defined(_MSVC_LANG) -# define CXX_STD _MSVC_LANG -#else -# define CXX_STD __cplusplus -#endif - -const char* info_language_standard_default = "INFO" ":" "standard_default[" -#if CXX_STD > 202002L - "23" -#elif CXX_STD > 201703L - "20" -#elif CXX_STD >= 201703L - "17" -#elif CXX_STD >= 201402L - "14" -#elif CXX_STD >= 201103L - "11" -#else - "98" -#endif -"]"; - -const char* info_language_extensions_default = "INFO" ":" "extensions_default[" -/* !defined(_MSC_VER) to exclude Clang's MSVC compatibility mode. */ -#if (defined(__clang__) || defined(__GNUC__) || \ - defined(__TI_COMPILER_VERSION__)) && \ - !defined(__STRICT_ANSI__) && !defined(_MSC_VER) - "ON" -#else - "OFF" -#endif -"]"; - -/*--------------------------------------------------------------------------*/ - -int main(int argc, char* argv[]) -{ - int require = 0; - require += info_compiler[argc]; - require += info_platform[argc]; -#ifdef COMPILER_VERSION_MAJOR - require += info_version[argc]; -#endif -#ifdef COMPILER_VERSION_INTERNAL - require += info_version_internal[argc]; -#endif -#ifdef SIMULATE_ID - require += info_simulate[argc]; -#endif -#ifdef SIMULATE_VERSION_MAJOR - require += info_simulate_version[argc]; -#endif -#if defined(__CRAYXT_COMPUTE_LINUX_TARGET) - require += info_cray[argc]; -#endif - require += info_language_standard_default[argc]; - require += info_language_extensions_default[argc]; - (void)argv; - return require; -} diff --git a/examples/00_graphics/CMakeFiles/CMakeDirectoryInformation.cmake b/examples/00_graphics/CMakeFiles/CMakeDirectoryInformation.cmake deleted file mode 100644 index c92a10b9..00000000 --- a/examples/00_graphics/CMakeFiles/CMakeDirectoryInformation.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.22 - -# Relative path conversion top directories. -set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/neo/codac/examples") -set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/neo/codac/examples/00_graphics") - -# Force unix paths in dependencies. -set(CMAKE_FORCE_UNIX_PATHS 1) - - -# The C and CXX include file regular expressions for this directory. -set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") -set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") -set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) -set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/examples/00_graphics/CMakeFiles/Makefile.cmake b/examples/00_graphics/CMakeFiles/Makefile.cmake deleted file mode 100644 index fbd61b2d..00000000 --- a/examples/00_graphics/CMakeFiles/Makefile.cmake +++ /dev/null @@ -1,121 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.22 - -# The generator used is: -set(CMAKE_DEPENDS_GENERATOR "Unix Makefiles") - -# The top level Makefile was generated from the following files: -set(CMAKE_MAKEFILE_DEPENDS - "CMakeCache.txt" - "CMakeFiles/3.22.1/CMakeCCompiler.cmake" - "CMakeFiles/3.22.1/CMakeCXXCompiler.cmake" - "CMakeFiles/3.22.1/CMakeSystem.cmake" - "../CMakeLists.txt" - "/usr/share/cmake-3.22/Modules/CMakeCCompiler.cmake.in" - "/usr/share/cmake-3.22/Modules/CMakeCCompilerABI.c" - "/usr/share/cmake-3.22/Modules/CMakeCInformation.cmake" - "/usr/share/cmake-3.22/Modules/CMakeCXXCompiler.cmake.in" - "/usr/share/cmake-3.22/Modules/CMakeCXXCompilerABI.cpp" - "/usr/share/cmake-3.22/Modules/CMakeCXXInformation.cmake" - "/usr/share/cmake-3.22/Modules/CMakeCommonLanguageInclude.cmake" - "/usr/share/cmake-3.22/Modules/CMakeCompilerIdDetection.cmake" - "/usr/share/cmake-3.22/Modules/CMakeDetermineCCompiler.cmake" - "/usr/share/cmake-3.22/Modules/CMakeDetermineCXXCompiler.cmake" - "/usr/share/cmake-3.22/Modules/CMakeDetermineCompileFeatures.cmake" - "/usr/share/cmake-3.22/Modules/CMakeDetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/CMakeDetermineCompilerABI.cmake" - "/usr/share/cmake-3.22/Modules/CMakeDetermineCompilerId.cmake" - "/usr/share/cmake-3.22/Modules/CMakeDetermineSystem.cmake" - "/usr/share/cmake-3.22/Modules/CMakeFindBinUtils.cmake" - "/usr/share/cmake-3.22/Modules/CMakeGenericSystem.cmake" - "/usr/share/cmake-3.22/Modules/CMakeInitializeConfigs.cmake" - "/usr/share/cmake-3.22/Modules/CMakeLanguageInformation.cmake" - "/usr/share/cmake-3.22/Modules/CMakeParseImplicitIncludeInfo.cmake" - "/usr/share/cmake-3.22/Modules/CMakeParseImplicitLinkInfo.cmake" - "/usr/share/cmake-3.22/Modules/CMakeParseLibraryArchitecture.cmake" - "/usr/share/cmake-3.22/Modules/CMakeSystem.cmake.in" - "/usr/share/cmake-3.22/Modules/CMakeSystemSpecificInformation.cmake" - "/usr/share/cmake-3.22/Modules/CMakeSystemSpecificInitialize.cmake" - "/usr/share/cmake-3.22/Modules/CMakeTestCCompiler.cmake" - "/usr/share/cmake-3.22/Modules/CMakeTestCXXCompiler.cmake" - "/usr/share/cmake-3.22/Modules/CMakeTestCompilerCommon.cmake" - "/usr/share/cmake-3.22/Modules/CMakeUnixFindMake.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/ADSP-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/ARMCC-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/ARMClang-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/AppleClang-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Borland-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Bruce-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/CMakeCommonCompilerMacros.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Clang-DetermineCompilerInternal.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Comeau-CXX-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Compaq-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Cray-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Embarcadero-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Fujitsu-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/GHS-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/GNU-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/GNU-C.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/GNU-CXX.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/GNU-FindBinUtils.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/GNU.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/HP-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/HP-CXX-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/IAR-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Intel-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/MSVC-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/NVHPC-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/NVIDIA-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/PGI-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/PathScale-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/SCO-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/SDCC-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/SunPro-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/TI-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/Watcom-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/XL-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/XL-CXX-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/XLClang-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/zOS-C-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake" - "/usr/share/cmake-3.22/Modules/Internal/FeatureTesting.cmake" - "/usr/share/cmake-3.22/Modules/Platform/Linux-Determine-CXX.cmake" - "/usr/share/cmake-3.22/Modules/Platform/Linux-GNU-C.cmake" - "/usr/share/cmake-3.22/Modules/Platform/Linux-GNU-CXX.cmake" - "/usr/share/cmake-3.22/Modules/Platform/Linux-GNU.cmake" - "/usr/share/cmake-3.22/Modules/Platform/Linux.cmake" - "/usr/share/cmake-3.22/Modules/Platform/UnixPaths.cmake" - ) - -# The corresponding makefile is: -set(CMAKE_MAKEFILE_OUTPUTS - "Makefile" - "CMakeFiles/cmake.check_cache" - ) - -# Byproducts of CMake generate step: -set(CMAKE_MAKEFILE_PRODUCTS - "CMakeFiles/3.22.1/CMakeSystem.cmake" - "CMakeFiles/3.22.1/CMakeCCompiler.cmake" - "CMakeFiles/3.22.1/CMakeCXXCompiler.cmake" - "CMakeFiles/3.22.1/CMakeCCompiler.cmake" - "CMakeFiles/3.22.1/CMakeCXXCompiler.cmake" - "CMakeFiles/CMakeDirectoryInformation.cmake" - ) - -# Dependency information for all targets: -set(CMAKE_DEPEND_INFO_FILES - ) diff --git a/examples/00_graphics/CMakeFiles/Makefile2 b/examples/00_graphics/CMakeFiles/Makefile2 deleted file mode 100644 index 51210666..00000000 --- a/examples/00_graphics/CMakeFiles/Makefile2 +++ /dev/null @@ -1,86 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.22 - -# Default target executed when no arguments are given to make. -default_target: all -.PHONY : default_target - -#============================================================================= -# Special targets provided by cmake. - -# Disable implicit rules so canonical targets will work. -.SUFFIXES: - -# Disable VCS-based implicit rules. -% : %,v - -# Disable VCS-based implicit rules. -% : RCS/% - -# Disable VCS-based implicit rules. -% : RCS/%,v - -# Disable VCS-based implicit rules. -% : SCCS/s.% - -# Disable VCS-based implicit rules. -% : s.% - -.SUFFIXES: .hpux_make_needs_suffix_list - -# Command-line flag to silence nested $(MAKE). -$(VERBOSE)MAKESILENT = -s - -#Suppress display of executed commands. -$(VERBOSE).SILENT: - -# A target that is always out of date. -cmake_force: -.PHONY : cmake_force - -#============================================================================= -# Set environment variables for the build. - -# The shell in which to execute make rules. -SHELL = /bin/sh - -# The CMake executable. -CMAKE_COMMAND = /usr/bin/cmake - -# The command to remove a file. -RM = /usr/bin/cmake -E rm -f - -# Escaping for special characters. -EQUALS = = - -# The top-level source directory on which CMake was run. -CMAKE_SOURCE_DIR = /home/neo/codac/examples - -# The top-level build directory on which CMake was run. -CMAKE_BINARY_DIR = /home/neo/codac/examples/00_graphics - -#============================================================================= -# Directory level rules for the build root directory - -# The main recursive "all" target. -all: -.PHONY : all - -# The main recursive "preinstall" target. -preinstall: -.PHONY : preinstall - -# The main recursive "clean" target. -clean: -.PHONY : clean - -#============================================================================= -# Special targets to cleanup operation of make. - -# Special rule to run CMake to check the build system integrity. -# No rule that depends on this can have commands that come from listfiles -# because they might be regenerated. -cmake_check_build_system: - $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 -.PHONY : cmake_check_build_system - diff --git a/examples/00_graphics/CMakeFiles/TargetDirectories.txt b/examples/00_graphics/CMakeFiles/TargetDirectories.txt deleted file mode 100644 index 68996981..00000000 --- a/examples/00_graphics/CMakeFiles/TargetDirectories.txt +++ /dev/null @@ -1,2 +0,0 @@ -/home/neo/codac/examples/00_graphics/CMakeFiles/edit_cache.dir -/home/neo/codac/examples/00_graphics/CMakeFiles/rebuild_cache.dir diff --git a/examples/00_graphics/CMakeFiles/cmake.check_cache b/examples/00_graphics/CMakeFiles/cmake.check_cache deleted file mode 100644 index 3dccd731..00000000 --- a/examples/00_graphics/CMakeFiles/cmake.check_cache +++ /dev/null @@ -1 +0,0 @@ -# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/examples/00_graphics/CMakeFiles/progress.marks b/examples/00_graphics/CMakeFiles/progress.marks deleted file mode 100644 index 573541ac..00000000 --- a/examples/00_graphics/CMakeFiles/progress.marks +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/examples/00_graphics/Makefile b/examples/00_graphics/Makefile deleted file mode 100644 index 093c9a05..00000000 --- a/examples/00_graphics/Makefile +++ /dev/null @@ -1,140 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.22 - -# Default target executed when no arguments are given to make. -default_target: all -.PHONY : default_target - -# Allow only one "make -f Makefile2" at a time, but pass parallelism. -.NOTPARALLEL: - -#============================================================================= -# Special targets provided by cmake. - -# Disable implicit rules so canonical targets will work. -.SUFFIXES: - -# Disable VCS-based implicit rules. -% : %,v - -# Disable VCS-based implicit rules. -% : RCS/% - -# Disable VCS-based implicit rules. -% : RCS/%,v - -# Disable VCS-based implicit rules. -% : SCCS/s.% - -# Disable VCS-based implicit rules. -% : s.% - -.SUFFIXES: .hpux_make_needs_suffix_list - -# Command-line flag to silence nested $(MAKE). -$(VERBOSE)MAKESILENT = -s - -#Suppress display of executed commands. -$(VERBOSE).SILENT: - -# A target that is always out of date. -cmake_force: -.PHONY : cmake_force - -#============================================================================= -# Set environment variables for the build. - -# The shell in which to execute make rules. -SHELL = /bin/sh - -# The CMake executable. -CMAKE_COMMAND = /usr/bin/cmake - -# The command to remove a file. -RM = /usr/bin/cmake -E rm -f - -# Escaping for special characters. -EQUALS = = - -# The top-level source directory on which CMake was run. -CMAKE_SOURCE_DIR = /home/neo/codac/examples - -# The top-level build directory on which CMake was run. -CMAKE_BINARY_DIR = /home/neo/codac/examples/00_graphics - -#============================================================================= -# Targets provided globally by CMake. - -# Special rule for the target edit_cache -edit_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." - /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. -.PHONY : edit_cache - -# Special rule for the target edit_cache -edit_cache/fast: edit_cache -.PHONY : edit_cache/fast - -# Special rule for the target rebuild_cache -rebuild_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." - /usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -.PHONY : rebuild_cache - -# Special rule for the target rebuild_cache -rebuild_cache/fast: rebuild_cache -.PHONY : rebuild_cache/fast - -# The main all target -all: cmake_check_build_system - $(CMAKE_COMMAND) -E cmake_progress_start /home/neo/codac/examples/00_graphics/CMakeFiles /home/neo/codac/examples/00_graphics//CMakeFiles/progress.marks - $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all - $(CMAKE_COMMAND) -E cmake_progress_start /home/neo/codac/examples/00_graphics/CMakeFiles 0 -.PHONY : all - -# The main clean target -clean: - $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 clean -.PHONY : clean - -# The main clean target -clean/fast: clean -.PHONY : clean/fast - -# Prepare targets for installation. -preinstall: all - $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall -.PHONY : preinstall - -# Prepare targets for installation. -preinstall/fast: - $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall -.PHONY : preinstall/fast - -# clear depends -depend: - $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 -.PHONY : depend - -# Help Target -help: - @echo "The following are some of the valid targets for this Makefile:" - @echo "... all (the default if no target is provided)" - @echo "... clean" - @echo "... depend" - @echo "... edit_cache" - @echo "... rebuild_cache" -.PHONY : help - - - -#============================================================================= -# Special targets to cleanup operation of make. - -# Special rule to run CMake to check the build system integrity. -# No rule that depends on this can have commands that come from listfiles -# because they might be regenerated. -cmake_check_build_system: - $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 -.PHONY : cmake_check_build_system - diff --git a/examples/00_graphics/cmake_install.cmake b/examples/00_graphics/cmake_install.cmake deleted file mode 100644 index 92777670..00000000 --- a/examples/00_graphics/cmake_install.cmake +++ /dev/null @@ -1,54 +0,0 @@ -# Install script for directory: /home/neo/codac/examples - -# Set the install prefix -if(NOT DEFINED CMAKE_INSTALL_PREFIX) - set(CMAKE_INSTALL_PREFIX "/home/neo/codac/build_install") -endif() -string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") - -# Set the install configuration name. -if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) - if(BUILD_TYPE) - string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" - CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") - else() - set(CMAKE_INSTALL_CONFIG_NAME "Release") - endif() - message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") -endif() - -# Set the component getting installed. -if(NOT CMAKE_INSTALL_COMPONENT) - if(COMPONENT) - message(STATUS "Install component: \"${COMPONENT}\"") - set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") - else() - set(CMAKE_INSTALL_COMPONENT) - endif() -endif() - -# Install shared libraries without execute permission? -if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) - set(CMAKE_INSTALL_SO_NO_EXE "1") -endif() - -# Is this installation the result of a crosscompile? -if(NOT DEFINED CMAKE_CROSSCOMPILING) - set(CMAKE_CROSSCOMPILING "FALSE") -endif() - -# Set default install directory permissions. -if(NOT DEFINED CMAKE_OBJDUMP) - set(CMAKE_OBJDUMP "/usr/bin/objdump") -endif() - -if(CMAKE_INSTALL_COMPONENT) - set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt") -else() - set(CMAKE_INSTALL_MANIFEST "install_manifest.txt") -endif() - -string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT - "${CMAKE_INSTALL_MANIFEST_FILES}") -file(WRITE "/home/neo/codac/examples/00_graphics/${CMAKE_INSTALL_MANIFEST}" - "${CMAKE_INSTALL_MANIFEST_CONTENT}") From eeb8295f7aaf2461080d22a5c639e2a2ccccca20 Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 2 Dec 2024 21:31:43 +0100 Subject: [PATCH 083/102] minor correction --- examples/00_graphics/graphic_examples.py | 2 +- tests/graphics/styles/codac2_tests_Color.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index 4d8549bb..539bc6ee 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -46,7 +46,7 @@ fig2.draw_ellipse([1,1],[0.5,2], 0.2, [Color.blue(),Color.blue(0.3)]) fig2.draw_point([2,2], [Color.red(),Color.yellow(0.5)]) fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) -fig2.draw_box([[2.6,3.1],[2.6,3.1]],[Color(0.305555556,0.9,0.78,interpol_mode=InterpolMode.HSV),Color(0.305555556,0.9,0.78,0.2,InterpolMode.HSV)]) +fig2.draw_box([[2.6,3.1],[2.6,3.1]],[Color(0.30,0.9,0.78,interpol_mode=InterpolMode.HSV),Color(0.30,0.9,0.78,0.2,InterpolMode.HSV)]) fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) fig3.set_axes(axis(0,[-1,21]), axis(1,[-5.5,0.5])) diff --git a/tests/graphics/styles/codac2_tests_Color.py b/tests/graphics/styles/codac2_tests_Color.py index d47baf66..fb52703a 100644 --- a/tests/graphics/styles/codac2_tests_Color.py +++ b/tests/graphics/styles/codac2_tests_Color.py @@ -3,7 +3,7 @@ # Codac tests # ---------------------------------------------------------------------------- # \date 2024 -# \author Simon Rohou, Maël GODARD +# \author Simon Rohou, Maël Godard # \copyright Copyright 2024 Codac Team # \license GNU Lesser General Public License (LGPL) From 6e2eb7e76f04c7659313a641cbce8ad682257358 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Tue, 3 Dec 2024 12:54:03 +0100 Subject: [PATCH 084/102] [doc] manual: minor update --- doc/manual/_static/css/custom.css | 10 +++++++ doc/manual/conf.py.in | 5 ++++ doc/manual/index.rst | 46 +++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 doc/manual/_static/css/custom.css diff --git a/doc/manual/_static/css/custom.css b/doc/manual/_static/css/custom.css new file mode 100644 index 00000000..bf36547f --- /dev/null +++ b/doc/manual/_static/css/custom.css @@ -0,0 +1,10 @@ +div.rst-content a:visited +{ + color: #2980b9; + text-decoration: none; +} + +div.rst-content li.toctree-l1 > a +{ + font-weight: bold; +} \ No newline at end of file diff --git a/doc/manual/conf.py.in b/doc/manual/conf.py.in index ff821a0e..e7d94dab 100644 --- a/doc/manual/conf.py.in +++ b/doc/manual/conf.py.in @@ -28,6 +28,11 @@ html_static_path = ['_static'] html_theme = "sphinx_rtd_theme" html_logo = "_static/logos/logo_codac.svg" +# These paths are either relative to html_static_path +# or fully qualified paths (eg. https://...) +html_css_files = [ + 'css/custom.css', +] html_theme_options = { 'logo_only': True, diff --git a/doc/manual/index.rst b/doc/manual/index.rst index 4aa0bdc9..460fb89b 100644 --- a/doc/manual/index.rst +++ b/doc/manual/index.rst @@ -2,8 +2,50 @@ Codac manual ============ +.. toctree:: + :caption: Overview of Codac + :maxdepth: 3 + + Constraint programming and IA + The Codac framework + Target audience + + +.. toctree:: + :caption: User manual + :maxdepth: 3 + + installation/index.rst + intervals/index.rst + linear/index.rst + functions/index.rst + tubes/index.rst + contractors/index.rst + separators/index.rst + pavers/index.rst + cn/index.rst + geometry/index.rst + ellipsoids/index.rst + topology/index.rst + visualization/index.rst + extensions/index.rst + seealso/index.rst + references/index.rst + + +.. toctree:: + :caption: How-to guides + :maxdepth: 3 + + howto/robotics/index.rst + howto/geometry/index.rst + howto/dynamical/index.rst + .. toctree:: - :maxdepth: 2 - :caption: Contents: + :caption: Development + :maxdepth: 3 + Changelog + C++ API + Information for developers \ No newline at end of file From f12cd831223240641e74bce14e9c6bed7a0c3dc9 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 3 Dec 2024 17:12:34 +0100 Subject: [PATCH 085/102] [graphics] modified Color and Colormap representations --- examples/00_graphics/graphic_examples.py | 14 +- .../src/graphics/styles/codac2_py_Color.cpp | 81 +++----- .../graphics/styles/codac2_py_ColorMap.cpp | 31 +-- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 52 +++-- src/graphics/styles/codac2_Color.cpp | 196 +++++++----------- src/graphics/styles/codac2_Color.h | 86 ++++---- src/graphics/styles/codac2_ColorMap.cpp | 129 ++---------- src/graphics/styles/codac2_ColorMap.h | 95 ++++++++- 8 files changed, 301 insertions(+), 383 deletions(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index 539bc6ee..c7015a1d 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -23,7 +23,7 @@ fig1.set_window_properties([50,50],[500,500]) # position, window size fig1.set_axes(axis(0,[-10,10]), axis(1,[-10,10])) # (axis_id,[range_of_values_on_this_axis]) fig1.draw_box([[-1,1],[-1,1]],[Color.green(),Color.red(0.2)]) # drawing a green box with red opacity values inside -fig1.draw_circle([1,1],0.5,Color(255,155,5)) # drawing a circle at (1,1) of radius 0.5 with a custom RGB color +fig1.draw_circle([1,1],0.5,Color([255,155,5])) # drawing a circle at (1,1) of radius 0.5 with a custom RGB color fig1.draw_ring([1,1],[4,6],Color.red()) # drawing a ring at (1,1) of radius [4,6] with a predefined red color fig2 = Figure2D("My figure 2", GraphicOutput.VIBES | GraphicOutput.IPE) @@ -46,17 +46,17 @@ fig2.draw_ellipse([1,1],[0.5,2], 0.2, [Color.blue(),Color.blue(0.3)]) fig2.draw_point([2,2], [Color.red(),Color.yellow(0.5)]) fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) -fig2.draw_box([[2.6,3.1],[2.6,3.1]],[Color(0.30,0.9,0.78,interpol_mode=InterpolMode.HSV),Color(0.30,0.9,0.78,0.2,InterpolMode.HSV)]) +fig2.draw_box([[2.6,3.1],[2.6,3.1]],[Color([108,90,78],Model.HSV),Color([108,90,78,20],Model.HSV)]) fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) fig3.set_axes(axis(0,[-1,21]), axis(1,[-5.5,0.5])) fig3.set_window_properties([800,250],[500,500]) -cmap_haxby=ColorMap.HAXBY -cmap_default=ColorMap.DEFAULT -cmap_blue_tube=ColorMap.BLUE_TUBE -cmap_red_tube=ColorMap.RED_TUBE -cmap_rainbow=ColorMap.RAINBOW +cmap_haxby=ColorMap.haxby() +cmap_default=ColorMap.basic() +cmap_blue_tube=ColorMap.blue_tube() +cmap_red_tube=ColorMap.red_tube() +cmap_rainbow=ColorMap.rainbow() for i in range (20): ratio=i/20 diff --git a/python/src/graphics/styles/codac2_py_Color.cpp b/python/src/graphics/styles/codac2_py_Color.cpp index 2ff64ecc..1660c94a 100644 --- a/python/src/graphics/styles/codac2_py_Color.cpp +++ b/python/src/graphics/styles/codac2_py_Color.cpp @@ -22,82 +22,57 @@ using namespace pybind11::literals; void export_Color(py::module& m) { - py::enum_(m, "InterpolMode") - .value("RGB", InterpolMode::RGB) - .value("HSV", InterpolMode::HSV) + + py::enum_(m, "Model") + .value("RGB", Color::Model::RGB) + .value("HSV", Color::Model::HSV) ; py::class_ exported_color(m, "Color", COLOR_MAIN); exported_color - - .def_readwrite("data", &Color::data, - ARRAY_FLOAT4_COLOR_DATA) - - .def_readwrite("interpol_mode", &Color::interpol_mode, - INTERPOLMODE_COLOR_INTERPOL_MODE) + + .def_readwrite("m", &Color::m, + MODEL_COLOR_M) .def(py::init<>(),COLOR_COLOR) - .def(py::init(), - COLOR_COLOR_FLOAT_FLOAT_FLOAT_FLOAT_INTERPOLMODE, - "x1"_a, "x2"_a, "x3"_a, "alpha"_a, "interpol_mode"_a=InterpolMode::RGB) - - .def(py::init(), - COLOR_COLOR_FLOAT_FLOAT_FLOAT_INTERPOLMODE, - "x1"_a, "x2"_a, "x3"_a, "interpol_mode"_a=InterpolMode::RGB) - - .def(py::init&,InterpolMode>(), - COLOR_COLOR_CONST_ARRAY_FLOAT3_REF_INTERPOLMODE, - "xyz"_a, "interpol_mode"_a=InterpolMode::RGB) - - .def(py::init&,InterpolMode>(), - COLOR_COLOR_CONST_ARRAY_FLOAT4_REF_INTERPOLMODE, - "xyza"_a, "interpol_mode"_a=InterpolMode::RGB) - - .def(py::init(), - COLOR_COLOR_INT_INT_INT_INT_INTERPOLMODE, - "x1"_a, "x2"_a, "x3"_a, "alpha"_a, "interpol_mode"_a=InterpolMode::RGB) - - .def(py::init(), - COLOR_COLOR_INT_INT_INT_INTERPOLMODE, - "x1"_a, "x2"_a, "x3"_a, "interpol_mode"_a=InterpolMode::RGB) + .def(py::init&,Color::Model>(), + COLOR_COLOR_CONST_ARRAY_FLOAT3_REF_MODEL, + "xyz"_a, "m_"_a=Color::Model::RGB) - .def(py::init&,InterpolMode>(), - COLOR_COLOR_CONST_ARRAY_INT3_REF_INTERPOLMODE, - "xyz"_a, "interpol_mode"_a=InterpolMode::RGB) + .def(py::init&,Color::Model>(), + COLOR_COLOR_CONST_ARRAY_FLOAT4_REF_MODEL, + "xyza"_a, "m_"_a=Color::Model::RGB) - .def(py::init&,InterpolMode>(), - COLOR_COLOR_CONST_ARRAY_INT4_REF_INTERPOLMODE, - "xyza"_a, "interpol_mode"_a=InterpolMode::RGB) + .def(py::init&,Color::Model>(), + COLOR_COLOR_CONST_INITIALIZER_LIST_FLOAT_MODEL, + "xyza"_a, "m_"_a=Color::Model::RGB) .def(py::init(), COLOR_COLOR_CONST_STRING_REF, "hex_str"_a) - // Conversions - - .def("toRGB", &Color::toRGB, - COLOR_COLOR_TORGB_CONST) - .def("toHSV", &Color::toHSV, - COLOR_COLOR_TOHSV_CONST) - - // Properties + // Html color .def("hex_str", &Color::hex_str, STRING_COLOR_HEX_STR_CONST) - .def("rgb", &Color::rgb, - ARRAY_INT3_COLOR_RGB_CONST) + // Conversions - .def("rgba", &Color::rgba, - ARRAY_INT3_COLOR_RGB_CONST) + .def("rgb", &Color::rgb, + COLOR_COLOR_RGB_CONST) .def("hsv", &Color::hsv, - ARRAY_INT3_COLOR_RGB_CONST) + COLOR_COLOR_HSV_CONST) + + // Overload flux operator - .def("hsva", &Color::hsva, - ARRAY_INT3_COLOR_RGB_CONST) + .def("__str__", [](const Color& c) { + std::ostringstream oss; + oss << c; + return oss.str(); + }) // Predefined colors diff --git a/python/src/graphics/styles/codac2_py_ColorMap.cpp b/python/src/graphics/styles/codac2_py_ColorMap.cpp index 11b66b9d..2c7c28b2 100644 --- a/python/src/graphics/styles/codac2_py_ColorMap.cpp +++ b/python/src/graphics/styles/codac2_py_ColorMap.cpp @@ -23,35 +23,26 @@ void export_ColorMap(py::module& m) py::class_ exported_colormap(m, "ColorMap", COLORMAP_MAIN); exported_colormap - .def_readwrite("colormap", &ColorMap::colormap) - - .def(py::init<>(), - COLORMAP_COLORMAP) - - .def("add_color_point", &ColorMap::add_color_point, - VOID_COLORMAP_ADD_COLOR_POINT_COLOR_FLOAT, - "color"_a, "index"_a) - .def("color", &ColorMap::color, COLOR_COLORMAP_COLOR_FLOAT_CONST, "r"_a) // Predifined color maps - .def_readonly_static("HAXBY", &ColorMap::HAXBY, - CONST_COLORMAP_COLORMAP_HAXBY) - - .def_readonly_static("DEFAULT", &ColorMap::DEFAULT, - CONST_COLORMAP_COLORMAP_DEFAULT) + .def_static("haxby", &ColorMap::haxby, + STATIC_COLORMAP_COLORMAP_HAXBY) + + .def_static("basic", &ColorMap::basic, + STATIC_COLORMAP_COLORMAP_BASIC) - .def_readonly_static("BLUE_TUBE", &ColorMap::BLUE_TUBE, - CONST_COLORMAP_COLORMAP_BLUE_TUBE) + .def_static("blue_tube", &ColorMap::blue_tube, + STATIC_COLORMAP_COLORMAP_BLUE_TUBE) - .def_readonly_static("RED_TUBE", &ColorMap::RED_TUBE, - CONST_COLORMAP_COLORMAP_RED_TUBE) + .def_static("red_tube", &ColorMap::red_tube, + STATIC_COLORMAP_COLORMAP_RED_TUBE) - .def_readonly_static("RAINBOW", &ColorMap::RAINBOW, - CONST_COLORMAP_COLORMAP_RAINBOW) + .def_static("rainbow", &ColorMap::rainbow, + STATIC_COLORMAP_COLORMAP_RAINBOW) ; } \ No newline at end of file diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 9da1d086..9981b3e5 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -75,18 +75,28 @@ void Figure2D_IPE::center_viewbox([[maybe_unused]] const Vector& c, [[maybe_unus assert(r.min_coeff() > 0.); } +std::string ipe_str(const Color& c) +{ + return " codac_color_" + c.hex_str().substr(1); +} + +int ipe_opacity(const Color& c) +{ + return (int)(10.*round(10.*(c.m==Color::RGB ? (c[3]/255.):(c[3]/100.)))); +} + void Figure2D_IPE::begin_path(const StyleProperties& s, bool tip=false) { // substr is needed to remove the "#" at the beginning of hex_str (deprecated by IPE) - _colors.emplace(s.stroke_color.hex_str().substr(1), s.stroke_color); - _colors.emplace(s.fill_color.hex_str().substr(1), s.fill_color); + _colors.emplace(ipe_str(s.stroke_color), s.stroke_color); + _colors.emplace(ipe_str(s.fill_color), s.fill_color); _f_temp_content << "\n \ "; } @@ -545,10 +555,10 @@ void Figure2D_IPE::print_header_page() for(auto& [k,c] : _colors) { - if (c.interpol_mode == InterpolMode::HSV) - c = c.toRGB(); + if (c.m == Color::HSV) + c = c.rgb(); _f << " \n"; + << "value=\"" << (float) (c[0]/255.) << " " <<(float) (c[1]/255.) << " " <<(float) (c[2]/255.) << "\" /> \n"; } _f << " \n \ diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index 7590234f..b121e943 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -13,62 +13,38 @@ using namespace std; using namespace codac2; Color::Color() -{ } - -Color::Color(float x1, float x2, float x3, float alpha,InterpolMode interpol_mode) - :data({x1,x2,x3,alpha}), interpol_mode(interpol_mode) + : m(RGB) { - assert(x1 >= 0. && x1 <= 1. && x2 >= 0. && x2 <= 1. && x3 >= 0. && x3 <= 1. && alpha >= 0. && alpha <= 1.); + (*this)[0] = 0.; + (*this)[1] = 0.; + (*this)[2] = 0.; + (*this)[3] = 0.; } -Color::Color(double x1, double x2, double x3, double alpha, InterpolMode interpol_mode) - : Color((float)x1, (float)x2, (float)x3, (float)alpha, interpol_mode) -{ } - -Color::Color(float x1, float x2, float x3, InterpolMode interpol_mode) - : Color(x1, x2, x3, (float) 1., interpol_mode) -{ } - -Color::Color(double x1, double x2, double x3, InterpolMode interpol_mode) - : Color((float)x1, (float)x2, (float) x3, (float) 1., interpol_mode) -{ } - -Color::Color(const std::array& xyz, InterpolMode interpol_mode) - : Color(xyz[0], xyz[1], xyz[2],(float) 1., interpol_mode) -{ } - -Color::Color(const std::array& xyza, InterpolMode interpol_mode) - : Color(xyza[0], xyza[1], xyza[2], xyza[3], interpol_mode) -{ } - -Color::Color(int x1, int x2, int x3, int alpha,InterpolMode interpol_mode) -: Color(interpol_mode == InterpolMode::RGB ? (float) (x1/255.) : (float) (x1/360.), - interpol_mode == InterpolMode::RGB ? (float) (x2/255.) : (float) (x2/100.), - interpol_mode == InterpolMode::RGB ? (float) (x3/255.) : (float) (x3/100.), - interpol_mode == InterpolMode::RGB ? (float) (alpha/255.) : (float) (alpha/100.), - interpol_mode) +Color::Color(const std::array& xyz, Model m_) + : m(m_) { - if (interpol_mode == InterpolMode::RGB) - { - assert(x1 >= 0 && x1 <= 255 && x2 >= 0 && x2 <= 255 && x3 >= 0 && x3 <= 255 && alpha >= 0 && alpha <= 255); - } - else - { - assert(x1 >= 0 && x1 <= 360 && x2 >= 0 && x2 <= 100 && x3 >= 0 && x3 <= 100 && alpha >= 0 && alpha <= 100); - } - + (*this)[0] = xyz[0]; + (*this)[1] = xyz[1]; + (*this)[2] = xyz[2]; + (*this)[3] = (m == RGB ? 255. : 100.); } -Color::Color(int x1, int x2, int x3, InterpolMode interpol_mode) - : Color(x1, x2, x3,interpol_mode == InterpolMode::RGB ? 255 : 100, interpol_mode) -{ } - -Color::Color(const std::array& xyz, InterpolMode interpol_mode) - : Color(xyz[0], xyz[1], xyz[2], interpol_mode == InterpolMode::RGB ? 255 : 100, interpol_mode) -{ } +Color::Color(const std::array& xyza, Model m_) + : m(m_) +{ + if (m_==RGB) + assert(xyza[0] >= 0. && xyza[0] <= 255. && xyza[1]>=0. && xyza[1] <= 255. && xyza[2]>=0. && xyza[2] <= 255. && xyza[3]>=0. && xyza[3] <= 255.); + else if (m_==HSV) + assert(xyza[0] >= 0. && xyza[0] <= 360. && xyza[1]>=0. && xyza[1] <= 100. && xyza[2]>=0. && xyza[2] <= 100. && xyza[3]>=0. && xyza[3] <= 100.); + (*this)[0] = xyza[0]; + (*this)[1] = xyza[1]; + (*this)[2] = xyza[2]; + (*this)[3] = xyza[3]; +} -Color::Color(const std::array& xyza, InterpolMode interpol_mode) - : Color(xyza[0], xyza[1], xyza[2], xyza[3], interpol_mode) +Color::Color(const std::initializer_list xyza, Model m_) + : Color(xyza.size() == 3 ? Color(to_array<3>(xyza), m_) : Color(to_array<4>(xyza), m_)) { } Color::Color(const std::string& hex_str) @@ -76,72 +52,84 @@ Color::Color(const std::string& hex_str) assert(hex_str.size() == 7 || hex_str.size() == 9); assert(hex_str[0] == '#'); - interpol_mode = InterpolMode::RGB; + m = RGB; int red,green,blue,a; std::istringstream(hex_str.substr(1,2)) >> std::hex >> red; std::istringstream(hex_str.substr(3,2)) >> std::hex >> green; std::istringstream(hex_str.substr(5,2)) >> std::hex >> blue; - data[0] = (float) (red/255.); - data[1] = (float) (green/255.); - data[2] = (float) (blue/255.); + (*this)[0] = (float) (red); + (*this)[1] = (float) (green); + (*this)[2] = (float) (blue); // Alpha (transparency) component may be appended to the #hexa notation. - // Value is '1' (max opacity) by default. + // Value is '255.' (max opacity) by default. if(hex_str.size() == 9) { std::istringstream(hex_str.substr(7,2)) >> std::hex >> a; - data[3] = (float) (a/255.); + (*this)[3] = (float) (a); } + else + (*this)[3] = 255.; } -Color Color::toRGB() const +Color Color::rgb() const { - if (interpol_mode==InterpolMode::RGB) + if (m==RGB) return *this; else { - float r = 1., g = 1., b = 1.; + float r = 0., g = 0., b = 0.; + + // Normalisation des valeurs + float h = (*this)[0] / 360.; // Hue normalisée (0 à 1) + float s = (*this)[1] / 100.; // Saturation normalisée (0 à 1) + float v = (*this)[2] / 100.; // Value normalisée (0 à 1) - int i = static_cast(data[0] * 6); - float f = (data[0] * 6) - i; + int i = static_cast(h * 6); + float f = (h * 6) - i; i = i % 6; - float p = data[2] * (1 - data[1]); - float q = data[2] * (1 - f * data[1]); - float t = data[2] * (1 - (1 - f) * data[1]); + float p = v * (1 - s); + float q = v * (1 - f * s); + float t = v * (1 - (1 - f) * s); switch (i) { - case 0: r = data[2]; g = t; b = p; break; - case 1: r = q; g = data[2]; b = p; break; - case 2: r = p; g = data[2]; b = t; break; - case 3: r = p; g = q; b = data[2]; break; - case 4: r = t; g = p; b = data[2]; break; - case 5: r = data[2]; g = p; b = q; break; + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; } - return Color(r, g, b, data[3],InterpolMode::RGB); + // Conversion vers l'échelle [0, 255] + r *= 255.; + g *= 255.; + b *= 255.; + + return Color({r, g, b,(float) ((*this)[3]*2.55)},RGB); } } -Color Color::toHSV() const +Color Color::hsv() const { - if (interpol_mode==InterpolMode::HSV) + if (m==HSV) return *this; else { - float c_max = std::max({data[0], data[1], data[2]}); - float c_min = std::min({data[0], data[1], data[2]}); + float c_max = std::max({(*this)[0], (*this)[1], (*this)[2]}); + float c_min = std::min({(*this)[0], (*this)[1], (*this)[2]}); float delta = c_max - c_min; float h = 0.0; if (delta != 0) { - if (c_max == data[0]) { - h = fmod((data[1] - data[2]) / delta, 6.0); - } else if (c_max == data[1]) { - h = (data[2] - data[0]) / delta + 2.0; - } else if (c_max == data[2]) { - h = (data[0] - data[1]) / delta + 4.0; + if (c_max == (*this)[0]) { + h = fmod(((*this)[1] - (*this)[2]) / delta, 6.0); + } else if (c_max == (*this)[1]) { + h = ((*this)[2] - (*this)[0]) / delta + 2.0; + } else if (c_max == (*this)[2]) { + h = ((*this)[0] - (*this)[1]) / delta + 4.0; } h /= 6.0; if (h < 0) { @@ -153,53 +141,25 @@ Color Color::toHSV() const float v = c_max; - return Color(h, s, v, data[3],InterpolMode::HSV); + h*=360.; + s*=100.; + v*=100.; + + return Color({h, s, v,(float) ((*this)[3]/2.55)},HSV); } } std::string Color::hex_str() const { - if (interpol_mode == InterpolMode::RGB) + if (m == RGB) { std::stringstream s; s << std::hex << std::setfill('0'); - s << std::setw(2) << (int)(data[0]*255) << std::setw(2) << (int)(data[1]*255) << std::setw(2) << (int)(data[2]*255); - if(data[3] != 1.) - s << std::setw(2) << (int)(data[3]*255); + s << std::setw(2) << (int)((*this)[0]) << std::setw(2) << (int)((*this)[1]) << std::setw(2) << (int)((*this)[2]); + if((*this)[3] != 1.) + s << std::setw(2) << (int)((*this)[3]); return "#"+s.str(); } else - return toRGB().hex_str(); -} - -std::array Color::rgb() const -{ - if (interpol_mode == InterpolMode::RGB) - return { (int)(data[0]*255), (int)(data[1]*255), (int)(data[2]*255) }; - else - return toRGB().rgb(); -} - -std::array Color::rgba() const -{ - if (interpol_mode == InterpolMode::RGB) - return { (int)(data[0]*255), (int)(data[1]*255), (int)(data[2]*255), (int)(data[3]*255) }; - else - return toRGB().rgba(); -} - -std::array Color::hsv() const -{ - if (interpol_mode == InterpolMode::HSV) - return { (int)(data[0]*360), (int)(data[1]*100), (int)(data[2]*100) }; - else - return toHSV().hsv(); -} - -std::array Color::hsva() const -{ - if (interpol_mode == InterpolMode::HSV) - return { (int)(data[0]*360), (int)(data[1]*100), (int)(data[2]*100), (int)(data[3]*100) }; - else - return toHSV().hsva(); + return rgb().hex_str(); } \ No newline at end of file diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index fbdd7d41..cc67ce30 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -17,57 +17,67 @@ namespace codac2 { - enum class InterpolMode - { - RGB = 0x01, - HSV = 0x02 - }; - struct Color + + struct Color : public std::array { - std::array data = {0.,0.,0.,1.0}; // RGB or HSV values + alpha, between 0 and 1 - InterpolMode interpol_mode = InterpolMode::RGB;//RGB or HSV + enum Model + { + RGB = 0x01, + HSV = 0x02 + }; + + Model m = RGB; //RGB or HSV // Constructors explicit Color(); - explicit Color(float x1, float x2, float x3, float alpha, InterpolMode interpol_mode = InterpolMode::RGB); // RGBA constructor - explicit Color(double x1, double x2, double x3, double alpha, InterpolMode interpol_mode = InterpolMode::RGB); - explicit Color(float x1, float x2, float x3, InterpolMode interpol_mode = InterpolMode::RGB); // RGB constructor - explicit Color(double x1, double x2, double x3, InterpolMode interpol_mode = InterpolMode::RGB); - explicit Color(const std::array& xyz, InterpolMode interpol_mode = InterpolMode::RGB); - explicit Color(const std::array& xyza, InterpolMode interpol_mode = InterpolMode::RGB); - explicit Color(int x1, int x2, int x3, int alpha,InterpolMode interpol_mode = InterpolMode::RGB); - explicit Color(int x1, int x2, int x3, InterpolMode interpol_mode = InterpolMode::RGB); - explicit Color(const std::array& xyz, InterpolMode interpol_mode = InterpolMode::RGB); - explicit Color(const std::array& xyza, InterpolMode interpol_mode = InterpolMode::RGB); + explicit Color(const std::array& xyz, Model m_ = RGB); + explicit Color(const std::array& xyza, Model m_ = RGB); + explicit Color(const std::initializer_list xyza, Model m_ = RGB); explicit Color(const std::string& hex_str); - //Conversions + // Html color + + std::string hex_str() const; - Color toRGB() const; - Color toHSV() const; + // Conversions - // Properties + Color rgb() const; + Color hsv() const; + + // Overload flux operator + + friend std::ostream& operator<<(std::ostream& os, const Color& c) + { + if (c.m == RGB) + os << "RGB Color (" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << ")"; + else if (c.m == HSV) + os << "HSV Color (" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << ")"; + return os; + } - std::string hex_str() const; - std::array rgb() const; - std::array rgba() const; - std::array hsv() const; - std::array hsva() const; // Predefined colors - static Color none() { return Color(255, 255, 255, 0 ); }; - static Color black(float alpha = 1) { return Color(0, 0, 0, (int)(alpha*255)); }; - static Color white(float alpha = 1) { return Color(255, 255, 255, (int)(alpha*255)); }; - static Color green(float alpha = 1) { return Color(144, 242, 0, (int)(alpha*255)); }; - static Color blue(float alpha = 1) { return Color(0, 98, 198, (int)(alpha*255)); }; - static Color cyan(float alpha = 1) { return Color(75, 207, 250, (int)(alpha*255)); }; - static Color yellow(float alpha = 1) { return Color(255, 211, 42, (int)(alpha*255)); }; - static Color red(float alpha = 1) { return Color(209, 59, 0, (int)(alpha*255)); }; - static Color dark_gray(float alpha = 1) { return Color(112, 112, 112, (int)(alpha*255)); }; - static Color purple(float alpha = 1) { return Color(154, 0, 170, (int)(alpha*255)); }; - static Color dark_green(float alpha = 1) { return Color(94, 158, 0, (int)(alpha*255)); }; + static Color none() { return Color({255., 255., 255., 0.}); }; + static Color black(float alpha = 1.) { return Color({0., 0., 0., (float) (alpha*255.)}); }; + static Color white(float alpha = 1.) { return Color({255., 255., 255., (float) (alpha*255.)}); }; + static Color green(float alpha = 1.) { return Color({144., 242., 0., (float) (alpha*255.)}); }; + static Color blue(float alpha = 1.) { return Color({0., 98., 198., (float) (alpha*255.)}); }; + static Color cyan(float alpha = 1.) { return Color({75., 207., 250., (float) (alpha*255.)}); }; + static Color yellow(float alpha = 1.) { return Color({255., 211., 42., (float) (alpha*255.)}); }; + static Color red(float alpha = 1.) { return Color({209., 59., 0., (float) (alpha*255.)}); }; + static Color dark_gray(float alpha = 1.) { return Color({112., 112., 112., (float) (alpha*255.)}); }; + static Color purple(float alpha = 1.) { return Color({154., 0., 170., (float) (alpha*255.)}); }; + static Color dark_green(float alpha = 1.) { return Color({94., 158., 0., (float) (alpha*255.)}); }; }; + + template + static std::array to_array(const std::initializer_list& list) { + assert(list.size() == N); + std::array arr; + std::copy(list.begin(), list.end(), arr.begin()); + return arr; + } } \ No newline at end of file diff --git a/src/graphics/styles/codac2_ColorMap.cpp b/src/graphics/styles/codac2_ColorMap.cpp index bbc7ea4f..7971462a 100644 --- a/src/graphics/styles/codac2_ColorMap.cpp +++ b/src/graphics/styles/codac2_ColorMap.cpp @@ -13,135 +13,32 @@ using namespace std; using namespace codac2; -ColorMap::ColorMap() - : colormap() -{} - -void ColorMap::add_color_point(Color color, float index) -{ - colormap[index] = color; -} - Color ColorMap::color(float r) const { - assert (colormap.size() >= 2); + assert (this->size() >= 2); if(std::isnan(r)) // undefined ratio - return Color(0.5, 0.5, 0.5); + return Color({0.5, 0.5, 0.5}); assert(Interval(0.,1.).contains(r)); - Interval map_domain = Interval(colormap.begin()->first,prev(colormap.end())->first); + Interval map_domain = Interval(this->begin()->first,prev(this->end())->first); float real_index = map_domain.lb() + r*map_domain.diam(); - if(colormap.find(real_index) == colormap.end()) // color interpolation + if(this->find(real_index) == this->end()) // color interpolation { typename map::const_iterator it_ub; - it_ub = colormap.lower_bound(real_index); - Color color_lb = prev(it_ub)->second.toRGB(); - Color color_ub = it_ub->second.toRGB(); + it_ub = this->lower_bound(real_index); + Color color_lb = prev(it_ub)->second; + Color color_ub = it_ub->second; float local_ratio = (real_index - prev(it_ub)->first) / (it_ub->first - prev(it_ub)->first); - return Color((float)(color_lb.data[0] + (color_ub.data[0] - color_lb.data[0]) * local_ratio), - (float)(color_lb.data[1] + (color_ub.data[1] - color_lb.data[1]) * local_ratio), - (float)(color_lb.data[2] + (color_ub.data[2] - color_lb.data[2]) * local_ratio), - (float)(color_lb.data[3] + (color_ub.data[3] - color_lb.data[3]) * local_ratio)); + return Color({(color_lb[0] + (color_ub[0] - color_lb[0]) * local_ratio), + (color_lb[1] + (color_ub[1] - color_lb[1]) * local_ratio), + (color_lb[2] + (color_ub[2] - color_lb[2]) * local_ratio), + (color_lb[3] + (color_ub[3] - color_lb[3]) * local_ratio)},color_lb.m); } else // color key - return colormap.at(real_index); -} - -ColorMap make_haxby() - { - ColorMap map; - map.add_color_point(Color(39,90,211), 0); - map.add_color_point(Color(40,123,245), 1); - map.add_color_point(Color(45,155,253), 2); - map.add_color_point(Color(73,209,255), 3); - map.add_color_point(Color(100,230,254), 4); - map.add_color_point(Color(118,235,226), 5); - map.add_color_point(Color(135,236,187), 6); - map.add_color_point(Color(194,252,165), 7); - map.add_color_point(Color(217,251,151), 8); - map.add_color_point(Color(233,241,131), 9); - map.add_color_point(Color(252,201,96), 10); - map.add_color_point(Color(255,184,84), 11); - map.add_color_point(Color(255,170,75), 12); - map.add_color_point(Color(255,167,83), 13); - map.add_color_point(Color(255,200,158), 14); - map.add_color_point(Color(255,233,217), 15); - return map; - } - -const ColorMap ColorMap::HAXBY = make_haxby(); - -ColorMap make_default() - { - ColorMap map; - map.add_color_point(Color(10,0,121), 0); - map.add_color_point(Color(40,0,150), 1); - map.add_color_point(Color(20,5,175), 2); - map.add_color_point(Color(0,10,200), 3); - map.add_color_point(Color(0,25,212), 4); - map.add_color_point(Color(0,40,224), 5); - map.add_color_point(Color(26,102,240), 6); - map.add_color_point(Color(13,129,248), 7); - map.add_color_point(Color(25,175,255), 8); - map.add_color_point(Color(50,190,255), 9); - map.add_color_point(Color(68,202,255), 10); - map.add_color_point(Color(97,225,240), 11); - map.add_color_point(Color(106,235,225), 12); - map.add_color_point(Color(124,235,200), 13); - map.add_color_point(Color(138,236,174), 14); - map.add_color_point(Color(172,245,168), 15); - map.add_color_point(Color(205,255,162), 16); - map.add_color_point(Color(223,245,141), 17); - map.add_color_point(Color(240,236,121), 18); - map.add_color_point(Color(247,215,104), 19); - map.add_color_point(Color(255,189,87), 20); - map.add_color_point(Color(255,160,69), 21); - map.add_color_point(Color(244,117,75), 22); - map.add_color_point(Color(238,80,78), 23); - map.add_color_point(Color(255,90,90), 24); - map.add_color_point(Color(255,124,124), 25); - map.add_color_point(Color(255,158,158), 26); - map.add_color_point(Color(245,179,174), 27); - map.add_color_point(Color(255,196,196), 28); - map.add_color_point(Color(255,215,215), 29); - map.add_color_point(Color(255,235,235), 31); - map.add_color_point(Color(255,254,253), 32); - return map; - } - - const ColorMap ColorMap::DEFAULT = make_default(); - -ColorMap make_blue_tube() -{ - ColorMap map; - map.add_color_point(Color(76,110,127), 0.); - map.add_color_point(Color(136,197,228), 1.); - return map; -} - -const ColorMap ColorMap::BLUE_TUBE = make_blue_tube(); - -ColorMap make_red_tube() -{ - ColorMap map; - map.add_color_point(Color(169,55,0), 0.); - map.add_color_point(Color(241,140,54), 1.); - return map; -} - -const ColorMap ColorMap::RED_TUBE = make_red_tube(); - -ColorMap make_rainbow() - { - ColorMap map; - for(int h = 300 ; h > 0 ; h-=10) - map.add_color_point(Color(h,100,100,100,InterpolMode::HSV), (300.-h)/300.); - return map; - } - - const ColorMap ColorMap::RAINBOW = make_rainbow(); \ No newline at end of file + return this->at(real_index); +} \ No newline at end of file diff --git a/src/graphics/styles/codac2_ColorMap.h b/src/graphics/styles/codac2_ColorMap.h index 36d44cd6..4ca78953 100644 --- a/src/graphics/styles/codac2_ColorMap.h +++ b/src/graphics/styles/codac2_ColorMap.h @@ -21,21 +21,96 @@ namespace codac2 * \struct ColorMap * \brief Represents a set of RGB values */ - struct ColorMap + struct ColorMap : public std::map { - ColorMap(); + Color color (float r) const; - std::map colormap; //!< map of colors + static ColorMap haxby() + { + return ColorMap({{0,Color({39.,90.,211.})}, + {1,Color({40.,123.,245.})}, + {2,Color({45.,155.,253.})}, + {3,Color({73.,209.,255.})}, + {4,Color({100.,230.,254.})}, + {5,Color({118.,235.,226.})}, + {6,Color({135.,236.,187.})}, + {7,Color({194.,252.,165.})}, + {8,Color({217.,251.,151.})}, + {9,Color({233.,241.,131.})}, + {10,Color({252.,201.,96.})}, + {11,Color({255.,184.,84.})}, + {12,Color({255.,170.,75.})}, + {13,Color({255.,167.,83.})}, + {14,Color({255.,200.,158.})}, + {15,Color({255.,233.,217.})} + }); - void add_color_point(Color color, float index); + + } - Color color (float r) const; + static ColorMap basic() // Can't use default as name + { + return ColorMap({{0,Color({10.,0.,121.})}, + {1,Color({40.,0.,150.})}, + {2,Color({20.,5.,175.})}, + {3,Color({0.,10.,200.})}, + {4,Color({0.,25.,212.})}, + {5,Color({0.,40.,224.})}, + {6,Color({26.,102.,240.})}, + {7,Color({13.,129.,248.})}, + {8,Color({25.,175.,255.})}, + {9,Color({50.,190.,255.})}, + {10,Color({68.,202.,255.})}, + {11,Color({97.,225.,240.})}, + {12,Color({106.,235.,225.})}, + {13,Color({124.,235.,200.})}, + {14,Color({138.,236.,174.})}, + {15,Color({172.,245.,168.})}, + {16,Color({205.,255.,162.})}, + {17,Color({223.,245.,141.})}, + {18,Color({240.,236.,121.})}, + {19,Color({247.,215.,104.})}, + {20,Color({255.,189.,87.})}, + {21,Color({255.,160.,69.})}, + {22,Color({244.,117.,75.})}, + {23,Color({238.,80.,78.})}, + {24,Color({255.,90.,90.})}, + {25,Color({255.,124.,124.})}, + {26,Color({255.,158.,158.})}, + {27,Color({245.,179.,174.})}, + {28,Color({255.,196.,196.})}, + {29,Color({255.,215.,215.})}, + {31,Color({255.,235.,235.})}, + {32,Color({255.,254.,253.})} + }); + } + + static ColorMap blue_tube() + { + return ColorMap({{0,Color({76.,110.,127.})}, + {1,Color({136.,197.,228.})} + }); + } + + static ColorMap red_tube() + { + return ColorMap({{0,Color({169.,55.,0.})}, + {1,Color({241.,140.,54.})} + }); + } + + static ColorMap rainbow() + { + ColorMap cmap; + int i = 0; + for(int h = 300 ; h > 0 ; h-=10) + { + cmap[i]=Color({(float)h,100.,100.},Color::HSV); + i++; + } + return cmap; + } - static const ColorMap HAXBY; //!< predefined HAXBY color map (mainly used for DEM) - static const ColorMap DEFAULT; //!< a predefined default color map - static const ColorMap BLUE_TUBE; //!< a predefined color map for tubes - static const ColorMap RED_TUBE; //!< a predefined color map for tubes - static const ColorMap RAINBOW; //!< a predefined color map }; } \ No newline at end of file From c0755720578ad4eff50c69c24f3c34c81380eb64 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 3 Dec 2024 18:28:54 +0100 Subject: [PATCH 086/102] [graphics] C++ tests passed --- .../src/graphics/styles/codac2_py_Color.cpp | 5 +- .../graphics/styles/codac2_py_ColorMap.cpp | 7 + src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 5 +- src/graphics/styles/codac2_Color.cpp | 24 +- src/graphics/styles/codac2_Color.h | 7 +- src/graphics/styles/codac2_ColorMap.cpp | 18 + src/graphics/styles/codac2_ColorMap.h | 123 ++++--- tests/graphics/styles/codac2_tests_Color.cpp | 346 ++++-------------- tests/graphics/styles/codac2_tests_Color.py | 220 ++++------- 9 files changed, 249 insertions(+), 506 deletions(-) diff --git a/python/src/graphics/styles/codac2_py_Color.cpp b/python/src/graphics/styles/codac2_py_Color.cpp index 1660c94a..5eec09de 100644 --- a/python/src/graphics/styles/codac2_py_Color.cpp +++ b/python/src/graphics/styles/codac2_py_Color.cpp @@ -53,11 +53,14 @@ void export_Color(py::module& m) "hex_str"_a) - // Html color + // Other formats .def("hex_str", &Color::hex_str, STRING_COLOR_HEX_STR_CONST) + .def("vec", &Color::vec, + VECTOR_COLOR_VEC_CONST) + // Conversions .def("rgb", &Color::rgb, diff --git a/python/src/graphics/styles/codac2_py_ColorMap.cpp b/python/src/graphics/styles/codac2_py_ColorMap.cpp index 2c7c28b2..83e720f4 100644 --- a/python/src/graphics/styles/codac2_py_ColorMap.cpp +++ b/python/src/graphics/styles/codac2_py_ColorMap.cpp @@ -23,6 +23,13 @@ void export_ColorMap(py::module& m) py::class_ exported_colormap(m, "ColorMap", COLORMAP_MAIN); exported_colormap + .def_readwrite("m", &ColorMap::m, + COLOR_MODEL_COLORMAP_M) + + .def(py::init(), + COLORMAP_COLORMAP_COLOR_MODEL, + "m"_a=Color::Model::RGB) + .def("color", &ColorMap::color, COLOR_COLORMAP_COLOR_FLOAT_CONST, "r"_a) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 9981b3e5..04a0157a 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -555,10 +555,9 @@ void Figure2D_IPE::print_header_page() for(auto& [k,c] : _colors) { - if (c.m == Color::HSV) - c = c.rgb(); + Color c_rgb = c.rgb(); _f << " \n"; + << "value=\"" << (float) (c_rgb[0]/255.) << " " <<(float) (c_rgb[1]/255.) << " " <<(float) (c_rgb[2]/255.) << "\" /> \n"; } _f << " \n \ diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index b121e943..8e147cdd 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -118,18 +118,21 @@ Color Color::hsv() const return *this; else { - float c_max = std::max({(*this)[0], (*this)[1], (*this)[2]}); - float c_min = std::min({(*this)[0], (*this)[1], (*this)[2]}); + float r = (*this)[0]/255.; + float g = (*this)[1]/255.; + float b = (*this)[2]/255.; + float c_max = std::max({r, g, b}); + float c_min = std::min({r, g, b}); float delta = c_max - c_min; float h = 0.0; if (delta != 0) { - if (c_max == (*this)[0]) { - h = fmod(((*this)[1] - (*this)[2]) / delta, 6.0); - } else if (c_max == (*this)[1]) { - h = ((*this)[2] - (*this)[0]) / delta + 2.0; - } else if (c_max == (*this)[2]) { - h = ((*this)[0] - (*this)[1]) / delta + 4.0; + if (c_max == r) { + h = fmod((g - b) / delta, 6.0); + } else if (c_max == g) { + h = (b - r) / delta + 2.0; + } else if (c_max == b) { + h = (r - g) / delta + 4.0; } h /= 6.0; if (h < 0) { @@ -162,4 +165,9 @@ std::string Color::hex_str() const } else return rgb().hex_str(); +} + +codac2::Vector Color::vec() const +{ + return codac2::Vector({(*this)[0], (*this)[1], (*this)[2], (*this)[3]}); } \ No newline at end of file diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index cc67ce30..eabe751d 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -12,8 +12,9 @@ #include #include #include -#include"codac2_assert.h" +#include"codac2_assert.h" +#include"codac2_Vector.h" namespace codac2 { @@ -37,10 +38,12 @@ namespace codac2 explicit Color(const std::initializer_list xyza, Model m_ = RGB); explicit Color(const std::string& hex_str); - // Html color + // other formats std::string hex_str() const; + codac2::Vector vec() const; + // Conversions Color rgb() const; diff --git a/src/graphics/styles/codac2_ColorMap.cpp b/src/graphics/styles/codac2_ColorMap.cpp index 7971462a..656a6e10 100644 --- a/src/graphics/styles/codac2_ColorMap.cpp +++ b/src/graphics/styles/codac2_ColorMap.cpp @@ -12,6 +12,9 @@ using namespace std; using namespace codac2; +ColorMap::ColorMap(Color::Model m_) : + m(m_) +{ } Color ColorMap::color(float r) const { @@ -30,6 +33,21 @@ Color ColorMap::color(float r) const Color color_lb = prev(it_ub)->second; Color color_ub = it_ub->second; + // Interpolation according to the ColorMap model + + if (m == Color::RGB) + { + color_lb = color_lb.rgb(); + color_ub = color_ub.rgb(); + } + + else if (m == Color::HSV) + { + color_lb = color_lb.hsv(); + color_ub = color_ub.hsv(); + } + + float local_ratio = (real_index - prev(it_ub)->first) / (it_ub->first - prev(it_ub)->first); return Color({(color_lb[0] + (color_ub[0] - color_lb[0]) * local_ratio), diff --git a/src/graphics/styles/codac2_ColorMap.h b/src/graphics/styles/codac2_ColorMap.h index 4ca78953..0205a4da 100644 --- a/src/graphics/styles/codac2_ColorMap.h +++ b/src/graphics/styles/codac2_ColorMap.h @@ -23,86 +23,91 @@ namespace codac2 */ struct ColorMap : public std::map { + Color::Model m; //RGB or HSV + + explicit ColorMap(Color::Model m_ = Color::RGB); Color color (float r) const; static ColorMap haxby() { - return ColorMap({{0,Color({39.,90.,211.})}, - {1,Color({40.,123.,245.})}, - {2,Color({45.,155.,253.})}, - {3,Color({73.,209.,255.})}, - {4,Color({100.,230.,254.})}, - {5,Color({118.,235.,226.})}, - {6,Color({135.,236.,187.})}, - {7,Color({194.,252.,165.})}, - {8,Color({217.,251.,151.})}, - {9,Color({233.,241.,131.})}, - {10,Color({252.,201.,96.})}, - {11,Color({255.,184.,84.})}, - {12,Color({255.,170.,75.})}, - {13,Color({255.,167.,83.})}, - {14,Color({255.,200.,158.})}, - {15,Color({255.,233.,217.})} - }); - - + ColorMap cmap( Color::RGB ); + cmap[0]=Color({39.,90.,211.}); + cmap[1]=Color({40.,123.,245.}); + cmap[2]=Color({45.,155.,253.}); + cmap[3]=Color({73.,209.,255.}); + cmap[4]=Color({100.,230.,254.}); + cmap[5]=Color({118.,235.,226.}); + cmap[6]=Color({135.,236.,187.}); + cmap[7]=Color({194.,252.,165.}); + cmap[8]=Color({217.,251.,151.}); + cmap[9]=Color({233.,241.,131.}); + cmap[10]=Color({252.,201.,96.}); + cmap[11]=Color({255.,184.,84.}); + cmap[12]=Color({255.,170.,75.}); + cmap[13]=Color({255.,167.,83.}); + cmap[14]=Color({255.,200.,158.}); + cmap[15]=Color({255.,233.,217.}); + return cmap; } static ColorMap basic() // Can't use default as name { - return ColorMap({{0,Color({10.,0.,121.})}, - {1,Color({40.,0.,150.})}, - {2,Color({20.,5.,175.})}, - {3,Color({0.,10.,200.})}, - {4,Color({0.,25.,212.})}, - {5,Color({0.,40.,224.})}, - {6,Color({26.,102.,240.})}, - {7,Color({13.,129.,248.})}, - {8,Color({25.,175.,255.})}, - {9,Color({50.,190.,255.})}, - {10,Color({68.,202.,255.})}, - {11,Color({97.,225.,240.})}, - {12,Color({106.,235.,225.})}, - {13,Color({124.,235.,200.})}, - {14,Color({138.,236.,174.})}, - {15,Color({172.,245.,168.})}, - {16,Color({205.,255.,162.})}, - {17,Color({223.,245.,141.})}, - {18,Color({240.,236.,121.})}, - {19,Color({247.,215.,104.})}, - {20,Color({255.,189.,87.})}, - {21,Color({255.,160.,69.})}, - {22,Color({244.,117.,75.})}, - {23,Color({238.,80.,78.})}, - {24,Color({255.,90.,90.})}, - {25,Color({255.,124.,124.})}, - {26,Color({255.,158.,158.})}, - {27,Color({245.,179.,174.})}, - {28,Color({255.,196.,196.})}, - {29,Color({255.,215.,215.})}, - {31,Color({255.,235.,235.})}, - {32,Color({255.,254.,253.})} - }); + ColorMap cmap( Color::RGB ); + cmap[0]=Color({10.,0.,121.}); + cmap[1]=Color({40.,0.,150.}); + cmap[2]=Color({20.,5.,175.}); + cmap[3]=Color({0.,10.,200.}); + cmap[4]=Color({0.,25.,212.}); + cmap[5]=Color({0.,40.,224.}); + cmap[6]=Color({26.,102.,240.}); + cmap[7]=Color({13.,129.,248.}); + cmap[8]=Color({25.,175.,255.}); + cmap[9]=Color({50.,190.,255.}); + cmap[10]=Color({68.,202.,255.}); + cmap[11]=Color({97.,225.,240.}); + cmap[12]=Color({106.,235.,225.}); + cmap[13]=Color({124.,235.,200.}); + cmap[14]=Color({138.,236.,174.}); + cmap[15]=Color({172.,245.,168.}); + cmap[16]=Color({205.,255.,162.}); + cmap[17]=Color({223.,245.,141.}); + cmap[18]=Color({240.,236.,121.}); + cmap[19]=Color({247.,215.,104.}); + cmap[20]=Color({255.,189.,87.}); + cmap[21]=Color({255.,160.,69.}); + cmap[22]=Color({244.,117.,75.}); + cmap[23]=Color({238.,80.,78.}); + cmap[24]=Color({255.,90.,90.}); + cmap[25]=Color({255.,124.,124.}); + cmap[26]=Color({255.,158.,158.}); + cmap[27]=Color({245.,179.,174.}); + cmap[28]=Color({255.,196.,196.}); + cmap[29]=Color({255.,215.,215.}); + cmap[30]=Color({255.,235.,235.}); + cmap[31]=Color({255.,254.,253.}); + return cmap; } static ColorMap blue_tube() { - return ColorMap({{0,Color({76.,110.,127.})}, - {1,Color({136.,197.,228.})} - }); + ColorMap cmap( Color::RGB ); + cmap[0]=Color({76.,110.,127.}); + cmap[1]=Color({136.,197.,228.}); + return cmap; } static ColorMap red_tube() { - return ColorMap({{0,Color({169.,55.,0.})}, - {1,Color({241.,140.,54.})} - }); + ColorMap cmap( Color::RGB ); + cmap[0]=Color({169.,55.,0.}); + cmap[1]=Color({241.,140.,54.}); + return cmap; } static ColorMap rainbow() { - ColorMap cmap; + ColorMap cmap( Color::HSV ); int i = 0; for(int h = 300 ; h > 0 ; h-=10) { diff --git a/tests/graphics/styles/codac2_tests_Color.cpp b/tests/graphics/styles/codac2_tests_Color.cpp index 9b356716..a9d0d20c 100644 --- a/tests/graphics/styles/codac2_tests_Color.cpp +++ b/tests/graphics/styles/codac2_tests_Color.cpp @@ -1,4 +1,4 @@ -/** +/** * Codac tests * ---------------------------------------------------------------------------- * \date 2024 @@ -8,300 +8,80 @@ */ #include -#include #include +#include using namespace std; using namespace codac2; -// Custom Matchers to manage tolerate errors - -// array matcher - -class Array4MatcherWithTolerance : public Catch::Matchers::MatcherBase> { - std::array m_expected; - int m_tolerance; - -public: - Array4MatcherWithTolerance(const std::array& expected, int tolerance) - : m_expected(expected), m_tolerance(tolerance) {} - - bool match(const std::array& actual) const override { - for (size_t i = 0; i < m_expected.size(); ++i) { - if (std::abs(actual[i] - m_expected[i]) > m_tolerance) { - return false; - } - } - return true; - } - - std::string describe() const override { - std::ostringstream oss; - oss << "is close to { "; - for (size_t i = 0; i < m_expected.size(); ++i) { - oss << m_expected[i]; - if (i < m_expected.size() - 1) oss << ", "; - } - oss << " } with tolerance " << m_tolerance; - return oss.str(); - } -}; - -// array matcher - -class Array3MatcherWithTolerance : public Catch::Matchers::MatcherBase> { - std::array m_expected; - int m_tolerance; - -public: - Array3MatcherWithTolerance(const std::array& expected, int tolerance) - : m_expected(expected), m_tolerance(tolerance) {} - - bool match(const std::array& actual) const override { - for (size_t i = 0; i < m_expected.size(); ++i) { - if (std::abs(actual[i] - m_expected[i]) > m_tolerance) { - return false; - } - } - return true; - } - - std::string describe() const override { - std::ostringstream oss; - oss << "is close to { "; - for (size_t i = 0; i < m_expected.size(); ++i) { - oss << m_expected[i]; - if (i < m_expected.size() - 1) oss << ", "; - } - oss << " } with tolerance " << m_tolerance; - return oss.str(); - } -}; - -// HTML color matcher - -class HtmlColorMatcherWithTolerance : public Catch::Matchers::MatcherBase { - std::string m_expected; - int m_tolerance; - - // Helper to convert a hex color to RGB - static std::array hexToRgb(const std::string& hex) { - assert(hex.size() == 7 && hex[0] == '#'); // Ensure format is #RRGGBB - return { - std::stoi(hex.substr(1, 2), nullptr, 16), - std::stoi(hex.substr(3, 2), nullptr, 16), - std::stoi(hex.substr(5, 2), nullptr, 16) - }; - } - -public: - HtmlColorMatcherWithTolerance(const std::string& expected, int tolerance) - : m_expected(expected), m_tolerance(tolerance) { - assert(m_expected.size() == 7 && m_expected[0] == '#'); // Ensure format is #RRGGBB - } - - bool match(const std::string& actual) const override { - if (actual.size() != 7 || actual[0] != '#') { - return false; // Invalid format - } - - auto expectedRgb = hexToRgb(m_expected); - auto actualRgb = hexToRgb(actual); - - for (size_t i = 0; i < 3; ++i) { - if (std::abs(actualRgb[i] - expectedRgb[i]) > m_tolerance) { - return false; - } - } - return true; - } - - std::string describe() const override { - std::ostringstream oss; - oss << "is close to " << m_expected << " with tolerance " << m_tolerance; - return oss.str(); - } -}; - -// RGBA HTML color matcher - -class HtmlColorMatcherWithToleranceRGBA : public Catch::Matchers::MatcherBase { - std::string m_expected; - int m_tolerance; - - // Helper to convert a hex color to RGBA - static std::array hexToRgba(const std::string& hex) { - assert(hex.size() == 9 && hex[0] == '#'); // Ensure format is #RRGGBBAA - return { - std::stoi(hex.substr(1, 2), nullptr, 16), - std::stoi(hex.substr(3, 2), nullptr, 16), - std::stoi(hex.substr(5, 2), nullptr, 16), - std::stoi(hex.substr(7, 2), nullptr, 16) - }; - } - -public: - HtmlColorMatcherWithToleranceRGBA(const std::string& expected, int tolerance) - : m_expected(expected), m_tolerance(tolerance) { - assert(m_expected.size() == 9 && m_expected[0] == '#'); // Ensure format is #RRGGBBAA - } - - bool match(const std::string& actual) const override { - if (actual.size() != 9 || actual[0] != '#') { - return false; // Invalid format - } - - auto expectedRgba = hexToRgba(m_expected); - auto actualRgba = hexToRgba(actual); - - for (size_t i = 0; i < 4; ++i) { - if (std::abs(actualRgba[i] - expectedRgba[i]) > m_tolerance) { - return false; - } - } - return true; - } - - std::string describe() const override { - std::ostringstream oss; - oss << "is close to " << m_expected << " with tolerance " << m_tolerance; - return oss.str(); - } -}; - -inline Array4MatcherWithTolerance IsCloseTo(const std::array& expected, int tolerance = 1) { - return Array4MatcherWithTolerance(expected, tolerance); -} - -inline Array3MatcherWithTolerance IsCloseTo(const std::array& expected, int tolerance = 1) { - return Array3MatcherWithTolerance(expected, tolerance); -} - -inline HtmlColorMatcherWithTolerance IsCloseToHtmlColor(const std::string& expected, int tolerance = 1) { - return HtmlColorMatcherWithTolerance(expected, tolerance); -} - -inline HtmlColorMatcherWithToleranceRGBA IsCloseToHtmlColorRGBA(const std::string& expected, int tolerance = 1) { - return HtmlColorMatcherWithToleranceRGBA(expected, tolerance); -} - - TEST_CASE("Color") { - { - // Red - - std::array d_rgb { 255,0,0 }; - std::array d_rgba { 255,0,0,255 }; - std::array d_hsv { 0,100,100 }; - std::array d_hsva { 0,100,100,100 }; - std::array d_rgb_f { 1.0,0.0,0.0 }; - std::array d_rgba_f { 1.0,0.0,0.0,1.0 }; - std::array d_hsv_f { 0.0,1.0,1.0 }; - std::array d_hsva_f { 0.0,1.0,1.0,1.0 }; - - vector v { - Color(d_rgb, InterpolMode::RGB /* InterpolMode::RGB is default */), - Color(d_rgba, InterpolMode::RGB), - Color(255,0,0, InterpolMode::RGB), - Color(255,0,0,255, InterpolMode::RGB), - Color(d_hsv, InterpolMode::HSV), - Color(d_hsva, InterpolMode::HSV), - Color(0,100,100, InterpolMode::HSV), - Color(0,100,100,100, InterpolMode::HSV), - Color(d_rgb_f, InterpolMode::RGB), - Color(d_rgba_f, InterpolMode::RGB), - Color( 1.0, 0.0, 0.0, InterpolMode::RGB), - Color( 1.0, 0.0, 0.0, 1.0, InterpolMode::RGB), - Color(d_hsv_f, InterpolMode::HSV), - Color(d_hsva_f, InterpolMode::HSV), - Color( 0.0, 1.0, 1.0, InterpolMode::HSV), - Color( 0.0, 1.0, 1.0, 1.0, InterpolMode::HSV), - Color("#FF0000") - }; - - for(const auto& c : v) { - CHECK_THAT(c.hex_str(), IsCloseToHtmlColor("#ff0000")); - CHECK_THAT(c.rgb(), IsCloseTo(std::array{ 255,0,0})); // return std::array - CHECK_THAT(c.rgba(), IsCloseTo(std::array{ 255,0,0,255})); // return std::array - CHECK_THAT(c.hsv(), IsCloseTo(std::array{ 0,100,100})); // return std::array - CHECK_THAT(c.hsva(), IsCloseTo(std::array{ 0,100,100,100})); // return std::array + // Red + + std::array d_rgb{255., 0., 0.}; + std::array d_rgba{255., 0., 0., 255.}; + std::array d_hsv{0., 100., 100.}; + std::array d_hsva{0., 100., 100., 100.}; + + vector v{ + Color(d_rgb, Color::RGB), + Color(d_rgba, Color::RGB), + Color(d_hsv, Color::HSV), + Color(d_hsva, Color::HSV), + Color("#FF0000")}; + + for (const auto &c : v) + { + CHECK(Approx(c.rgb().vec(),1.) == Color({255., 0., 0.}).vec()); + CHECK(Approx(c.rgb().vec(),1.) == Color({255., 0., 0., 255.}).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({0., 100., 100.}, Color::HSV).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({0., 100., 100., 100.}, Color::HSV).vec()); + } } - } - - { - // Pink full opacity - - int a = 255; - std::array d_rgb { 229,128,255 }; - std::array d_rgba { 229,128,255,a }; - std::array d_hsv { 288,50,100 }; - std::array d_hsva { 288,50,100,100}; - std::array d_rgb_f {(float) (229./255.), (float) (128./255.), (float) (255./255.)}; - std::array d_rgba_f {(float) (229./255.), (float) (128./255.), (float) (255./255.), 1.0}; - std::array d_hsv_f {(float) (288./360.), (float) (50./100.), (float) (100./100.)}; - std::array d_hsva_f {(float) (288./360.), (float) (50./100.), (float) (100./100.), 1.0}; - - vector v { - Color(d_rgb, InterpolMode::RGB /* InterpolMode::RGB is default */), - Color(d_rgba, InterpolMode::RGB), - Color(229,128,255, InterpolMode::RGB), - Color(229,128,255,a, InterpolMode::RGB), - Color(d_hsv, InterpolMode::HSV), - Color(d_hsva, InterpolMode::HSV), - Color(288,50,100, InterpolMode::HSV), - Color(288,50,100,100, InterpolMode::HSV), - Color(d_rgb_f, InterpolMode::RGB), - Color(d_rgba_f, InterpolMode::RGB), - Color( 229./255., 128./255., 255./255., InterpolMode::RGB), - Color( 229./255., 128./255., 255./255., 1.0, InterpolMode::RGB), - Color(d_hsv_f, InterpolMode::HSV), - Color(d_hsva_f, InterpolMode::HSV), - Color( 288./360., 50./100., 100./100., InterpolMode::HSV), - Color( 288./360.,50./100., 100./100., 1.0, InterpolMode::HSV), - Color("#e580ff") - }; - - for(const auto& c : v) { - CHECK_THAT(c.hex_str(), IsCloseToHtmlColor("#e580ff")); - CHECK_THAT(c.rgb(), IsCloseTo(std::array{ 229,128,255})); // return std::array - CHECK_THAT(c.rgba(), IsCloseTo(std::array{ 229,128,255,a})); // return std::array - CHECK_THAT(c.hsv(), IsCloseTo(std::array{ 288,50,100})); // return std::array - CHECK_THAT(c.hsva(), IsCloseTo(std::array{ 288,50,100,100})); // return std::array + // Pink full opacity + + float a = 255.; + std::array d_rgb{229., 128., 255.}; + std::array d_rgba{229., 128., 255., a}; + std::array d_hsv{288., 50., 100.}; + std::array d_hsva{288., 50., 100., 100.}; + + vector v{ + Color(d_rgb, Color::RGB), + Color(d_rgba, Color::RGB), + Color(d_hsv, Color::HSV), + Color(d_hsva, Color::HSV), + Color("#e580ff")}; + + for (const auto &c : v) + { + CHECK(Approx(c.rgb().vec(),1.) == Color({229., 128., 255.}).vec()); + CHECK(Approx(c.rgb().vec(),1.) == Color({229., 128., 255., a}).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({288., 50., 100.}, Color::HSV).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({288., 50., 100., 100.}, Color::HSV).vec()); + } } - } - - { - // Pink 40% opacity - - int a = 0.4*255; - std::array d_rgba { 229,128,255,a }; - std::array d_hsva { 288,50,100,40 }; - std::array d_rgba_f {(float) (229./255.), (float) (128./255.), (float) (255./255.),(float) 0.4}; - std::array d_hsva_f {(float) (288./360.), (float) (50./100.), (float) (100./100.), (float) 0.4}; - vector v { - Color(d_rgba, InterpolMode::RGB), - Color(229,128,255,a, InterpolMode::RGB), - Color(d_hsva, InterpolMode::HSV), - Color(288,50,100,40, InterpolMode::HSV), - Color(d_rgba_f, InterpolMode::RGB), - Color( 229./255., 128./255., 255./255., 0.4, InterpolMode::RGB), - Color(d_hsva_f, InterpolMode::HSV), - Color( 288./360.,50./100., 100./100., 0.4, InterpolMode::HSV), - Color("#e580ff66") - }; + { + // Pink 40% opacity + + float a = 0.4*255.; + std::array d_rgba { 229.,128.,255.,a }; + std::array d_hsva { 288.,50.,100.,40. }; + + vector v { + Color(d_rgba, Color::RGB), + Color(d_hsva, Color::HSV), + Color("#e580ff66") + }; - for(const auto& c : v) - { - CHECK_THAT(c.hex_str(), IsCloseToHtmlColorRGBA("#e580ff66")); - CHECK_THAT(c.rgb(), IsCloseTo(std::array{ 229,128,255})); // return std::array - CHECK_THAT(c.rgba(), IsCloseTo(std::array{ 229,128,255,a})); // return std::array - CHECK_THAT(c.hsv(), IsCloseTo(std::array{ 288,50,100})); // return std::array - CHECK_THAT(c.hsva(), IsCloseTo(std::array{ 288,50,100,40})); // return std::array - } - } + for(const auto& c : v) + { + CHECK(Approx(c.rgb().vec(),1.) == Color({229.,128.,255.,a}).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({288.,50.,100.,40.},Color::HSV).vec()); + } + } } \ No newline at end of file diff --git a/tests/graphics/styles/codac2_tests_Color.py b/tests/graphics/styles/codac2_tests_Color.py index fb52703a..21041f96 100644 --- a/tests/graphics/styles/codac2_tests_Color.py +++ b/tests/graphics/styles/codac2_tests_Color.py @@ -10,65 +10,6 @@ import unittest from codac import * -class ArrayMatcherWithTolerance: - def __init__(self, expected, tolerance=1): - self.expected = expected - self.tolerance = tolerance - - def match(self, actual): - if len(actual) != len(self.expected): - return False - for i in range(len(self.expected)): - if abs(actual[i] - self.expected[i]).mid() > self.tolerance: - return False - return True - - def describe(self): - return f'is close to {self.expected} with tolerance {self.tolerance}' - - -import re - -class HtmlColorMatcherWithTolerance: - def __init__(self, expected: str, tolerance: int = 1): - assert self._is_valid_color(expected), f"Invalid color format: {expected}" - self.expected = expected - self.tolerance = tolerance - - def _is_valid_color(self, color: str) -> bool: - """Validate the color format as #RRGGBBAA or #RRGGBB.""" - return bool(re.match(r"^#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$", color)) - - def _hex_to_components(self, hex_color: str): - """Convert a #RRGGBBAA or #RRGGBB color to a tuple of integers.""" - if len(hex_color) == 7: # #RRGGBB - return tuple(int(hex_color[i:i+2], 16) for i in range(1, 7, 2)) - elif len(hex_color) == 9: # #RRGGBBAA - return tuple(int(hex_color[i:i+2], 16) for i in range(1, 9, 2)) - - def match(self, actual: str) -> bool: - """Check if the actual color matches the expected color within the tolerance.""" - if not self._is_valid_color(actual): - return False - - expected_components = self._hex_to_components(self.expected) - actual_components = self._hex_to_components(actual) - - if len(expected_components) != len(actual_components): - return False - - return all(abs(e - a).mid() <= self.tolerance for e, a in zip(expected_components, actual_components)) - - def describe(self) -> str: - """Provide a description of the matcher.""" - return f"is close to {self.expected} with tolerance {self.tolerance}" - - -def is_close_to(expected, tolerance=1): - return ArrayMatcherWithTolerance(expected, tolerance) - -def is_close_to_html_color(expected, tolerance=1): - return HtmlColorMatcherWithTolerance(expected, tolerance) class TestColor(unittest.TestCase): @@ -79,104 +20,83 @@ def test_Color(self): d_rgba = [255, 0, 0, 255] d_hsv = [0, 100, 100] d_hsva = [0, 100, 100, 100] - d_rgb_f= [1.0, 0.0, 0.0] - d_rgba_f= [1.0, 0.0, 0.0, 1.0] - d_hsv_f= [0.0, 1.0, 1.0] - d_hsva_f= [0.0, 1.0, 1.0, 1.0] colors = [ - Color(d_rgb, InterpolMode.RGB), - Color(d_rgba, InterpolMode.RGB), - Color(255, 0, 0, interpol_mode=InterpolMode.RGB), - Color(255, 0, 0, 255, InterpolMode.RGB), - Color(d_hsv, InterpolMode.HSV), - Color(d_hsva, InterpolMode.HSV), - Color(0, 100, 100, interpol_mode=InterpolMode.HSV), - Color(0, 100, 100, 100, InterpolMode.HSV), - Color(d_rgb_f, InterpolMode.RGB), - Color(d_rgba_f, InterpolMode.RGB), - Color(1.0, 0.0, 0.0, interpol_mode=InterpolMode.RGB), - Color(1.0, 0.0, 0.0, 1.0, InterpolMode.RGB), - Color(d_hsv_f, InterpolMode.HSV), - Color(d_hsva_f, InterpolMode.HSV), - Color(0.0, 1.0, 1.0, interpol_mode=InterpolMode.HSV), - Color(0.0, 1.0, 1.0, 1.0, InterpolMode.HSV), + Color(d_rgb, Model.RGB), + Color(d_rgba, Model.RGB), + Color(d_hsv, Model.HSV), + Color(d_hsva, Model.HSV), Color("#FF0000") ] for c in colors: - self.assertTrue(is_close_to_html_color("#FF0000").match(c.hex_str())) - self.assertTrue(is_close_to([255, 0, 0]).match(c.rgb())) - self.assertTrue(is_close_to([255, 0, 0, 255]).match(c.rgba())) - self.assertTrue(is_close_to([0, 100, 100]).match(c.hsv())) - self.assertTrue(is_close_to([0, 100, 100, 100]).match(c.hsva())) - - # Pink full opacity - - d_rgb = [229,128,255] - d_rgba = [229,128,255,255] - d_hsv = [288,50,100] - d_hsva = [288,50,100,100] - d_rgb_f = [229.0/255.0, 128.0/255.0, 255.0/255.0] - d_rgba_f = [229.0/255.0, 128.0/255.0, 255.0/255.0, 1.0] - d_hsv_f = [288.0/360.0, 50.0/100.0, 100.0/100.0] - d_hsva_f = [288.0/360.0, 50.0/100.0, 100.0/100.0, 1.0] - - colors = [ - Color(d_rgb, InterpolMode.RGB), - Color(d_rgba, InterpolMode.RGB), - Color(229,128,255, interpol_mode=InterpolMode.RGB), - Color(229,128,255,255, InterpolMode.RGB), - Color(d_hsv, InterpolMode.HSV), - Color(d_hsva, InterpolMode.HSV), - Color(288,50,100, interpol_mode=InterpolMode.HSV), - Color(288,50,100,100, InterpolMode.HSV), - Color(d_rgb_f, InterpolMode.RGB), - Color(d_rgba_f, InterpolMode.RGB), - Color(229.0/255.0, 128.0/255.0, 255.0/255.0, interpol_mode=InterpolMode.RGB), - Color(229.0/255.0, 128.0/255.0, 255.0/255.0, 1.0, InterpolMode.RGB), - Color(d_hsv_f, InterpolMode.HSV), - Color(d_hsva_f, InterpolMode.HSV), - Color(288.0/360.0, 50.0/100.0, 100.0/100.0, interpol_mode=InterpolMode.HSV), - Color(288.0/360.0, 50.0/100.0, 100.0/100.0, 1.0, InterpolMode.HSV), - Color("#E580FF") - ] - - for c in colors: - self.assertTrue(is_close_to_html_color("#E580FF").match(c.hex_str())) - self.assertTrue(is_close_to([229,128,255]).match(c.rgb())) - self.assertTrue(is_close_to([229,128,255,255]).match(c.rgba())) - self.assertTrue(is_close_to([288,50,100]).match(c.hsv())) - self.assertTrue(is_close_to([288,50,100,100]).match(c.hsva())) - - # Pink 40% opacity - - a_rgb=102 - a_hsv=40 - d_rgba = [229,128,255,a_rgb] - d_hsva = [288,50,100,a_hsv] - d_rgba_f = [229.0/255.0, 128.0/255.0, 255.0/255.0, 102.0/255.0] - d_hsva_f = [288.0/360.0, 50.0/100.0, 100.0/100.0, 40.0/100.0] - - colors = [ - Color(d_rgba, InterpolMode.RGB), - Color(229,128,255,a_rgb, InterpolMode.RGB), - Color(d_hsva, InterpolMode.HSV), - Color(288,50,100,a_hsv, InterpolMode.HSV), - Color(d_rgba_f, InterpolMode.RGB), - Color(229.0/255.0, 128.0/255.0, 255.0/255.0, 102.0/255.0, InterpolMode.RGB), - Color(d_hsva_f, InterpolMode.HSV), - Color(288.0/360.0, 50.0/100.0, 100.0/100.0, 40.0/100.0, InterpolMode.HSV), - Color("#E580FF66") - ] - for c in colors: - self.assertTrue(is_close_to_html_color("#E580FF66").match(c.hex_str())) - self.assertTrue(is_close_to([229,128,255]).match(c.rgb())) - self.assertTrue(is_close_to([229,128,255,a_rgb]).match(c.rgba())) - self.assertTrue(is_close_to([288,50,100]).match(c.hsv())) - self.assertTrue(is_close_to([288,50,100,a_hsv]).match(c.hsva())) - + self.assertTrue(Color([255, 0, 0]).rgb().vec().match(Approx(c.rgb().vec(), 1.0))) + + # # Pink full opacity + + # d_rgb = [229,128,255] + # d_rgba = [229,128,255,255] + # d_hsv = [288,50,100] + # d_hsva = [288,50,100,100] + # d_rgb_f = [229.0/255.0, 128.0/255.0, 255.0/255.0] + # d_rgba_f = [229.0/255.0, 128.0/255.0, 255.0/255.0, 1.0] + # d_hsv_f = [288.0/360.0, 50.0/100.0, 100.0/100.0] + # d_hsva_f = [288.0/360.0, 50.0/100.0, 100.0/100.0, 1.0] + + # colors = [ + # Color(d_rgb, Model.RGB), + # Color(d_rgba, Model.RGB), + # Color(229,128,255, interpol_mode=Model.RGB), + # Color(229,128,255,255, Model.RGB), + # Color(d_hsv, Model.HSV), + # Color(d_hsva, Model.HSV), + # Color(288,50,100, interpol_mode=Model.HSV), + # Color(288,50,100,100, Model.HSV), + # Color(d_rgb_f, Model.RGB), + # Color(d_rgba_f, Model.RGB), + # Color(229.0/255.0, 128.0/255.0, 255.0/255.0, interpol_mode=Model.RGB), + # Color(229.0/255.0, 128.0/255.0, 255.0/255.0, 1.0, Model.RGB), + # Color(d_hsv_f, Model.HSV), + # Color(d_hsva_f, Model.HSV), + # Color(288.0/360.0, 50.0/100.0, 100.0/100.0, interpol_mode=Model.HSV), + # Color(288.0/360.0, 50.0/100.0, 100.0/100.0, 1.0, Model.HSV), + # Color("#E580FF") + # ] + + # for c in colors: + # self.assertTrue(is_close_to_html_color("#E580FF").match(c.hex_str())) + # self.assertTrue(is_close_to([229,128,255]).match(c.rgb())) + # self.assertTrue(is_close_to([229,128,255,255]).match(c.rgba())) + # self.assertTrue(is_close_to([288,50,100]).match(c.hsv())) + # self.assertTrue(is_close_to([288,50,100,100]).match(c.hsva())) + + # # Pink 40% opacity + + # a_rgb=102 + # a_hsv=40 + # d_rgba = [229,128,255,a_rgb] + # d_hsva = [288,50,100,a_hsv] + # d_rgba_f = [229.0/255.0, 128.0/255.0, 255.0/255.0, 102.0/255.0] + # d_hsva_f = [288.0/360.0, 50.0/100.0, 100.0/100.0, 40.0/100.0] + + # colors = [ + # Color(d_rgba, Model.RGB), + # Color(229,128,255,a_rgb, Model.RGB), + # Color(d_hsva, Model.HSV), + # Color(288,50,100,a_hsv, Model.HSV), + # Color(d_rgba_f, Model.RGB), + # Color(229.0/255.0, 128.0/255.0, 255.0/255.0, 102.0/255.0, Model.RGB), + # Color(d_hsva_f, Model.HSV), + # Color(288.0/360.0, 50.0/100.0, 100.0/100.0, 40.0/100.0, Model.HSV), + # Color("#E580FF66") + # ] + # for c in colors: + # self.assertTrue(is_close_to_html_color("#E580FF66").match(c.hex_str())) + # self.assertTrue(is_close_to([229,128,255]).match(c.rgb())) + # self.assertTrue(is_close_to([229,128,255,a_rgb]).match(c.rgba())) + # self.assertTrue(is_close_to([288,50,100]).match(c.hsv())) + # self.assertTrue(is_close_to([288,50,100,a_hsv]).match(c.hsva())) From 6e3bbfd544430454b771ea57feeaa27c72a193c5 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 3 Dec 2024 18:49:09 +0100 Subject: [PATCH 087/102] [graphics] all tests passed --- .../src/graphics/styles/codac2_py_Color.cpp | 18 +-- .../graphics/styles/codac2_py_ColorMap.cpp | 8 +- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 2 +- src/graphics/styles/codac2_Color.cpp | 20 ++-- src/graphics/styles/codac2_Color.h | 22 ++-- src/graphics/styles/codac2_ColorMap.cpp | 6 +- src/graphics/styles/codac2_ColorMap.h | 16 +-- tests/graphics/styles/codac2_tests_Color.cpp | 30 ++--- tests/graphics/styles/codac2_tests_Color.py | 107 +++++++----------- 9 files changed, 102 insertions(+), 127 deletions(-) diff --git a/python/src/graphics/styles/codac2_py_Color.cpp b/python/src/graphics/styles/codac2_py_Color.cpp index 5eec09de..cdd321c2 100644 --- a/python/src/graphics/styles/codac2_py_Color.cpp +++ b/python/src/graphics/styles/codac2_py_Color.cpp @@ -23,9 +23,9 @@ using namespace pybind11::literals; void export_Color(py::module& m) { - py::enum_(m, "Model") - .value("RGB", Color::Model::RGB) - .value("HSV", Color::Model::HSV) + py::enum_(m, "Model") + .value("RGB", Model::RGB) + .value("HSV", Model::HSV) ; py::class_ exported_color(m, "Color", COLOR_MAIN); @@ -36,17 +36,17 @@ void export_Color(py::module& m) .def(py::init<>(),COLOR_COLOR) - .def(py::init&,Color::Model>(), + .def(py::init&,Model>(), COLOR_COLOR_CONST_ARRAY_FLOAT3_REF_MODEL, - "xyz"_a, "m_"_a=Color::Model::RGB) + "xyz"_a, "m_"_a=Model::RGB) - .def(py::init&,Color::Model>(), + .def(py::init&,Model>(), COLOR_COLOR_CONST_ARRAY_FLOAT4_REF_MODEL, - "xyza"_a, "m_"_a=Color::Model::RGB) + "xyza"_a, "m_"_a=Model::RGB) - .def(py::init&,Color::Model>(), + .def(py::init&,Model>(), COLOR_COLOR_CONST_INITIALIZER_LIST_FLOAT_MODEL, - "xyza"_a, "m_"_a=Color::Model::RGB) + "xyza"_a, "m_"_a=Model::RGB) .def(py::init(), COLOR_COLOR_CONST_STRING_REF, diff --git a/python/src/graphics/styles/codac2_py_ColorMap.cpp b/python/src/graphics/styles/codac2_py_ColorMap.cpp index 83e720f4..3ba8d5fc 100644 --- a/python/src/graphics/styles/codac2_py_ColorMap.cpp +++ b/python/src/graphics/styles/codac2_py_ColorMap.cpp @@ -24,11 +24,11 @@ void export_ColorMap(py::module& m) exported_colormap .def_readwrite("m", &ColorMap::m, - COLOR_MODEL_COLORMAP_M) + MODEL_COLORMAP_M) - .def(py::init(), - COLORMAP_COLORMAP_COLOR_MODEL, - "m"_a=Color::Model::RGB) + .def(py::init(), + COLORMAP_COLORMAP_MODEL, + "m"_a=Model::RGB) .def("color", &ColorMap::color, COLOR_COLORMAP_COLOR_FLOAT_CONST, diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 04a0157a..41005b72 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -82,7 +82,7 @@ std::string ipe_str(const Color& c) int ipe_opacity(const Color& c) { - return (int)(10.*round(10.*(c.m==Color::RGB ? (c[3]/255.):(c[3]/100.)))); + return (int)(10.*round(10.*(c.m==Model::RGB ? (c[3]/255.):(c[3]/100.)))); } void Figure2D_IPE::begin_path(const StyleProperties& s, bool tip=false) diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index 8e147cdd..9d344af1 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -13,7 +13,7 @@ using namespace std; using namespace codac2; Color::Color() - : m(RGB) + : m(Model::RGB) { (*this)[0] = 0.; (*this)[1] = 0.; @@ -27,15 +27,15 @@ Color::Color(const std::array& xyz, Model m_) (*this)[0] = xyz[0]; (*this)[1] = xyz[1]; (*this)[2] = xyz[2]; - (*this)[3] = (m == RGB ? 255. : 100.); + (*this)[3] = (m == Model::RGB ? 255. : 100.); } Color::Color(const std::array& xyza, Model m_) : m(m_) { - if (m_==RGB) + if (m_==Model::RGB) assert(xyza[0] >= 0. && xyza[0] <= 255. && xyza[1]>=0. && xyza[1] <= 255. && xyza[2]>=0. && xyza[2] <= 255. && xyza[3]>=0. && xyza[3] <= 255.); - else if (m_==HSV) + else if (m_==Model::HSV) assert(xyza[0] >= 0. && xyza[0] <= 360. && xyza[1]>=0. && xyza[1] <= 100. && xyza[2]>=0. && xyza[2] <= 100. && xyza[3]>=0. && xyza[3] <= 100.); (*this)[0] = xyza[0]; (*this)[1] = xyza[1]; @@ -52,7 +52,7 @@ Color::Color(const std::string& hex_str) assert(hex_str.size() == 7 || hex_str.size() == 9); assert(hex_str[0] == '#'); - m = RGB; + m = Model::RGB; int red,green,blue,a; std::istringstream(hex_str.substr(1,2)) >> std::hex >> red; @@ -75,7 +75,7 @@ Color::Color(const std::string& hex_str) Color Color::rgb() const { - if (m==RGB) + if (m==Model::RGB) return *this; else { @@ -108,13 +108,13 @@ Color Color::rgb() const g *= 255.; b *= 255.; - return Color({r, g, b,(float) ((*this)[3]*2.55)},RGB); + return Color({r, g, b,(float) ((*this)[3]*2.55)},Model::RGB); } } Color Color::hsv() const { - if (m==HSV) + if (m==Model::HSV) return *this; else { @@ -148,13 +148,13 @@ Color Color::hsv() const s*=100.; v*=100.; - return Color({h, s, v,(float) ((*this)[3]/2.55)},HSV); + return Color({h, s, v,(float) ((*this)[3]/2.55)},Model::HSV); } } std::string Color::hex_str() const { - if (m == RGB) + if (m == Model::RGB) { std::stringstream s; s << std::hex << std::setfill('0'); diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index eabe751d..d3a3d797 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -19,23 +19,23 @@ namespace codac2 { + enum class Model + { + RGB = 0x01, + HSV = 0x02 + }; struct Color : public std::array { - enum Model - { - RGB = 0x01, - HSV = 0x02 - }; - Model m = RGB; //RGB or HSV + Model m = Model::RGB; //RGB or HSV // Constructors explicit Color(); - explicit Color(const std::array& xyz, Model m_ = RGB); - explicit Color(const std::array& xyza, Model m_ = RGB); - explicit Color(const std::initializer_list xyza, Model m_ = RGB); + explicit Color(const std::array& xyz, Model m_ = Model::RGB); + explicit Color(const std::array& xyza, Model m_ = Model::RGB); + explicit Color(const std::initializer_list xyza, Model m_ = Model::RGB); explicit Color(const std::string& hex_str); // other formats @@ -53,9 +53,9 @@ namespace codac2 friend std::ostream& operator<<(std::ostream& os, const Color& c) { - if (c.m == RGB) + if (c.m == Model::RGB) os << "RGB Color (" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << ")"; - else if (c.m == HSV) + else if (c.m == Model::HSV) os << "HSV Color (" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << ")"; return os; } diff --git a/src/graphics/styles/codac2_ColorMap.cpp b/src/graphics/styles/codac2_ColorMap.cpp index 656a6e10..f63b63f0 100644 --- a/src/graphics/styles/codac2_ColorMap.cpp +++ b/src/graphics/styles/codac2_ColorMap.cpp @@ -12,7 +12,7 @@ using namespace std; using namespace codac2; -ColorMap::ColorMap(Color::Model m_) : +ColorMap::ColorMap(Model m_) : m(m_) { } @@ -35,13 +35,13 @@ Color ColorMap::color(float r) const // Interpolation according to the ColorMap model - if (m == Color::RGB) + if (m == Model::RGB) { color_lb = color_lb.rgb(); color_ub = color_ub.rgb(); } - else if (m == Color::HSV) + else if (m == Model::HSV) { color_lb = color_lb.hsv(); color_ub = color_ub.hsv(); diff --git a/src/graphics/styles/codac2_ColorMap.h b/src/graphics/styles/codac2_ColorMap.h index 0205a4da..55c0d290 100644 --- a/src/graphics/styles/codac2_ColorMap.h +++ b/src/graphics/styles/codac2_ColorMap.h @@ -23,15 +23,15 @@ namespace codac2 */ struct ColorMap : public std::map { - Color::Model m; //RGB or HSV + Model m; //RGB or HSV - explicit ColorMap(Color::Model m_ = Color::RGB); + explicit ColorMap(Model m_ = Model::RGB); Color color (float r) const; static ColorMap haxby() { - ColorMap cmap( Color::RGB ); + ColorMap cmap( Model::RGB ); cmap[0]=Color({39.,90.,211.}); cmap[1]=Color({40.,123.,245.}); cmap[2]=Color({45.,155.,253.}); @@ -53,7 +53,7 @@ namespace codac2 static ColorMap basic() // Can't use default as name { - ColorMap cmap( Color::RGB ); + ColorMap cmap( Model::RGB ); cmap[0]=Color({10.,0.,121.}); cmap[1]=Color({40.,0.,150.}); cmap[2]=Color({20.,5.,175.}); @@ -91,7 +91,7 @@ namespace codac2 static ColorMap blue_tube() { - ColorMap cmap( Color::RGB ); + ColorMap cmap( Model::RGB ); cmap[0]=Color({76.,110.,127.}); cmap[1]=Color({136.,197.,228.}); return cmap; @@ -99,7 +99,7 @@ namespace codac2 static ColorMap red_tube() { - ColorMap cmap( Color::RGB ); + ColorMap cmap( Model::RGB ); cmap[0]=Color({169.,55.,0.}); cmap[1]=Color({241.,140.,54.}); return cmap; @@ -107,11 +107,11 @@ namespace codac2 static ColorMap rainbow() { - ColorMap cmap( Color::HSV ); + ColorMap cmap( Model::HSV ); int i = 0; for(int h = 300 ; h > 0 ; h-=10) { - cmap[i]=Color({(float)h,100.,100.},Color::HSV); + cmap[i]=Color({(float)h,100.,100.},Model::HSV); i++; } return cmap; diff --git a/tests/graphics/styles/codac2_tests_Color.cpp b/tests/graphics/styles/codac2_tests_Color.cpp index a9d0d20c..8ae4e0dd 100644 --- a/tests/graphics/styles/codac2_tests_Color.cpp +++ b/tests/graphics/styles/codac2_tests_Color.cpp @@ -25,18 +25,18 @@ TEST_CASE("Color") std::array d_hsva{0., 100., 100., 100.}; vector v{ - Color(d_rgb, Color::RGB), - Color(d_rgba, Color::RGB), - Color(d_hsv, Color::HSV), - Color(d_hsva, Color::HSV), + Color(d_rgb, Model::RGB), + Color(d_rgba, Model::RGB), + Color(d_hsv, Model::HSV), + Color(d_hsva, Model::HSV), Color("#FF0000")}; for (const auto &c : v) { CHECK(Approx(c.rgb().vec(),1.) == Color({255., 0., 0.}).vec()); CHECK(Approx(c.rgb().vec(),1.) == Color({255., 0., 0., 255.}).vec()); - CHECK(Approx(c.hsv().vec(),1.) == Color({0., 100., 100.}, Color::HSV).vec()); - CHECK(Approx(c.hsv().vec(),1.) == Color({0., 100., 100., 100.}, Color::HSV).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({0., 100., 100.}, Model::HSV).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({0., 100., 100., 100.}, Model::HSV).vec()); } } @@ -50,18 +50,18 @@ TEST_CASE("Color") std::array d_hsva{288., 50., 100., 100.}; vector v{ - Color(d_rgb, Color::RGB), - Color(d_rgba, Color::RGB), - Color(d_hsv, Color::HSV), - Color(d_hsva, Color::HSV), + Color(d_rgb, Model::RGB), + Color(d_rgba, Model::RGB), + Color(d_hsv, Model::HSV), + Color(d_hsva, Model::HSV), Color("#e580ff")}; for (const auto &c : v) { CHECK(Approx(c.rgb().vec(),1.) == Color({229., 128., 255.}).vec()); CHECK(Approx(c.rgb().vec(),1.) == Color({229., 128., 255., a}).vec()); - CHECK(Approx(c.hsv().vec(),1.) == Color({288., 50., 100.}, Color::HSV).vec()); - CHECK(Approx(c.hsv().vec(),1.) == Color({288., 50., 100., 100.}, Color::HSV).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({288., 50., 100.}, Model::HSV).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({288., 50., 100., 100.}, Model::HSV).vec()); } } @@ -73,15 +73,15 @@ TEST_CASE("Color") std::array d_hsva { 288.,50.,100.,40. }; vector v { - Color(d_rgba, Color::RGB), - Color(d_hsva, Color::HSV), + Color(d_rgba, Model::RGB), + Color(d_hsva, Model::HSV), Color("#e580ff66") }; for(const auto& c : v) { CHECK(Approx(c.rgb().vec(),1.) == Color({229.,128.,255.,a}).vec()); - CHECK(Approx(c.hsv().vec(),1.) == Color({288.,50.,100.,40.},Color::HSV).vec()); + CHECK(Approx(c.hsv().vec(),1.) == Color({288.,50.,100.,40.},Model::HSV).vec()); } } } \ No newline at end of file diff --git a/tests/graphics/styles/codac2_tests_Color.py b/tests/graphics/styles/codac2_tests_Color.py index 21041f96..bd9e4c8e 100644 --- a/tests/graphics/styles/codac2_tests_Color.py +++ b/tests/graphics/styles/codac2_tests_Color.py @@ -31,73 +31,48 @@ def test_Color(self): ] for c in colors: - self.assertTrue(Color([255, 0, 0]).rgb().vec().match(Approx(c.rgb().vec(), 1.0))) - - # # Pink full opacity - - # d_rgb = [229,128,255] - # d_rgba = [229,128,255,255] - # d_hsv = [288,50,100] - # d_hsva = [288,50,100,100] - # d_rgb_f = [229.0/255.0, 128.0/255.0, 255.0/255.0] - # d_rgba_f = [229.0/255.0, 128.0/255.0, 255.0/255.0, 1.0] - # d_hsv_f = [288.0/360.0, 50.0/100.0, 100.0/100.0] - # d_hsva_f = [288.0/360.0, 50.0/100.0, 100.0/100.0, 1.0] - - # colors = [ - # Color(d_rgb, Model.RGB), - # Color(d_rgba, Model.RGB), - # Color(229,128,255, interpol_mode=Model.RGB), - # Color(229,128,255,255, Model.RGB), - # Color(d_hsv, Model.HSV), - # Color(d_hsva, Model.HSV), - # Color(288,50,100, interpol_mode=Model.HSV), - # Color(288,50,100,100, Model.HSV), - # Color(d_rgb_f, Model.RGB), - # Color(d_rgba_f, Model.RGB), - # Color(229.0/255.0, 128.0/255.0, 255.0/255.0, interpol_mode=Model.RGB), - # Color(229.0/255.0, 128.0/255.0, 255.0/255.0, 1.0, Model.RGB), - # Color(d_hsv_f, Model.HSV), - # Color(d_hsva_f, Model.HSV), - # Color(288.0/360.0, 50.0/100.0, 100.0/100.0, interpol_mode=Model.HSV), - # Color(288.0/360.0, 50.0/100.0, 100.0/100.0, 1.0, Model.HSV), - # Color("#E580FF") - # ] - - # for c in colors: - # self.assertTrue(is_close_to_html_color("#E580FF").match(c.hex_str())) - # self.assertTrue(is_close_to([229,128,255]).match(c.rgb())) - # self.assertTrue(is_close_to([229,128,255,255]).match(c.rgba())) - # self.assertTrue(is_close_to([288,50,100]).match(c.hsv())) - # self.assertTrue(is_close_to([288,50,100,100]).match(c.hsva())) - - # # Pink 40% opacity - - # a_rgb=102 - # a_hsv=40 - # d_rgba = [229,128,255,a_rgb] - # d_hsva = [288,50,100,a_hsv] - # d_rgba_f = [229.0/255.0, 128.0/255.0, 255.0/255.0, 102.0/255.0] - # d_hsva_f = [288.0/360.0, 50.0/100.0, 100.0/100.0, 40.0/100.0] - - # colors = [ - # Color(d_rgba, Model.RGB), - # Color(229,128,255,a_rgb, Model.RGB), - # Color(d_hsva, Model.HSV), - # Color(288,50,100,a_hsv, Model.HSV), - # Color(d_rgba_f, Model.RGB), - # Color(229.0/255.0, 128.0/255.0, 255.0/255.0, 102.0/255.0, Model.RGB), - # Color(d_hsva_f, Model.HSV), - # Color(288.0/360.0, 50.0/100.0, 100.0/100.0, 40.0/100.0, Model.HSV), - # Color("#E580FF66") - # ] - # for c in colors: - # self.assertTrue(is_close_to_html_color("#E580FF66").match(c.hex_str())) - # self.assertTrue(is_close_to([229,128,255]).match(c.rgb())) - # self.assertTrue(is_close_to([229,128,255,a_rgb]).match(c.rgba())) - # self.assertTrue(is_close_to([288,50,100]).match(c.hsv())) - # self.assertTrue(is_close_to([288,50,100,a_hsv]).match(c.hsva())) + self.assertTrue(Approx(c.rgb().vec(), 1.0)==Color([255, 0, 0]).rgb().vec()) + self.assertTrue(Approx(c.rgb().vec(), 1.0)==Color([255, 0, 0, 255]).rgb().vec()) + self.assertTrue(Approx(c.hsv().vec(), 1.0)==Color([0, 100, 100],Model.HSV).hsv().vec()) + self.assertTrue(Approx(c.hsv().vec(), 1.0)==Color([0, 100, 100, 100],Model.HSV).hsv().vec()) + # Pink full opacity + + d_rgb = [229,128,255] + d_rgba = [229,128,255,255] + d_hsv = [288,50,100] + d_hsva = [288,50,100,100] + + colors = [ + Color(d_rgb, Model.RGB), + Color(d_rgba, Model.RGB), + Color(d_hsv, Model.HSV), + Color(d_hsva, Model.HSV), + Color("#E580FF") + ] + + for c in colors: + self.assertTrue(Approx(c.rgb().vec(), 1.0)==Color([229,128,255]).rgb().vec()) + self.assertTrue(Approx(c.rgb().vec(), 1.0)==Color([229,128,255,255]).rgb().vec()) + self.assertTrue(Approx(c.hsv().vec(), 1.0)==Color([288,50,100],Model.HSV).hsv().vec()) + self.assertTrue(Approx(c.hsv().vec(), 1.0)==Color([288,50,100,100],Model.HSV).hsv().vec()) + + # Pink 40% opacity + + a_rgb=102 + a_hsv=40 + d_rgba = [229,128,255,a_rgb] + d_hsva = [288,50,100,a_hsv] + + + colors = [ + Color(d_rgba, Model.RGB), + Color(d_hsva, Model.HSV), + Color("#E580FF66") + ] + for c in colors: + self.assertTrue(Approx(c.rgb().vec(), 1.0)==Color([229,128,255,a_rgb]).rgb().vec()) + self.assertTrue(Approx(c.hsv().vec(), 1.0)==Color([288,50,100,a_hsv],Model.HSV).hsv().vec()) if __name__ == '__main__': From 59a86f1a32f8be4480309d61554d1e1e53efe27b Mon Sep 17 00:00:00 2001 From: godardma Date: Wed, 4 Dec 2024 14:16:44 +0100 Subject: [PATCH 088/102] [graphics] minor update (thanks to Simon's advice) --- examples/00_graphics/graphic_examples.py | 7 +++++ .../src/graphics/styles/codac2_py_Color.cpp | 12 ++++---- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 2 +- src/graphics/styles/codac2_Color.cpp | 30 +++++-------------- src/graphics/styles/codac2_Color.h | 14 ++++----- src/graphics/styles/codac2_ColorMap.cpp | 2 +- 6 files changed, 28 insertions(+), 39 deletions(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index c7015a1d..be878046 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -44,9 +44,16 @@ fig2.draw_polygone([[2,4.5],[4,4.5],[4.2,3.5],[3.5,3]], [Color.none(),Color.green(0.5)]) fig2.draw_polyline([[-0.8,0],[0,1.5]], 0.2, [Color.red(),Color.black(0.3)]) fig2.draw_ellipse([1,1],[0.5,2], 0.2, [Color.blue(),Color.blue(0.3)]) + +# Colors +# predefined colors without and with opacity fig2.draw_point([2,2], [Color.red(),Color.yellow(0.5)]) +# HTML color without and with opacity fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) +# HSV color without and with opacity fig2.draw_box([[2.6,3.1],[2.6,3.1]],[Color([108,90,78],Model.HSV),Color([108,90,78,20],Model.HSV)]) +# RGB auto cast from list +fig2.draw_box([[2.,2.3],[2.6,2.9]],[[255,0,255],[255,0,255,100]]) fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) fig3.set_axes(axis(0,[-1,21]), axis(1,[-5.5,0.5])) diff --git a/python/src/graphics/styles/codac2_py_Color.cpp b/python/src/graphics/styles/codac2_py_Color.cpp index cdd321c2..d960b3ac 100644 --- a/python/src/graphics/styles/codac2_py_Color.cpp +++ b/python/src/graphics/styles/codac2_py_Color.cpp @@ -31,9 +31,6 @@ void export_Color(py::module& m) py::class_ exported_color(m, "Color", COLOR_MAIN); exported_color - .def_readwrite("m", &Color::m, - MODEL_COLOR_M) - .def(py::init<>(),COLOR_COLOR) .def(py::init&,Model>(), @@ -44,14 +41,13 @@ void export_Color(py::module& m) COLOR_COLOR_CONST_ARRAY_FLOAT4_REF_MODEL, "xyza"_a, "m_"_a=Model::RGB) - .def(py::init&,Model>(), - COLOR_COLOR_CONST_INITIALIZER_LIST_FLOAT_MODEL, - "xyza"_a, "m_"_a=Model::RGB) - .def(py::init(), COLOR_COLOR_CONST_STRING_REF, "hex_str"_a) + .def("model", &Color::model, + CONST_MODEL_REF_COLOR_MODEL_CONST) + // Other formats @@ -114,4 +110,6 @@ void export_Color(py::module& m) STATIC_COLOR_COLOR_DARK_GRAY_FLOAT, "alpha"_a=1.) ; + + py::implicitly_convertible(); } \ No newline at end of file diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 41005b72..64aa7143 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -82,7 +82,7 @@ std::string ipe_str(const Color& c) int ipe_opacity(const Color& c) { - return (int)(10.*round(10.*(c.m==Model::RGB ? (c[3]/255.):(c[3]/100.)))); + return (int)(10.*round(10.*(c.model()==Model::RGB ? (c[3]/255.):(c[3]/100.)))); } void Figure2D_IPE::begin_path(const StyleProperties& s, bool tip=false) diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index 9d344af1..adb7b720 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -13,47 +13,31 @@ using namespace std; using namespace codac2; Color::Color() - : m(Model::RGB) -{ - (*this)[0] = 0.; - (*this)[1] = 0.; - (*this)[2] = 0.; - (*this)[3] = 0.; -} + : Color({0.,0.,0.,0.}) +{ } Color::Color(const std::array& xyz, Model m_) - : m(m_) -{ - (*this)[0] = xyz[0]; - (*this)[1] = xyz[1]; - (*this)[2] = xyz[2]; - (*this)[3] = (m == Model::RGB ? 255. : 100.); -} + : Color({xyz[0],xyz[1],xyz[2],(m_ == Model::RGB ? (float) 255. : (float) 100.)}, m_) +{ } Color::Color(const std::array& xyza, Model m_) - : m(m_) + : std::array(xyza), m(m_) { if (m_==Model::RGB) assert(xyza[0] >= 0. && xyza[0] <= 255. && xyza[1]>=0. && xyza[1] <= 255. && xyza[2]>=0. && xyza[2] <= 255. && xyza[3]>=0. && xyza[3] <= 255.); else if (m_==Model::HSV) assert(xyza[0] >= 0. && xyza[0] <= 360. && xyza[1]>=0. && xyza[1] <= 100. && xyza[2]>=0. && xyza[2] <= 100. && xyza[3]>=0. && xyza[3] <= 100.); - (*this)[0] = xyza[0]; - (*this)[1] = xyza[1]; - (*this)[2] = xyza[2]; - (*this)[3] = xyza[3]; } Color::Color(const std::initializer_list xyza, Model m_) : Color(xyza.size() == 3 ? Color(to_array<3>(xyza), m_) : Color(to_array<4>(xyza), m_)) { } -Color::Color(const std::string& hex_str) +Color::Color(const std::string& hex_str) : m(Model::RGB) { assert(hex_str.size() == 7 || hex_str.size() == 9); assert(hex_str[0] == '#'); - m = Model::RGB; - int red,green,blue,a; std::istringstream(hex_str.substr(1,2)) >> std::hex >> red; std::istringstream(hex_str.substr(3,2)) >> std::hex >> green; @@ -148,7 +132,7 @@ Color Color::hsv() const s*=100.; v*=100.; - return Color({h, s, v,(float) ((*this)[3]/2.55)},Model::HSV); + return Color({h, s, v,std::min(100.,((*this)[3]/2.55))},Model::HSV); } } diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index d3a3d797..03e789fb 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -19,16 +19,14 @@ namespace codac2 { - enum class Model - { - RGB = 0x01, - HSV = 0x02 - }; + enum Model { RGB, HSV }; struct Color : public std::array { + protected: + Model m; - Model m = Model::RGB; //RGB or HSV + public: // Constructors @@ -38,6 +36,9 @@ namespace codac2 explicit Color(const std::initializer_list xyza, Model m_ = Model::RGB); explicit Color(const std::string& hex_str); + const Model& model() const { return m; } + + // other formats std::string hex_str() const; @@ -60,7 +61,6 @@ namespace codac2 return os; } - // Predefined colors static Color none() { return Color({255., 255., 255., 0.}); }; diff --git a/src/graphics/styles/codac2_ColorMap.cpp b/src/graphics/styles/codac2_ColorMap.cpp index f63b63f0..728264b9 100644 --- a/src/graphics/styles/codac2_ColorMap.cpp +++ b/src/graphics/styles/codac2_ColorMap.cpp @@ -53,7 +53,7 @@ Color ColorMap::color(float r) const return Color({(color_lb[0] + (color_ub[0] - color_lb[0]) * local_ratio), (color_lb[1] + (color_ub[1] - color_lb[1]) * local_ratio), (color_lb[2] + (color_ub[2] - color_lb[2]) * local_ratio), - (color_lb[3] + (color_ub[3] - color_lb[3]) * local_ratio)},color_lb.m); + (color_lb[3] + (color_ub[3] - color_lb[3]) * local_ratio)},color_lb.model()); } From c0022292c16457df4fd84df7575e5769543b8c5f Mon Sep 17 00:00:00 2001 From: godardma Date: Wed, 4 Dec 2024 14:25:53 +0100 Subject: [PATCH 089/102] [graphics] minor update --- examples/00_graphics/graphic_examples.py | 2 +- src/graphics/styles/codac2_Color.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/00_graphics/graphic_examples.py b/examples/00_graphics/graphic_examples.py index be878046..b4089801 100644 --- a/examples/00_graphics/graphic_examples.py +++ b/examples/00_graphics/graphic_examples.py @@ -52,7 +52,7 @@ fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) # HSV color without and with opacity fig2.draw_box([[2.6,3.1],[2.6,3.1]],[Color([108,90,78],Model.HSV),Color([108,90,78,20],Model.HSV)]) -# RGB auto cast from list +# RGB color auto cast from list without and with opacity fig2.draw_box([[2.,2.3],[2.6,2.9]],[[255,0,255],[255,0,255,100]]) fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) diff --git a/src/graphics/styles/codac2_Color.cpp b/src/graphics/styles/codac2_Color.cpp index adb7b720..55b5860d 100644 --- a/src/graphics/styles/codac2_Color.cpp +++ b/src/graphics/styles/codac2_Color.cpp @@ -92,7 +92,7 @@ Color Color::rgb() const g *= 255.; b *= 255.; - return Color({r, g, b,(float) ((*this)[3]*2.55)},Model::RGB); + return Color({r, g, b,std::min(255.,((*this)[3]*2.55))},Model::RGB); } } From 567f03de8022890935cf3700f6dcd2bef72e82b4 Mon Sep 17 00:00:00 2001 From: godardma Date: Wed, 4 Dec 2024 21:34:25 +0100 Subject: [PATCH 090/102] [graphics] protected ColorMap model --- .../graphics/styles/codac2_py_ColorMap.cpp | 6 +- src/graphics/styles/codac2_Color.h | 68 +++---- src/graphics/styles/codac2_ColorMap.h | 173 +++++++++--------- 3 files changed, 126 insertions(+), 121 deletions(-) diff --git a/python/src/graphics/styles/codac2_py_ColorMap.cpp b/python/src/graphics/styles/codac2_py_ColorMap.cpp index 3ba8d5fc..e127777e 100644 --- a/python/src/graphics/styles/codac2_py_ColorMap.cpp +++ b/python/src/graphics/styles/codac2_py_ColorMap.cpp @@ -23,13 +23,13 @@ void export_ColorMap(py::module& m) py::class_ exported_colormap(m, "ColorMap", COLORMAP_MAIN); exported_colormap - .def_readwrite("m", &ColorMap::m, - MODEL_COLORMAP_M) - .def(py::init(), COLORMAP_COLORMAP_MODEL, "m"_a=Model::RGB) + .def("model", &ColorMap::model, + CONST_MODEL_REF_COLORMAP_MODEL_CONST) + .def("color", &ColorMap::color, COLOR_COLORMAP_COLOR_FLOAT_CONST, "r"_a) diff --git a/src/graphics/styles/codac2_Color.h b/src/graphics/styles/codac2_Color.h index 03e789fb..a7ae40c6 100644 --- a/src/graphics/styles/codac2_Color.h +++ b/src/graphics/styles/codac2_Color.h @@ -28,52 +28,52 @@ namespace codac2 public: - // Constructors + // Constructors - explicit Color(); - explicit Color(const std::array& xyz, Model m_ = Model::RGB); - explicit Color(const std::array& xyza, Model m_ = Model::RGB); - explicit Color(const std::initializer_list xyza, Model m_ = Model::RGB); - explicit Color(const std::string& hex_str); + explicit Color(); + explicit Color(const std::array& xyz, Model m_ = Model::RGB); + explicit Color(const std::array& xyza, Model m_ = Model::RGB); + explicit Color(const std::initializer_list xyza, Model m_ = Model::RGB); + explicit Color(const std::string& hex_str); - const Model& model() const { return m; } + const Model& model() const { return m; } - // other formats + // other formats - std::string hex_str() const; + std::string hex_str() const; - codac2::Vector vec() const; + codac2::Vector vec() const; - // Conversions + // Conversions - Color rgb() const; - Color hsv() const; + Color rgb() const; + Color hsv() const; - // Overload flux operator + // Overload flux operator - friend std::ostream& operator<<(std::ostream& os, const Color& c) - { - if (c.m == Model::RGB) - os << "RGB Color (" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << ")"; - else if (c.m == Model::HSV) - os << "HSV Color (" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << ")"; - return os; - } + friend std::ostream& operator<<(std::ostream& os, const Color& c) + { + if (c.m == Model::RGB) + os << "RGB Color (" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << ")"; + else if (c.m == Model::HSV) + os << "HSV Color (" << c[0] << "," << c[1] << "," << c[2] << "," << c[3] << ")"; + return os; + } - // Predefined colors + // Predefined colors - static Color none() { return Color({255., 255., 255., 0.}); }; - static Color black(float alpha = 1.) { return Color({0., 0., 0., (float) (alpha*255.)}); }; - static Color white(float alpha = 1.) { return Color({255., 255., 255., (float) (alpha*255.)}); }; - static Color green(float alpha = 1.) { return Color({144., 242., 0., (float) (alpha*255.)}); }; - static Color blue(float alpha = 1.) { return Color({0., 98., 198., (float) (alpha*255.)}); }; - static Color cyan(float alpha = 1.) { return Color({75., 207., 250., (float) (alpha*255.)}); }; - static Color yellow(float alpha = 1.) { return Color({255., 211., 42., (float) (alpha*255.)}); }; - static Color red(float alpha = 1.) { return Color({209., 59., 0., (float) (alpha*255.)}); }; - static Color dark_gray(float alpha = 1.) { return Color({112., 112., 112., (float) (alpha*255.)}); }; - static Color purple(float alpha = 1.) { return Color({154., 0., 170., (float) (alpha*255.)}); }; - static Color dark_green(float alpha = 1.) { return Color({94., 158., 0., (float) (alpha*255.)}); }; + static Color none() { return Color({255., 255., 255., 0.}); }; + static Color black(float alpha = 1.) { return Color({0., 0., 0., (float) (alpha*255.)}); }; + static Color white(float alpha = 1.) { return Color({255., 255., 255., (float) (alpha*255.)}); }; + static Color green(float alpha = 1.) { return Color({144., 242., 0., (float) (alpha*255.)}); }; + static Color blue(float alpha = 1.) { return Color({0., 98., 198., (float) (alpha*255.)}); }; + static Color cyan(float alpha = 1.) { return Color({75., 207., 250., (float) (alpha*255.)}); }; + static Color yellow(float alpha = 1.) { return Color({255., 211., 42., (float) (alpha*255.)}); }; + static Color red(float alpha = 1.) { return Color({209., 59., 0., (float) (alpha*255.)}); }; + static Color dark_gray(float alpha = 1.) { return Color({112., 112., 112., (float) (alpha*255.)}); }; + static Color purple(float alpha = 1.) { return Color({154., 0., 170., (float) (alpha*255.)}); }; + static Color dark_green(float alpha = 1.) { return Color({94., 158., 0., (float) (alpha*255.)}); }; }; template diff --git a/src/graphics/styles/codac2_ColorMap.h b/src/graphics/styles/codac2_ColorMap.h index 55c0d290..c8d9e09a 100644 --- a/src/graphics/styles/codac2_ColorMap.h +++ b/src/graphics/styles/codac2_ColorMap.h @@ -23,99 +23,104 @@ namespace codac2 */ struct ColorMap : public std::map { - Model m; //RGB or HSV + protected: + Model m; //RGB or HSV - explicit ColorMap(Model m_ = Model::RGB); + public: + + explicit ColorMap(Model m_ = Model::RGB); - Color color (float r) const; + const Model& model() const { return m; } - static ColorMap haxby() - { - ColorMap cmap( Model::RGB ); - cmap[0]=Color({39.,90.,211.}); - cmap[1]=Color({40.,123.,245.}); - cmap[2]=Color({45.,155.,253.}); - cmap[3]=Color({73.,209.,255.}); - cmap[4]=Color({100.,230.,254.}); - cmap[5]=Color({118.,235.,226.}); - cmap[6]=Color({135.,236.,187.}); - cmap[7]=Color({194.,252.,165.}); - cmap[8]=Color({217.,251.,151.}); - cmap[9]=Color({233.,241.,131.}); - cmap[10]=Color({252.,201.,96.}); - cmap[11]=Color({255.,184.,84.}); - cmap[12]=Color({255.,170.,75.}); - cmap[13]=Color({255.,167.,83.}); - cmap[14]=Color({255.,200.,158.}); - cmap[15]=Color({255.,233.,217.}); - return cmap; - } + Color color (float r) const; - static ColorMap basic() // Can't use default as name - { - ColorMap cmap( Model::RGB ); - cmap[0]=Color({10.,0.,121.}); - cmap[1]=Color({40.,0.,150.}); - cmap[2]=Color({20.,5.,175.}); - cmap[3]=Color({0.,10.,200.}); - cmap[4]=Color({0.,25.,212.}); - cmap[5]=Color({0.,40.,224.}); - cmap[6]=Color({26.,102.,240.}); - cmap[7]=Color({13.,129.,248.}); - cmap[8]=Color({25.,175.,255.}); - cmap[9]=Color({50.,190.,255.}); - cmap[10]=Color({68.,202.,255.}); - cmap[11]=Color({97.,225.,240.}); - cmap[12]=Color({106.,235.,225.}); - cmap[13]=Color({124.,235.,200.}); - cmap[14]=Color({138.,236.,174.}); - cmap[15]=Color({172.,245.,168.}); - cmap[16]=Color({205.,255.,162.}); - cmap[17]=Color({223.,245.,141.}); - cmap[18]=Color({240.,236.,121.}); - cmap[19]=Color({247.,215.,104.}); - cmap[20]=Color({255.,189.,87.}); - cmap[21]=Color({255.,160.,69.}); - cmap[22]=Color({244.,117.,75.}); - cmap[23]=Color({238.,80.,78.}); - cmap[24]=Color({255.,90.,90.}); - cmap[25]=Color({255.,124.,124.}); - cmap[26]=Color({255.,158.,158.}); - cmap[27]=Color({245.,179.,174.}); - cmap[28]=Color({255.,196.,196.}); - cmap[29]=Color({255.,215.,215.}); - cmap[30]=Color({255.,235.,235.}); - cmap[31]=Color({255.,254.,253.}); - return cmap; - } + static ColorMap haxby() + { + ColorMap cmap( Model::RGB ); + cmap[0]=Color({39.,90.,211.}); + cmap[1]=Color({40.,123.,245.}); + cmap[2]=Color({45.,155.,253.}); + cmap[3]=Color({73.,209.,255.}); + cmap[4]=Color({100.,230.,254.}); + cmap[5]=Color({118.,235.,226.}); + cmap[6]=Color({135.,236.,187.}); + cmap[7]=Color({194.,252.,165.}); + cmap[8]=Color({217.,251.,151.}); + cmap[9]=Color({233.,241.,131.}); + cmap[10]=Color({252.,201.,96.}); + cmap[11]=Color({255.,184.,84.}); + cmap[12]=Color({255.,170.,75.}); + cmap[13]=Color({255.,167.,83.}); + cmap[14]=Color({255.,200.,158.}); + cmap[15]=Color({255.,233.,217.}); + return cmap; + } - static ColorMap blue_tube() - { - ColorMap cmap( Model::RGB ); - cmap[0]=Color({76.,110.,127.}); - cmap[1]=Color({136.,197.,228.}); - return cmap; - } + static ColorMap basic() // Can't use default as name + { + ColorMap cmap( Model::RGB ); + cmap[0]=Color({10.,0.,121.}); + cmap[1]=Color({40.,0.,150.}); + cmap[2]=Color({20.,5.,175.}); + cmap[3]=Color({0.,10.,200.}); + cmap[4]=Color({0.,25.,212.}); + cmap[5]=Color({0.,40.,224.}); + cmap[6]=Color({26.,102.,240.}); + cmap[7]=Color({13.,129.,248.}); + cmap[8]=Color({25.,175.,255.}); + cmap[9]=Color({50.,190.,255.}); + cmap[10]=Color({68.,202.,255.}); + cmap[11]=Color({97.,225.,240.}); + cmap[12]=Color({106.,235.,225.}); + cmap[13]=Color({124.,235.,200.}); + cmap[14]=Color({138.,236.,174.}); + cmap[15]=Color({172.,245.,168.}); + cmap[16]=Color({205.,255.,162.}); + cmap[17]=Color({223.,245.,141.}); + cmap[18]=Color({240.,236.,121.}); + cmap[19]=Color({247.,215.,104.}); + cmap[20]=Color({255.,189.,87.}); + cmap[21]=Color({255.,160.,69.}); + cmap[22]=Color({244.,117.,75.}); + cmap[23]=Color({238.,80.,78.}); + cmap[24]=Color({255.,90.,90.}); + cmap[25]=Color({255.,124.,124.}); + cmap[26]=Color({255.,158.,158.}); + cmap[27]=Color({245.,179.,174.}); + cmap[28]=Color({255.,196.,196.}); + cmap[29]=Color({255.,215.,215.}); + cmap[30]=Color({255.,235.,235.}); + cmap[31]=Color({255.,254.,253.}); + return cmap; + } - static ColorMap red_tube() - { - ColorMap cmap( Model::RGB ); - cmap[0]=Color({169.,55.,0.}); - cmap[1]=Color({241.,140.,54.}); - return cmap; - } + static ColorMap blue_tube() + { + ColorMap cmap( Model::RGB ); + cmap[0]=Color({76.,110.,127.}); + cmap[1]=Color({136.,197.,228.}); + return cmap; + } + + static ColorMap red_tube() + { + ColorMap cmap( Model::RGB ); + cmap[0]=Color({169.,55.,0.}); + cmap[1]=Color({241.,140.,54.}); + return cmap; + } - static ColorMap rainbow() - { - ColorMap cmap( Model::HSV ); - int i = 0; - for(int h = 300 ; h > 0 ; h-=10) + static ColorMap rainbow() { - cmap[i]=Color({(float)h,100.,100.},Model::HSV); - i++; + ColorMap cmap( Model::HSV ); + int i = 0; + for(int h = 300 ; h > 0 ; h-=10) + { + cmap[i]=Color({(float)h,100.,100.},Model::HSV); + i++; + } + return cmap; } - return cmap; - } }; } \ No newline at end of file From 6b93738948dcabc6312e2fab114929f0a839567c Mon Sep 17 00:00:00 2001 From: godardma Date: Thu, 5 Dec 2024 13:24:47 +0100 Subject: [PATCH 091/102] [graphics] correction for IPE color naming --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 64aa7143..b9349c99 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -77,7 +77,7 @@ void Figure2D_IPE::center_viewbox([[maybe_unused]] const Vector& c, [[maybe_unus std::string ipe_str(const Color& c) { - return " codac_color_" + c.hex_str().substr(1); + return c.hex_str().substr(1); } int ipe_opacity(const Color& c) From ee4dd02fc6c2b7d51b9b408ccc07e3002a3fa162 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 5 Dec 2024 17:38:01 +0100 Subject: [PATCH 092/102] [core] inlining Interval methods and related operators --- src/core/CMakeLists.txt | 1 - src/core/domains/interval/codac2_Interval.cpp | 392 ----------------- src/core/domains/interval/codac2_Interval.h | 404 +++++++++++++++++- .../interval/codac2_Interval_operations.cpp | 242 +---------- .../interval/codac2_Interval_operations.h | 361 ++++++++++++---- 5 files changed, 690 insertions(+), 710 deletions(-) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a323bb92..986b0ed2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -50,7 +50,6 @@ ${CMAKE_CURRENT_SOURCE_DIR}/domains/codac2_BoolInterval.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/codac2_Domain.h - ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_Interval.cpp ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_Interval.h ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_Interval_operations.cpp ${CMAKE_CURRENT_SOURCE_DIR}/domains/interval/codac2_Interval_operations.h diff --git a/src/core/domains/interval/codac2_Interval.cpp b/src/core/domains/interval/codac2_Interval.cpp index 7f53d83b..e69de29b 100644 --- a/src/core/domains/interval/codac2_Interval.cpp +++ b/src/core/domains/interval/codac2_Interval.cpp @@ -1,392 +0,0 @@ -/** - * codac2_Interval.cpp - * - * This class reuses several functions developed for ibex::Interval. - * The original IBEX code is encapsulated in Codac for allowing inheritance - * to Codac classes and also for documentation, binding, and independency purposes. - * See ibex::Interval (IBEX lib, main author: Gilles Chabert) - * https://ibex-lib.readthedocs.io - * - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Gilles Chabert, Simon Rohou - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#include -#include -#include "codac2_Interval.h" -#include "codac2_assert.h" - -using namespace std; - -namespace codac2 -{ - Interval::Interval() - : ibex::Interval() - { } - - Interval::Interval(double a) - : ibex::Interval(a) - { } - - Interval::Interval(double a, double b) - : ibex::Interval(a,b) - { } - - Interval::Interval(const Interval& x) - : ibex::Interval(x) - { } - - Interval::Interval(array array) - : ibex::Interval(array) - { } - - Interval::Interval(array array) - : ibex::Interval(array) - { } - - Interval::Interval(std::initializer_list l) - : Interval() - { - init_from_list(l); - } - - Interval& Interval::init(const Interval& x) - { - *this = x; - return *this; - } - - Interval& Interval::init_from_list(const std::list& l) - { - assert_release((l.size() == 1 || l.size() == 2) - && "'Interval' can only be defined by one or two 'double' values."); - *this = Interval(*l.begin(),*std::prev(l.end())); - return *this; - } - - Interval& Interval::operator=(const Interval& x) - { - ibex::Interval::operator=(x); - return *this; - } - - bool Interval::operator==(const Interval& x) const - { - return ibex::Interval::operator==(x); - } - - bool Interval::operator!=(const Interval& x) const - { - return ibex::Interval::operator!=(x); - } - - double Interval::lb() const - { - return ibex::Interval::lb(); - } - - double Interval::ub() const - { - return ibex::Interval::ub(); - } - - double Interval::mid() const - { - return ibex::Interval::mid(); - } - - double Interval::mag() const - { - return ibex::Interval::mag(); - } - - double Interval::mig() const - { - return ibex::Interval::mig(); - } - - double Interval::rand() const - { - if(is_empty()) - return std::numeric_limits::quiet_NaN(); - - double a = max(next_float(-oo),lb()); - double b = min(previous_float(oo),ub()); - return a + (((double)std::rand())/(double)RAND_MAX)*(b-a); - } - - double Interval::rad() const - { - return ibex::Interval::rad(); - } - - double Interval::diam() const - { - return ibex::Interval::diam(); - } - - double Interval::volume() const - { - return ibex::Interval::diam(); - } - - Index Interval::size() const - { - return 1; - } - - void Interval::set_empty() - { - ibex::Interval::set_empty(); - } - - bool Interval::is_empty() const - { - return ibex::Interval::is_empty(); - } - - bool Interval::contains(const double& x) const - { - return ibex::Interval::contains(x); - } - - bool Interval::interior_contains(const double& x) const - { - return ibex::Interval::interior_contains(x); - } - - bool Interval::is_unbounded() const - { - return ibex::Interval::is_unbounded(); - } - - bool Interval::is_degenerated() const - { - return ibex::Interval::is_degenerated(); - } - - bool Interval::intersects(const Interval &x) const - { - return ibex::Interval::intersects(x); - } - - bool Interval::is_disjoint(const Interval& x) const - { - return ibex::Interval::is_disjoint(x); - } - - bool Interval::overlaps(const Interval& x) const - { - return ibex::Interval::overlaps(x); - } - - bool Interval::is_subset(const Interval& x) const - { - return ibex::Interval::is_subset(x); - } - - bool Interval::is_strict_subset(const Interval& x) const - { - return ibex::Interval::is_strict_subset(x); - } - - bool Interval::is_interior_subset(const Interval& x) const - { - return ibex::Interval::is_interior_subset(x); - } - - bool Interval::is_strict_interior_subset(const Interval& x) const - { - return ibex::Interval::is_strict_interior_subset(x); - } - - bool Interval::is_superset(const Interval& x) const - { - return ibex::Interval::is_superset(x); - } - - bool Interval::is_strict_superset(const Interval& x) const - { - return ibex::Interval::is_strict_superset(x); - } - - Interval& Interval::inflate(const double& rad) - { - ibex::Interval::inflate(rad); - return *this; - } - - bool Interval::is_bisectable() const - { - return ibex::Interval::is_bisectable(); - } - - pair Interval::bisect(float ratio) const - { - assert_release(Interval(0,1).interior_contains(ratio)); - auto p = ibex::Interval::bisect(ratio); - return { p.first, p.second }; - } - - vector Interval::complementary(bool compactness) const - { - if(is_empty() || (compactness && is_degenerated())) - return { {-oo,oo} }; - - vector l; - - if(lb() > -oo) - l.push_back({-oo,lb()}); - - if(ub() < oo) - l.push_back({ub(),oo}); - - return l; - } - - vector Interval::diff(const Interval& y, bool compactness) const - { - if(compactness && is_degenerated()) - { - if(is_empty() || y.contains(lb())) - return {}; - else - return { *this }; - } - - vector l; - for(const auto& li : y.complementary(compactness)) - { - Interval inter = li & *this; - if(!inter.is_degenerated()) - l.push_back(inter); - } - - return l; - } - - Interval& Interval::operator|=(const Interval& x) - { - ibex::Interval::operator|=(x); - return *this; - } - - Interval& Interval::operator&=(const Interval& x) - { - ibex::Interval::operator&=(x); - return *this; - } - - Interval& Interval::operator+=(double x) - { - ibex::Interval::operator+=(x); - return *this; - } - - Interval& Interval::operator+=(const Interval& x) - { - ibex::Interval::operator+=(x); - return *this; - } - - Interval Interval::operator-() const - { - return 0.-*this; - } - - Interval& Interval::operator-=(double x) - { - ibex::Interval::operator-=(x); - return *this; - } - - Interval& Interval::operator-=(const Interval& x) - { - ibex::Interval::operator-=(x); - return *this; - } - - Interval& Interval::operator*=(double x) - { - ibex::Interval::operator*=(x); - return *this; - } - - Interval& Interval::operator*=(const Interval& x) - { - ibex::Interval::operator*=(x); - return *this; - } - - Interval& Interval::operator/=(double x) - { - ibex::Interval::operator/=(x); - return *this; - } - - Interval& Interval::operator/=(const Interval& x) - { - ibex::Interval::operator/=(x); - return *this; - } - - Interval Interval::empty() - { - return ibex::Interval::empty_set(); - } - - Interval Interval::zero() - { - return ibex::Interval::zero(); - } - - Interval Interval::zeros() - { - return ibex::Interval::zero(); - } - - Interval Interval::one() - { - return ibex::Interval::one(); - } - - Interval Interval::ones() - { - return ibex::Interval::one(); - } - - Interval Interval::half_pi() - { - return ibex::Interval::half_pi(); - } - - Interval Interval::pi() - { - return ibex::Interval::pi(); - } - - Interval Interval::two_pi() - { - return ibex::Interval::two_pi(); - } - - ostream& operator<<(ostream& os, const Interval& x) - { - gaol::interval::precision(os.precision()); - ibex::operator<<(os,x); - return os; - } - - Interval::Interval(const ibex::Interval& x) - : ibex::Interval(x) - { } - - Interval operator""_i(long double x) - { - return Interval(x); - } - -} // namespace codac diff --git a/src/core/domains/interval/codac2_Interval.h b/src/core/domains/interval/codac2_Interval.h index aa6f69a0..80730c8c 100644 --- a/src/core/domains/interval/codac2_Interval.h +++ b/src/core/domains/interval/codac2_Interval.h @@ -21,6 +21,7 @@ #include #include "codac2_Index.h" #include "codac2_Domain.h" +#include "codac2_assert.h" namespace codac2 { @@ -511,44 +512,60 @@ namespace codac2 * * \return an empty set */ - static Interval empty(); + static Interval empty() + { + return ibex::Interval::empty_set(); + } /** * \brief Provides an interval for \f$[0]\f$ * * \return an interval containing \f$0\f$ */ - static Interval zero(); - static Interval zeros(); + static Interval zero() + { + return ibex::Interval::zero(); + } /** * \brief Provides an interval for \f$[1]\f$ * * \return an interval containing \f$1\f$ */ - static Interval one(); - static Interval ones(); + static Interval one() + { + return ibex::Interval::one(); + } /** * \brief Provides an interval for \f$[\frac{\pi}{2}]\f$ * * \return an interval containing \f$\frac{\pi}{2}\f$ */ - static Interval half_pi(); + static Interval half_pi() + { + return ibex::Interval::half_pi(); + } /** * \brief Provides an interval for \f$[\pi]\f$ * * \return an interval containing \f$\pi\f$ */ - static Interval pi(); + static Interval pi() + { + return ibex::Interval::pi(); + } /** * \brief Provides an interval for \f$[2\pi]\f$ * * \return an interval containing \f$2\pi\f$ */ - static Interval two_pi(); + static Interval two_pi() + { + return ibex::Interval::two_pi(); + } friend std::ostream& operator<<(std::ostream& os, const Interval& x); @@ -680,3 +697,374 @@ namespace codac2 return ibex::next_float(x); } } + +// Inline functions + +namespace codac2 +{ + inline Interval::Interval() + : ibex::Interval() + { } + + inline Interval::Interval(double a) + : ibex::Interval(a) + { } + + inline Interval::Interval(double a, double b) + : ibex::Interval(a,b) + { } + + inline Interval::Interval(const Interval& x) + : ibex::Interval(x) + { } + + inline Interval::Interval(std::array array) + : ibex::Interval(array) + { } + + inline Interval::Interval(std::array array) + : ibex::Interval(array) + { } + + inline Interval::Interval(std::initializer_list l) + : Interval() + { + init_from_list(l); + } + + inline Interval& Interval::init(const Interval& x) + { + *this = x; + return *this; + } + + inline Interval& Interval::init_from_list(const std::list& l) + { + assert_release((l.size() == 1 || l.size() == 2) + && "'Interval' can only be defined by one or two 'double' values."); + *this = Interval(*l.begin(),*std::prev(l.end())); + return *this; + } + + inline Interval& Interval::operator=(const Interval& x) + { + ibex::Interval::operator=(x); + return *this; + } + + inline bool Interval::operator==(const Interval& x) const + { + return ibex::Interval::operator==(x); + } + + inline bool Interval::operator!=(const Interval& x) const + { + return ibex::Interval::operator!=(x); + } + + inline double Interval::lb() const + { + return ibex::Interval::lb(); + } + + inline double Interval::ub() const + { + return ibex::Interval::ub(); + } + + inline double Interval::mid() const + { + return ibex::Interval::mid(); + } + + inline double Interval::mag() const + { + return ibex::Interval::mag(); + } + + inline double Interval::mig() const + { + return ibex::Interval::mig(); + } + + inline double Interval::rand() const + { + if(is_empty()) + return std::numeric_limits::quiet_NaN(); + + double a = std::max(next_float(-oo),lb()); + double b = std::min(previous_float(oo),ub()); + return a + (((double)std::rand())/(double)RAND_MAX)*(b-a); + } + + inline double Interval::rad() const + { + return ibex::Interval::rad(); + } + + inline double Interval::diam() const + { + return ibex::Interval::diam(); + } + + inline double Interval::volume() const + { + return ibex::Interval::diam(); + } + + inline Index Interval::size() const + { + return 1; + } + + inline void Interval::set_empty() + { + ibex::Interval::set_empty(); + } + + inline bool Interval::is_empty() const + { + return ibex::Interval::is_empty(); + } + + inline bool Interval::contains(const double& x) const + { + return ibex::Interval::contains(x); + } + + inline bool Interval::interior_contains(const double& x) const + { + return ibex::Interval::interior_contains(x); + } + + inline bool Interval::is_unbounded() const + { + return ibex::Interval::is_unbounded(); + } + + inline bool Interval::is_degenerated() const + { + return ibex::Interval::is_degenerated(); + } + + inline bool Interval::intersects(const Interval &x) const + { + return ibex::Interval::intersects(x); + } + + inline bool Interval::is_disjoint(const Interval& x) const + { + return ibex::Interval::is_disjoint(x); + } + + inline bool Interval::overlaps(const Interval& x) const + { + return ibex::Interval::overlaps(x); + } + + inline bool Interval::is_subset(const Interval& x) const + { + return ibex::Interval::is_subset(x); + } + + inline bool Interval::is_strict_subset(const Interval& x) const + { + return ibex::Interval::is_strict_subset(x); + } + + inline bool Interval::is_interior_subset(const Interval& x) const + { + return ibex::Interval::is_interior_subset(x); + } + + inline bool Interval::is_strict_interior_subset(const Interval& x) const + { + return ibex::Interval::is_strict_interior_subset(x); + } + + inline bool Interval::is_superset(const Interval& x) const + { + return ibex::Interval::is_superset(x); + } + + inline bool Interval::is_strict_superset(const Interval& x) const + { + return ibex::Interval::is_strict_superset(x); + } + + inline Interval& Interval::inflate(const double& rad) + { + ibex::Interval::inflate(rad); + return *this; + } + + inline bool Interval::is_bisectable() const + { + return ibex::Interval::is_bisectable(); + } + + inline std::pair Interval::bisect(float ratio) const + { + assert_release(Interval(0,1).interior_contains(ratio)); + auto p = ibex::Interval::bisect(ratio); + return { p.first, p.second }; + } + + inline std::vector Interval::complementary(bool compactness) const + { + if(is_empty() || (compactness && is_degenerated())) + return { {-oo,oo} }; + + std::vector l; + + if(lb() > -oo) + l.push_back({-oo,lb()}); + + if(ub() < oo) + l.push_back({ub(),oo}); + + return l; + } + + inline std::vector Interval::diff(const Interval& y, bool compactness) const + { + if(compactness && is_degenerated()) + { + if(is_empty() || y.contains(lb())) + return {}; + else + return { *this }; + } + + std::vector l; + for(const auto& li : y.complementary(compactness)) + { + Interval inter = li & *this; + if(!inter.is_degenerated()) + l.push_back(inter); + } + + return l; + } + + inline Interval& Interval::operator|=(const Interval& x) + { + ibex::Interval::operator|=(x); + return *this; + } + + inline Interval& Interval::operator&=(const Interval& x) + { + ibex::Interval::operator&=(x); + return *this; + } + + inline Interval& Interval::operator+=(double x) + { + ibex::Interval::operator+=(x); + return *this; + } + + inline Interval& Interval::operator+=(const Interval& x) + { + ibex::Interval::operator+=(x); + return *this; + } + + inline Interval Interval::operator-() const + { + return 0.-*this; + } + + inline Interval& Interval::operator-=(double x) + { + ibex::Interval::operator-=(x); + return *this; + } + + inline Interval& Interval::operator-=(const Interval& x) + { + ibex::Interval::operator-=(x); + return *this; + } + + inline Interval& Interval::operator*=(double x) + { + ibex::Interval::operator*=(x); + return *this; + } + + inline Interval& Interval::operator*=(const Interval& x) + { + ibex::Interval::operator*=(x); + return *this; + } + + inline Interval& Interval::operator/=(double x) + { + ibex::Interval::operator/=(x); + return *this; + } + + inline Interval& Interval::operator/=(const Interval& x) + { + ibex::Interval::operator/=(x); + return *this; + } + + /*static inline Interval Interval::empty() + { + return ibex::Interval::empty_set(); + } + + static inline Interval Interval::zero() + { + return ibex::Interval::zero(); + } + + static inline Interval Interval::zeros() + { + return ibex::Interval::zero(); + } + + static inline Interval Interval::one() + { + return ibex::Interval::one(); + } + + static inline Interval Interval::ones() + { + return ibex::Interval::one(); + } + + static inline Interval Interval::half_pi() + { + return ibex::Interval::half_pi(); + } + + static inline Interval Interval::pi() + { + return ibex::Interval::pi(); + } + + static inline Interval Interval::two_pi() + { + return ibex::Interval::two_pi(); + }*/ + + inline std::ostream& operator<<(std::ostream& os, const Interval& x) + { + gaol::interval::precision(os.precision()); + ibex::operator<<(os,x); + return os; + } + + inline Interval::Interval(const ibex::Interval& x) + : ibex::Interval(x) + { } + + inline Interval operator""_i(long double x) + { + return Interval(x); + } +} \ No newline at end of file diff --git a/src/core/domains/interval/codac2_Interval_operations.cpp b/src/core/domains/interval/codac2_Interval_operations.cpp index 9af5818a..8b1ce5ac 100644 --- a/src/core/domains/interval/codac2_Interval_operations.cpp +++ b/src/core/domains/interval/codac2_Interval_operations.cpp @@ -21,245 +21,13 @@ using namespace std; namespace codac2 { - const Interval& operator+(const Interval& x) + Interval operator-(double x, const Interval& y) { - return x; + return ibex::operator-(x, y); } - #define interval_arithm_op(f) \ - Interval f(const Interval& x, const Interval& y) \ - { \ - return ibex::f(x, y); \ - } \ - Interval f(double x, const Interval& y) \ - { \ - return ibex::f(x, y); \ - } \ - Interval f(const Interval& x, double y) \ - { \ - return ibex::f(x, y); \ - } \ - - interval_arithm_op(operator&) - interval_arithm_op(operator|) - interval_arithm_op(operator+) - interval_arithm_op(operator-) - interval_arithm_op(operator*) - interval_arithm_op(operator/) - - #define unary_interval_op(f) \ - Interval f(const Interval& x) \ - { \ - return ibex::f(x); \ - } \ - - #define binary_interval_op(f) \ - Interval f(const Interval& x, const Interval& y) \ - { \ - return ibex::f(x, y); \ - } \ - - unary_interval_op(sqr) - unary_interval_op(sqrt) - - Interval pow(const Interval& x, int n) - { - return ibex::pow(x, n); - } - - Interval pow(const Interval& x, double d) - { - return ibex::pow(x, d); - } - - binary_interval_op(pow) - - Interval root(const Interval& x, int n) - { - return ibex::root(x, n); - } - - unary_interval_op(exp) - unary_interval_op(log) - unary_interval_op(cos) - unary_interval_op(sin) - unary_interval_op(tan) - unary_interval_op(acos) - unary_interval_op(asin) - unary_interval_op(atan) - binary_interval_op(atan2) - unary_interval_op(cosh) - unary_interval_op(sinh) - unary_interval_op(tanh) - unary_interval_op(acosh) - unary_interval_op(asinh) - unary_interval_op(atanh) - unary_interval_op(abs) - binary_interval_op(min) - binary_interval_op(max) - unary_interval_op(sign) - unary_interval_op(integer) - unary_interval_op(floor) - unary_interval_op(ceil) - - void bwd_add(const Interval& y, Interval& x1, Interval& x2) - { - ibex::bwd_add(y,x1,x2); - } - - void bwd_sub(const Interval& y, Interval& x1, Interval& x2) - { - ibex::bwd_sub(y,x1,x2); - } - - void bwd_mul(const Interval& y, Interval& x1, Interval& x2) - { - ibex::bwd_mul(y,x1,x2); - } - - void bwd_div(const Interval& y, Interval& x1, Interval& x2) - { - ibex::bwd_div(y,x1,x2); - } - - void bwd_sqr(const Interval& y, Interval& x) - { - ibex::bwd_sqr(y,x); - } - - void bwd_sqrt(const Interval& y, Interval& x) - { - ibex::bwd_sqrt(y,x); - } - - void bwd_pow(const Interval& y, Interval& x, int p) - { - ibex::bwd_pow(y,p,x); - } - - void bwd_pow(const Interval& y, Interval& x, Interval& p) - { - assert(p.is_degenerated() && "bwd_power(y,x1,x2) (with x1 and x2 intervals) not implemented yet with Gaol"); - ibex::bwd_pow(y,p.mid(),x); - } - - void bwd_root(const Interval& y, Interval& x, int p) - { - ibex::bwd_root(y,p,x); - } - - void bwd_exp(const Interval& y, Interval& x) - { - ibex::bwd_exp(y,x); - } - - void bwd_log(const Interval& y, Interval& x) - { - ibex::bwd_log(y,x); - } - - void bwd_cos(const Interval& y, Interval& x) - { - ibex::bwd_cos(y,x); - } - - void bwd_sin(const Interval& y, Interval& x) - { - ibex::bwd_sin(y,x); - } - - void bwd_tan(const Interval& y, Interval& x) - { - ibex::bwd_tan(y,x); - } - - void bwd_acos(const Interval& y, Interval& x) - { - ibex::bwd_acos(y,x); - } - - void bwd_asin(const Interval& y, Interval& x) - { - ibex::bwd_asin(y,x); - } - - void bwd_atan(const Interval& y, Interval& x) - { - ibex::bwd_atan(y,x); - } - - void bwd_atan2(const Interval& y, Interval& x1, Interval& x2) - { - ibex::bwd_atan2(y,x1,x2); - } - - void bwd_cosh(const Interval& y, Interval& x) - { - ibex::bwd_cosh(y,x); - } - - void bwd_sinh(const Interval& y, Interval& x) - { - ibex::bwd_sinh(y,x); - } - - void bwd_tanh(const Interval& y, Interval& x) - { - ibex::bwd_tanh(y,x); - } - - void bwd_acosh(const Interval& y, Interval& x) - { - ibex::bwd_acosh(y,x); - } - - void bwd_asinh(const Interval& y, Interval& x) - { - ibex::bwd_asinh(y,x); - } - - void bwd_atanh(const Interval& y, Interval& x) - { - ibex::bwd_atanh(y,x); - } - - void bwd_abs(const Interval& y, Interval& x) - { - ibex::bwd_abs(y,x); - } - - void bwd_min(const Interval& y, Interval& x1, Interval& x2) - { - ibex::bwd_min(y,x1,x2); - } - - void bwd_max(const Interval& y, Interval& x1, Interval& x2) - { - ibex::bwd_max(y,x1,x2); - } - - void bwd_sign(const Interval& y, Interval& x) - { - ibex::bwd_sign(y,x); - } - - void bwd_floor(const Interval& y, Interval& x) - { - ibex::bwd_floor(y,x); - } - - void bwd_ceil(const Interval& y, Interval& x) - { - ibex::bwd_ceil(y,x); - } - - void bwd_saw(const Interval& y, Interval& x) - { - ibex::bwd_saw(y,x); - } - - void bwd_imod(Interval& x, Interval& y, double p) + Interval operator-(const Interval& x, double y) { - ibex::bwd_imod(x,y,p); + return ibex::operator-(x, y); } -} // namespace codac \ No newline at end of file +} \ No newline at end of file diff --git a/src/core/domains/interval/codac2_Interval_operations.h b/src/core/domains/interval/codac2_Interval_operations.h index 10cb3094..3a27fd10 100644 --- a/src/core/domains/interval/codac2_Interval_operations.h +++ b/src/core/domains/interval/codac2_Interval_operations.h @@ -29,7 +29,10 @@ namespace codac2 * \param y interval value * \return intersection result */ - Interval operator&(const Interval& x, const Interval& y); + inline Interval operator&(const Interval& x, const Interval& y) + { + return ibex::operator&(x,y); + } /** * \brief Returns the squared-union of two intervals: \f$[x]\sqcup[y]\f$ @@ -40,7 +43,10 @@ namespace codac2 * \param y interval value * \return squared-union result */ - Interval operator|(const Interval& x, const Interval& y); + inline Interval operator|(const Interval& x, const Interval& y) + { + return ibex::operator|(x,y); + } /** * \brief Returns this @@ -50,7 +56,10 @@ namespace codac2 * \param x interval value * \return the same interval */ - const Interval& operator+(const Interval& x); + inline const Interval& operator+(const Interval& x) + { + return x; + } /** * \brief Returns \f$[x]+y\f$ with \f$y\in\mathbb{R}\f$ @@ -59,7 +68,10 @@ namespace codac2 * \param y real value * \return the addition result */ - Interval operator+(const Interval& x, double y); + inline Interval operator+(const Interval& x, double y) + { + return ibex::operator+(x,y); + } /** * \brief Returns \f$x+[y]\f$ with \f$x\in\mathbb{R}\f$ @@ -68,7 +80,10 @@ namespace codac2 * \param y interval value * \return the addition result */ - Interval operator+(double x, const Interval& y); + inline Interval operator+(double x, const Interval& y) + { + return ibex::operator+(x,y); + } /** * \brief Returns \f$[x]+[y]\f$ @@ -77,7 +92,10 @@ namespace codac2 * \param y interval value * \return the addition result */ - Interval operator+(const Interval& x, const Interval& y); + inline Interval operator+(const Interval& x, const Interval& y) + { + return ibex::operator+(x,y); + } /** * \brief Returns \f$[x]-y\f$ with \f$y\in\mathbb{R}\f$ @@ -104,7 +122,10 @@ namespace codac2 * \param y interval value * \return the substraction result */ - Interval operator-(const Interval& x, const Interval& y); + inline Interval operator-(const Interval& x, const Interval& y) + { + return ibex::operator-(x, y); + } /** * \brief Returns \f$[x]*y\f$ with \f$y\in\mathbb{R}\f$ @@ -113,7 +134,10 @@ namespace codac2 * \param y real value * \return the multiplication result */ - Interval operator*(const Interval& x, double y); + inline Interval operator*(const Interval& x, double y) + { + return ibex::operator*(x,y); + } /** * \brief Returns \f$x*[y]\f$ with \f$x\in\mathbb{R}\f$ @@ -122,7 +146,10 @@ namespace codac2 * \param y interval value * \return the multiplication result */ - Interval operator*(double x, const Interval& y); + inline Interval operator*(double x, const Interval& y) + { + return ibex::operator*(x,y); + } /** * \brief Returns \f$[x]*[y]\f$ @@ -131,7 +158,10 @@ namespace codac2 * \param y interval value * \return the multiplication result */ - Interval operator*(const Interval& x, const Interval& y); + inline Interval operator*(const Interval& x, const Interval& y) + { + return ibex::operator*(x,y); + } /** * \brief Returns \f$[x]/y\f$ with \f$y\in\mathbb{R}\f$ @@ -140,7 +170,10 @@ namespace codac2 * \param y real value * \return the division result */ - Interval operator/(const Interval& x, double y); + inline Interval operator/(const Interval& x, double y) + { + return ibex::operator/(x,y); + } /** * \brief Returns \f$x/[y]\f$ with \f$x\in\mathbb{R}\f$ @@ -149,7 +182,10 @@ namespace codac2 * \param y interval value * \return the division result */ - Interval operator/(double x, const Interval& y); + inline Interval operator/(double x, const Interval& y) + { + return ibex::operator/(x,y); + } /** * \brief Returns \f$[x]/[y]\f$ @@ -158,7 +194,10 @@ namespace codac2 * \param y interval value * \return the division result */ - Interval operator/(const Interval& x, const Interval& y); + inline Interval operator/(const Interval& x, const Interval& y) + { + return ibex::operator/(x,y); + } /** * \brief Returns \f$[x]^2\f$ @@ -166,7 +205,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval sqr(const Interval& x); + inline Interval sqr(const Interval& x) + { + return ibex::sqr(x); + } /** * \brief Returns \f$\sqrt{[x]}\f$ @@ -174,7 +216,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval sqrt(const Interval& x); + inline Interval sqrt(const Interval& x) + { + return ibex::sqrt(x); + } /** * \brief Returns \f$[x]^n\f$, \f$n\in\mathbb{Z}\f$ @@ -183,7 +228,10 @@ namespace codac2 * \param n integer power value * \return the operation result */ - Interval pow(const Interval& x, int n); + inline Interval pow(const Interval& x, int n) + { + return ibex::pow(x,n); + } /** * \brief Returns \f$[x]^d\f$, \f$d\in\mathbb{R}\f$ @@ -192,7 +240,10 @@ namespace codac2 * \param d real power value * \return the operation result */ - Interval pow(const Interval& x, double d); + inline Interval pow(const Interval& x, double d) + { + return ibex::pow(x,d); + } /** * \brief Returns \f$[x]^{[y]}\f$, \f$y\in\mathbb{IR}\f$ @@ -201,7 +252,10 @@ namespace codac2 * \param y interval power value * \return the operation result */ - Interval pow(const Interval& x, const Interval& y); + inline Interval pow(const Interval& x, const Interval& y) + { + return ibex::pow(x,y); + } /** * \brief Returns the n-th root: \f$\sqrt[n]{[x]}\f$ @@ -210,7 +264,10 @@ namespace codac2 * \param n integer root * \return the operation result */ - Interval root(const Interval& x, int n); + inline Interval root(const Interval& x, int n) + { + return ibex::root(x,n); + } /** * \brief Returns \f$\exp([x])\f$ @@ -218,7 +275,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval exp(const Interval& x); + inline Interval exp(const Interval& x) + { + return ibex::exp(x); + } /** * \brief Returns \f$\log([x])\f$ @@ -226,7 +286,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval log(const Interval& x); + inline Interval log(const Interval& x) + { + return ibex::log(x); + } /** * \brief Returns \f$\cos([x])\f$ @@ -234,7 +297,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval cos(const Interval& x); + inline Interval cos(const Interval& x) + { + return ibex::cos(x); + } /** * \brief Returns \f$\sin([x])\f$ @@ -242,7 +308,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval sin(const Interval& x); + inline Interval sin(const Interval& x) + { + return ibex::sin(x); + } /** * \brief Returns \f$\tan([x])\f$ @@ -250,7 +319,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval tan(const Interval& x); + inline Interval tan(const Interval& x) + { + return ibex::tan(x); + } /** * \brief Returns \f$\acos([x])\f$ @@ -258,7 +330,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval acos(const Interval& x); + inline Interval acos(const Interval& x) + { + return ibex::acos(x); + } /** * \brief Returns \f$\asin([x])\f$ @@ -266,7 +341,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval asin(const Interval& x); + inline Interval asin(const Interval& x) + { + return ibex::asin(x); + } /** * \brief Returns \f$\atan([x])\f$ @@ -274,7 +352,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval atan(const Interval& x); + inline Interval atan(const Interval& x) + { + return ibex::atan(x); + } /** * \brief Returns \f$\mathrm{arctan2}([y],[x])\f$ @@ -283,7 +364,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval atan2(const Interval& y, const Interval& x); + inline Interval atan2(const Interval& y, const Interval& x) + { + return ibex::atan2(y,x); + } /** * \brief Returns \f$\cosh([x])\f$ @@ -291,7 +375,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval cosh(const Interval& x); + inline Interval cosh(const Interval& x) + { + return ibex::cosh(x); + } /** * \brief Returns \f$\sinh([x])\f$ @@ -299,7 +386,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval sinh(const Interval& x); + inline Interval sinh(const Interval& x) + { + return ibex::sinh(x); + } /** * \brief Returns \f$\tanh([x])\f$ @@ -307,7 +397,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval tanh(const Interval& x); + inline Interval tanh(const Interval& x) + { + return ibex::tanh(x); + } /** * \brief Returns \f$\acosh([x])\f$ @@ -315,7 +408,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval acosh(const Interval& x); + inline Interval acosh(const Interval& x) + { + return ibex::acosh(x); + } /** * \brief Returns \f$\asinh([x])\f$ @@ -323,7 +419,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval asinh(const Interval& x); + inline Interval asinh(const Interval& x) + { + return ibex::asinh(x); + } /** * \brief Returns \f$\atanh([x])\f$ @@ -331,7 +430,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval atanh(const Interval& x); + inline Interval atanh(const Interval& x) + { + return ibex::atanh(x); + } /** * \brief Returns \f$\mid[x]\mid = \left\{\mid x \mid, x\in[x]\right\}\f$ @@ -339,7 +441,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval abs(const Interval& x); + inline Interval abs(const Interval& x) + { + return ibex::abs(x); + } /** * \brief Returns \f$\min([x],[y])=\left\{\min(x,y), x\in[x], y\in[y]\right\}\f$ @@ -348,7 +453,10 @@ namespace codac2 * \param y interval value * \return the operation result */ - Interval min(const Interval& x, const Interval& y); + inline Interval min(const Interval& x, const Interval& y) + { + return ibex::min(x,y); + } /** * \brief Returns \f$\max([x],[y])=\left\{\max(x,y), x\in[x], y\in[y]\right\}\f$ @@ -357,7 +465,10 @@ namespace codac2 * \param y interval value * \return the operation result */ - Interval max(const Interval& x, const Interval& y); + inline Interval max(const Interval& x, const Interval& y) + { + return ibex::max(x,y); + } /** * \brief Returns \f$\sign([x])=\left[\left\{\sign(x), x\in[x]\right\}\right]\f$ @@ -367,7 +478,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval sign(const Interval& x); + inline Interval sign(const Interval& x) + { + return ibex::sign(x); + } /** * \brief Returns the largest integer interval included in \f$[x]\f$ @@ -375,7 +489,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval integer(const Interval& x); + inline Interval integer(const Interval& x) + { + return ibex::integer(x); + } /** * \brief Returns floor of \f$[x]\f$ @@ -383,7 +500,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval floor(const Interval& x); + inline Interval floor(const Interval& x) + { + return ibex::floor(x); + } /** * \brief Returns ceil of \f$[x]\f$ @@ -391,7 +511,10 @@ namespace codac2 * \param x interval value * \return the operation result */ - Interval ceil(const Interval& x); + inline Interval ceil(const Interval& x) + { + return ibex::ceil(x); + } /** * \brief Computes the backward (reverse) addition @@ -403,7 +526,10 @@ namespace codac2 * \param x1 prior value for \f$[x_1]\f$, may be contracted * \param x2 prior value for \f$[x_2]\f$, may be contracted */ - void bwd_add(const Interval& y, Interval& x1, Interval& x2); + inline void bwd_add(const Interval& y, Interval& x1, Interval& x2) + { + ibex::bwd_add(y,x1,x2); + } /** * \brief Computes the backward (reverse) substraction @@ -415,7 +541,10 @@ namespace codac2 * \param x1 prior value for \f$[x_1]\f$, may be contracted * \param x2 prior value for \f$[x_2]\f$, may be contracted */ - void bwd_sub(const Interval& y, Interval& x1, Interval& x2); + inline void bwd_sub(const Interval& y, Interval& x1, Interval& x2) + { + ibex::bwd_sub(y,x1,x2); + } /** * \brief Computes the backward (reverse) multiplication @@ -427,7 +556,10 @@ namespace codac2 * \param x1 prior value for \f$[x_1]\f$, may be contracted * \param x2 prior value for \f$[x_2]\f$, may be contracted */ - void bwd_mul(const Interval& y, Interval& x1, Interval& x2); + inline void bwd_mul(const Interval& y, Interval& x1, Interval& x2) + { + ibex::bwd_mul(y,x1,x2); + } /** * \brief Computes the backward (reverse) division @@ -439,7 +571,10 @@ namespace codac2 * \param x1 prior value for \f$[x_1]\f$, may be contracted * \param x2 prior value for \f$[x_2]\f$, may be contracted */ - void bwd_div(const Interval& y, Interval& x1, Interval& x2); + inline void bwd_div(const Interval& y, Interval& x1, Interval& x2) + { + ibex::bwd_div(y,x1,x2); + } /** * \brief Computes the backward (reverse) squared operation @@ -450,7 +585,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_sqr(const Interval& y, Interval& x); + inline void bwd_sqr(const Interval& y, Interval& x) + { + ibex::bwd_sqr(y,x); + } /** * \brief Computes the backward (reverse) squared-root operation @@ -461,7 +599,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_sqrt(const Interval& y, Interval& x); + inline void bwd_sqrt(const Interval& y, Interval& x) + { + ibex::bwd_sqrt(y,x); + } /** * \brief Computes the backward (reverse) power operation @@ -473,7 +614,10 @@ namespace codac2 * \param x prior value for \f$[x]\f$, may be contracted * \param p power integer value */ - void bwd_pow(const Interval& y, Interval& x, int p); + inline void bwd_pow(const Interval& y, Interval& x, int p) + { + ibex::bwd_pow(y,p,x); + } /** * \brief Computes the backward (reverse) power operation @@ -485,7 +629,11 @@ namespace codac2 * \param x prior value for \f$[x]\f$, may be contracted * \param p prior value for \f$[p]\f$, may be contracted */ - void bwd_pow(const Interval& y, Interval& x, Interval& p); + inline void bwd_pow(const Interval& y, Interval& x, Interval& p) + { + assert(p.is_degenerated() && "bwd_power(y,x1,x2) (with x1 and x2 intervals) not implemented yet with Gaol"); + ibex::bwd_pow(y,p.mid(),x); + } /** * \brief Computes the backward (reverse) root operation @@ -497,7 +645,10 @@ namespace codac2 * \param x prior value for \f$[x]\f$, may be contracted * \param p root integer value */ - void bwd_root(const Interval& y, Interval& x, int p); + inline void bwd_root(const Interval& y, Interval& x, int p) + { + ibex::bwd_root(y,p,x); + } /** * \brief Computes the backward (reverse) exponential operation @@ -508,7 +659,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_exp(const Interval& y, Interval& x); + inline void bwd_exp(const Interval& y, Interval& x) + { + ibex::bwd_exp(y,x); + } /** * \brief Computes the backward (reverse) logarithmic operation @@ -519,7 +673,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_log(const Interval& y, Interval& x); + inline void bwd_log(const Interval& y, Interval& x) + { + ibex::bwd_log(y,x); + } /** * \brief Computes the backward (reverse) cosine operation @@ -530,7 +687,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_cos(const Interval& y, Interval& x); + inline void bwd_cos(const Interval& y, Interval& x) + { + ibex::bwd_cos(y,x); + } /** * \brief Computes the backward (reverse) sine operation @@ -541,7 +701,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_sin(const Interval& y, Interval& x); + inline void bwd_sin(const Interval& y, Interval& x) + { + ibex::bwd_sin(y,x); + } /** * \brief Computes the backward (reverse) tangent operation @@ -552,7 +715,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_tan(const Interval& y, Interval& x); + inline void bwd_tan(const Interval& y, Interval& x) + { + ibex::bwd_tan(y,x); + } /** * \brief Computes the backward (reverse) arccos operation @@ -563,7 +729,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_acos(const Interval& y, Interval& x); + inline void bwd_acos(const Interval& y, Interval& x) + { + ibex::bwd_acos(y,x); + } /** * \brief Computes the backward (reverse) arcsin operation @@ -574,7 +743,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_asin(const Interval& y, Interval& x); + inline void bwd_asin(const Interval& y, Interval& x) + { + ibex::bwd_asin(y,x); + } /** * \brief Computes the backward (reverse) arctan operation @@ -585,7 +757,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_atan(const Interval& y, Interval& x); + inline void bwd_atan(const Interval& y, Interval& x) + { + ibex::bwd_atan(y,x); + } /** * \brief Computes the backward (reverse) arctan2 operation @@ -597,7 +772,10 @@ namespace codac2 * \param x1 prior value for \f$[x_1]\f$, may be contracted * \param x2 prior value for \f$[x_2]\f$, may be contracted */ - void bwd_atan2(const Interval& y, Interval& x1, Interval& x2); + inline void bwd_atan2(const Interval& y, Interval& x1, Interval& x2) + { + ibex::bwd_atan2(y,x1,x2); + } /** * \brief Computes the backward (reverse) hyperbolic cosine operation @@ -608,7 +786,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_cosh(const Interval& y, Interval& x); + inline void bwd_cosh(const Interval& y, Interval& x) + { + ibex::bwd_cosh(y,x); + } /** * \brief Computes the backward (reverse) hyperbolic sine operation @@ -619,7 +800,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_sinh(const Interval& y, Interval& x); + inline void bwd_sinh(const Interval& y, Interval& x) + { + ibex::bwd_sinh(y,x); + } /** * \brief Computes the backward (reverse) hyperbolic tangent operation @@ -630,7 +814,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_tanh(const Interval& y, Interval& x); + inline void bwd_tanh(const Interval& y, Interval& x) + { + ibex::bwd_tanh(y,x); + } /** * \brief Computes the backward (reverse) hyperbolic arccos operation @@ -641,7 +828,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_acosh(const Interval& y, Interval& x); + inline void bwd_acosh(const Interval& y, Interval& x) + { + ibex::bwd_acosh(y,x); + } /** * \brief Computes the backward (reverse) hyperbolic arcsin operation @@ -652,7 +842,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_asinh(const Interval& y, Interval& x); + inline void bwd_asinh(const Interval& y, Interval& x) + { + ibex::bwd_asinh(y,x); + } /** * \brief Computes the backward (reverse) hyperbolic arctan operation @@ -663,7 +856,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_atanh(const Interval& y, Interval& x); + inline void bwd_atanh(const Interval& y, Interval& x) + { + ibex::bwd_atanh(y,x); + } /** * \brief Computes the backward (reverse) absolute-value operation @@ -674,7 +870,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_abs(const Interval& y, Interval& x); + inline void bwd_abs(const Interval& y, Interval& x) + { + ibex::bwd_abs(y,x); + } /** * \brief Computes the backward (reverse) of the max operation @@ -686,7 +885,10 @@ namespace codac2 * \param x1 prior value for \f$[x_1]\f$, may be contracted * \param x2 prior value for \f$[x_2]\f$, may be contracted */ - void bwd_min(const Interval& y, Interval& x1, Interval& x2); + inline void bwd_min(const Interval& y, Interval& x1, Interval& x2) + { + ibex::bwd_min(y,x1,x2); + } /** * \brief Computes the backward (reverse) of the min operation @@ -698,7 +900,10 @@ namespace codac2 * \param x1 prior value for \f$[x_1]\f$, may be contracted * \param x2 prior value for \f$[x_2]\f$, may be contracted */ - void bwd_max(const Interval& y, Interval& x1, Interval& x2); + inline void bwd_max(const Interval& y, Interval& x1, Interval& x2) + { + ibex::bwd_max(y,x1,x2); + } /** * \brief Computes the backward (reverse) sign operation @@ -709,7 +914,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_sign(const Interval& y, Interval& x); + inline void bwd_sign(const Interval& y, Interval& x) + { + ibex::bwd_sign(y,x); + } /** * \brief Computes the backward (reverse) floor operation @@ -720,7 +928,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_floor(const Interval& y, Interval& x); + inline void bwd_floor(const Interval& y, Interval& x) + { + ibex::bwd_floor(y,x); + } /** * \brief Computes the backward (reverse) ceil operation @@ -731,7 +942,10 @@ namespace codac2 * \param y interval value (result of the forward operation) * \param x prior value for \f$[x]\f$, may be contracted */ - void bwd_ceil(const Interval& y, Interval& x); + inline void bwd_ceil(const Interval& y, Interval& x) + { + ibex::bwd_ceil(y,x); + } /** * \brief Contract \f$[x_1]\f$ and \f$[x_2]\f$ w.r.t. the fact that they are equivalent modulo the period \f$p\f$ @@ -740,6 +954,9 @@ namespace codac2 * \param x2 prior value for \f$[x_2]\f$, may be contracted * \param p period value */ - void bwd_imod(Interval& x1, Interval& x2, double p); + inline void bwd_imod(Interval& x1, Interval& x2, double p) + { + ibex::bwd_imod(x1,x2,p); + } } \ No newline at end of file From 475592c1803d19aed89e91a57c5276747a16a014 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Fri, 6 Dec 2024 13:26:27 +0100 Subject: [PATCH 093/102] [core] inlining Interval: removed codac2_Interval.cpp --- src/core/domains/interval/codac2_Interval.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/core/domains/interval/codac2_Interval.cpp diff --git a/src/core/domains/interval/codac2_Interval.cpp b/src/core/domains/interval/codac2_Interval.cpp deleted file mode 100644 index e69de29b..00000000 From 1db3f4c8fbadc5ddea438f4b6e71a2ade6748c70 Mon Sep 17 00:00:00 2001 From: godardma Date: Fri, 6 Dec 2024 13:32:43 +0100 Subject: [PATCH 094/102] [paver] added pave from shared_ptr --- src/core/paver/codac2_pave.cpp | 10 ++++++++++ src/core/paver/codac2_pave.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/core/paver/codac2_pave.cpp b/src/core/paver/codac2_pave.cpp index b1ee89e4..81c5cff1 100644 --- a/src/core/paver/codac2_pave.cpp +++ b/src/core/paver/codac2_pave.cpp @@ -14,6 +14,11 @@ using namespace codac2; namespace codac2 { + PavingOut pave(const IntervalVector& x, std::shared_ptr> c, double eps) + { + return pave(x, *c, eps); + } + PavingOut pave(const IntervalVector& x, const CtcBase& c, double eps) { assert_release(eps > 0.); @@ -48,6 +53,11 @@ namespace codac2 return p; } + PavingInOut pave(const IntervalVector& x, std::shared_ptr s, double eps) + { + return pave(x, *s, eps); + } + PavingInOut pave(const IntervalVector& x, const SepBase& s, double eps) { assert_release(eps > 0.); diff --git a/src/core/paver/codac2_pave.h b/src/core/paver/codac2_pave.h index 82f4ea44..0f8c890c 100644 --- a/src/core/paver/codac2_pave.h +++ b/src/core/paver/codac2_pave.h @@ -18,7 +18,9 @@ namespace codac2 { // eps: accuracy of the paving algorithm, the undefined boxes will have their max_diam <= eps + PavingOut pave(const IntervalVector& x, std::shared_ptr> c, double eps); PavingOut pave(const IntervalVector& x, const CtcBase& c, double eps); + PavingInOut pave(const IntervalVector& x, std::shared_ptr s, double eps); PavingInOut pave(const IntervalVector& x, const SepBase& s, double eps); template From 519b78130c768759b04b4946f409595b47658806 Mon Sep 17 00:00:00 2001 From: godardma Date: Fri, 6 Dec 2024 15:36:14 +0100 Subject: [PATCH 095/102] [python] added missing draw_paving binding --- python/src/graphics/figures/codac2_py_Figure2D.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/python/src/graphics/figures/codac2_py_Figure2D.cpp b/python/src/graphics/figures/codac2_py_Figure2D.cpp index d72d33c1..aedc6482 100644 --- a/python/src/graphics/figures/codac2_py_Figure2D.cpp +++ b/python/src/graphics/figures/codac2_py_Figure2D.cpp @@ -136,6 +136,16 @@ void export_Figure2D(py::module& m) VOID_FIGURE2D_DRAW_AUV_CONST_VECTOR_REF_FLOAT_CONST_STYLEPROPERTIES_REF, "x"_a, "size"_a, "s"_a=StyleProperties()) + // Pavings + + .def("draw_paving", (void(Figure2D::*)(const PavingOut&,const StyleProperties&,const StyleProperties&))&Figure2D::draw_paving, + VOID_FIGURE2D_DRAW_PAVING_CONST_PAVINGOUT_REF_CONST_STYLEPROPERTIES_REF_CONST_STYLEPROPERTIES_REF, + "p"_a, "boundary_style"_a=StyleProperties::boundary(), "outside_style"_a=StyleProperties::outside()) + + .def("draw_paving", (void(Figure2D::*)(const PavingInOut&,const StyleProperties&,const StyleProperties&,const StyleProperties&))&Figure2D::draw_paving, + VOID_FIGURE2D_DRAW_PAVING_CONST_PAVINGINOUT_REF_CONST_STYLEPROPERTIES_REF_CONST_STYLEPROPERTIES_REF_CONST_STYLEPROPERTIES_REF, + "p"_a, "boundary_style"_a=StyleProperties::boundary(), "outside_style"_a=StyleProperties::outside(), "inside_style"_a=StyleProperties::inside()) + ; py::class_ exported_default_view(m, "DefaultView", DEFAULTVIEW_MAIN); From d4b7a359bbb29d02083b461918f814afabe92d0b Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Fri, 6 Dec 2024 21:15:03 +0100 Subject: [PATCH 096/102] =?UTF-8?q?[mat]=20corrected=20bug=20in=20Gauss=20?= =?UTF-8?q?Jordan=20decomposition=20(thanks=20Damien=20Mass=C3=A9!)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/matrices/codac2_GaussJordan.cpp | 17 +++++++++-------- src/core/matrices/codac2_GaussJordan.h | 4 +++- src/core/matrices/codac2_matrices.h | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/core/matrices/codac2_GaussJordan.cpp b/src/core/matrices/codac2_GaussJordan.cpp index 0b2b2e42..1a61da6d 100644 --- a/src/core/matrices/codac2_GaussJordan.cpp +++ b/src/core/matrices/codac2_GaussJordan.cpp @@ -2,7 +2,7 @@ * codac2_GaussJordan.cpp * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou + * \author Luc Jaulin, Simon Rohou, Damien Massé * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ @@ -40,17 +40,18 @@ namespace codac2 Matrix gauss_jordan(const Matrix& A) { - Index n = A.rows();//, m = A.cols(); + Index n = A.rows(), m = A.cols(); Eigen::FullPivLU lu(A); Matrix L = Matrix::Identity(n,n); - //if(std::pow(L.determinant(),2) < 1e-5) - //{ - // cout << "[Matrix gauss_jordan(const Matrix& A)] -> eye Matrix" << endl; - // return Matrix::eye(n,n); - //} + if(std::pow(L.determinant(),2) < 1e-5) + { + cout << "[Matrix gauss_jordan(const Matrix& A)] -> eye Matrix" << endl; + return Matrix::eye(n,n); + } - L.block(0,0,n,n).triangularView() = lu.matrixLU(); + L.block(0,0,n,std::min(m,n)).triangularView() = + lu.matrixLU().block(0,0,n,std::min(m,n)); Matrix P = lu.permutationP(); Matrix U = lu.matrixLU().triangularView(); diff --git a/src/core/matrices/codac2_GaussJordan.h b/src/core/matrices/codac2_GaussJordan.h index 78b6a14b..4db601ba 100644 --- a/src/core/matrices/codac2_GaussJordan.h +++ b/src/core/matrices/codac2_GaussJordan.h @@ -2,7 +2,7 @@ * \file codac2_GaussJordan.h * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou + * \author Luc Jaulin, Simon Rohou, Damien Massé * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ @@ -16,4 +16,6 @@ namespace codac2 { // Gauss Jordan band diagonalization preconditioning Matrix gauss_jordan(const Matrix& A); + + // From https://www.ensta-bretagne.fr/jaulin/centered.html } \ No newline at end of file diff --git a/src/core/matrices/codac2_matrices.h b/src/core/matrices/codac2_matrices.h index 5053886f..f389d705 100644 --- a/src/core/matrices/codac2_matrices.h +++ b/src/core/matrices/codac2_matrices.h @@ -41,7 +41,7 @@ namespace Eigen * (this is a standard C++ macro which disables all asserts). * https://eigen.tuxfamily.org/dox/TopicPreprocessorDirectives.html */ -#define EIGEN_NO_DEBUG +//#define EIGEN_NO_DEBUG // uncomment to disable Eigen's assertions #endif #include From 9a30b0c5fc5104d4cf0aa873f19f6aa9ae7de715 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Fri, 6 Dec 2024 21:34:40 +0100 Subject: [PATCH 097/102] [intv] corrected possible bug in .rand() method --- src/core/domains/interval/codac2_Interval.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/domains/interval/codac2_Interval.h b/src/core/domains/interval/codac2_Interval.h index 80730c8c..87822395 100644 --- a/src/core/domains/interval/codac2_Interval.h +++ b/src/core/domains/interval/codac2_Interval.h @@ -794,7 +794,10 @@ namespace codac2 double a = std::max(next_float(-oo),lb()); double b = std::min(previous_float(oo),ub()); - return a + (((double)std::rand())/(double)RAND_MAX)*(b-a); + double r = a + (((double)std::rand())/(double)RAND_MAX)*(b-a); + // The above operation may result in a floating point outside the bounds, + // due to floating-point errors. Such possible error is corrected below: + return std::max(lb(),std::min(r,ub())); } inline double Interval::rad() const From 155c14bda95eb7d519d62e8ea5e99beecdc7f13a Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Mon, 9 Dec 2024 14:02:46 +0100 Subject: [PATCH 098/102] [ctc] added assertion for CtcInverse (image argument) --- src/core/contractors/codac2_CtcInverse.h | 5 ++++- .../analytic/codac2_AnalyticFunction.h | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/core/contractors/codac2_CtcInverse.h b/src/core/contractors/codac2_CtcInverse.h index a987520a..33b8365e 100644 --- a/src/core/contractors/codac2_CtcInverse.h +++ b/src/core/contractors/codac2_CtcInverse.h @@ -29,7 +29,10 @@ namespace codac2 requires IsCtcBaseOrPtr CtcInverse(const AnalyticFunction::Domain>& f, const C& ctc_y, bool with_centered_form = true, bool is_not_in = false) : _f(f), _ctc_y(ctc_y), _with_centered_form(with_centered_form), _is_not_in(is_not_in) - { } + { + assert_release([&]() { return f.output_size() == size_of(ctc_y); }() + && "CtcInverse: invalid dimension of image argument ('y' or 'ctc_y')"); + } CtcInverse(const AnalyticFunction::Domain>& f, const Y& y, bool with_centered_form = true, bool is_not_in = false) : CtcInverse(f, CtcWrapper_(y), with_centered_form, is_not_in) diff --git a/src/core/functions/analytic/codac2_AnalyticFunction.h b/src/core/functions/analytic/codac2_AnalyticFunction.h index d15886f7..b5a45a14 100644 --- a/src/core/functions/analytic/codac2_AnalyticFunction.h +++ b/src/core/functions/analytic/codac2_AnalyticFunction.h @@ -112,6 +112,26 @@ namespace codac2 return eval_(x...).da; } + Index output_size() const + { + if constexpr(std::is_same_v) + return 1; + + else if constexpr(std::is_same_v) + { + // A dump evaluation is performed to estimate the dimension + // of the image of this function. A natural evaluation is assumed + // to be faster. + return natural_eval(IntervalVector(this->input_size())).size(); + } + + else + { + assert_release(false && "unable to estimate output size"); + return 0; + } + } + friend std::ostream& operator<<(std::ostream& os, [[maybe_unused]] const AnalyticFunction& f) { if constexpr(std::is_same_v) From 81fb78981c526b17762dd9e69a1397275376e575 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Mon, 9 Dec 2024 15:12:56 +0100 Subject: [PATCH 099/102] [ctc] improved efficiency of MulOp::bwd --- src/core/contractors/codac2_directed_ctc.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/core/contractors/codac2_directed_ctc.cpp b/src/core/contractors/codac2_directed_ctc.cpp index 6187a4db..d55e2472 100644 --- a/src/core/contractors/codac2_directed_ctc.cpp +++ b/src/core/contractors/codac2_directed_ctc.cpp @@ -397,8 +397,8 @@ using namespace codac2; else*/ { IntervalMatrix Q = gauss_jordan(x1.mid()); - auto b_tilde = Q*y; - auto A_tilde = Q*x1; // should be a tree matrix + IntervalVector b_tilde = Q*y; + IntervalMatrix A_tilde = Q*x1; // should be a tree matrix for(int a = 0 ; a < 1 ; a++) { @@ -412,10 +412,7 @@ using namespace codac2; if(i != j) u -= x2[j]*A_tilde(k,j); - if(A_tilde(k,i).contains(0.)) - continue; - - x2[i] &= u / A_tilde(k,i); + MulOp::bwd(u, x2[i], A_tilde(k,i)); } } } From 269afa65e9c7ba4fcb96d3e3ba397df8d4471454 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Thu, 12 Dec 2024 19:55:37 +0100 Subject: [PATCH 100/102] [ctc] improved MulOp operators (for r>c linear systems) --- src/core/contractors/codac2_directed_ctc.cpp | 84 +++++++++++++++++++- src/core/contractors/codac2_directed_ctc.h | 5 ++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/core/contractors/codac2_directed_ctc.cpp b/src/core/contractors/codac2_directed_ctc.cpp index d55e2472..db25b48a 100644 --- a/src/core/contractors/codac2_directed_ctc.cpp +++ b/src/core/contractors/codac2_directed_ctc.cpp @@ -362,6 +362,48 @@ using namespace codac2; MulOp::bwd(y, x2, x1); } + Interval MulOp::fwd(const IntervalRow& x1, const IntervalVector& x2) + { + assert(x1.size() == x2.size()); + Interval s(0.); + for(Index i = 0 ; i < x1.size() ; i++) + s += x1[i]*x2[i]; + return s; + } + + //ScalarOpValue MulOp::fwd(const RowOpValue& x1, const VectorOpValue& x2) + //{ + // // RowOpValue not yet defined + //} + + void MulOp::bwd(const Interval& y, IntervalRow& x1, IntervalVector& x2) + { + assert(x1.size() == x2.size()); + + const Index n = x1.size(); + vector sums(n), prods(n); + + // Forward propagation + + for(Index i = 0 ; i < n ; i++) + { + prods[i] = x1[i]*x2[i]; + sums[i] = prods[i]; + if(i > 0) sums[i] += sums[i-1]; + } + + // Backward propagation + + sums[n-1] &= y; + + for(Index i = n-1 ; i >= 0 ; i--) + { + if(i > 0) AddOp::bwd(sums[i],sums[i-1],prods[i]); + else prods[0] &= sums[0]; + MulOp::bwd(prods[i],x1[i],x2[i]); + } + } + IntervalVector MulOp::fwd(const IntervalMatrix& x1, const IntervalVector& x2) { assert(x1.cols() == x2.size()); @@ -381,20 +423,58 @@ using namespace codac2; #include "codac2_linear_ctc.h" #include "codac2_GaussJordan.h" + //#include "codac2_ibex.h" + void MulOp::bwd(const IntervalVector& y, IntervalMatrix& x1, IntervalVector& x2) { assert(x1.rows() == y.size()); assert(x1.cols() == x2.size()); - /*if(x1.is_squared()) // not working for any x1 + /*if(x1.is_squared()) // not working for any squared x1 { CtcGaussElim ctc_ge; CtcLinearPrecond ctc_gep(ctc_ge); IntervalVector y_(y); ctc_gep.contract(x1,x2,y_); + }*/ + + if(x1.rows() > x1.cols()) + { + #if 0 // IBEX version + ibex::IntervalVector ibex_y(to_ibex(y)), ibex_x2(to_ibex(x2)); + ibex::IntervalMatrix ibex_x1(to_ibex(x1)); + ibex::bwd_mul(ibex_y, ibex_x1, ibex_x2, 0.05); + x1 &= to_codac(ibex_x1); + x2 &= to_codac(ibex_x2); + #else + + Index last_row = 0; + Index i = 0; + + do + { + double vol_x2 = x2.volume(); + IntervalRow row_i = x1.row(i); + MulOp::bwd(y[i],row_i,x2); + + if(row_i.is_empty()) + { + x1.set_empty(); + return; + } + + else + x1.row(i) = row_i; + + if(x2.volume()/vol_x2 < 0.98) + last_row = i; + i = (i+1)%y.size(); + } while(i != last_row); + + #endif } - else*/ + else { IntervalMatrix Q = gauss_jordan(x1.mid()); IntervalVector b_tilde = Q*y; diff --git a/src/core/contractors/codac2_directed_ctc.h b/src/core/contractors/codac2_directed_ctc.h index 66c65ac7..4b9ad460 100644 --- a/src/core/contractors/codac2_directed_ctc.h +++ b/src/core/contractors/codac2_directed_ctc.h @@ -12,6 +12,7 @@ #include #include "codac2_analytic_values.h" #include "codac2_template_tools.h" +#include "codac2_IntervalRow.h" namespace codac2 { @@ -87,6 +88,10 @@ namespace codac2 static VectorOpValue fwd(const VectorOpValue& x1, const ScalarOpValue& x2); static void bwd(const IntervalVector& y, IntervalVector& x1, Interval& x2); + static Interval fwd(const IntervalRow& x1, const IntervalVector& x2); + //static ScalarOpValue fwd(const RowOpValue& x1, const VectorOpValue& x2); // RowOpValue not yet defined + static void bwd(const Interval& y, IntervalRow& x1, IntervalVector& x2); + static IntervalVector fwd(const IntervalMatrix& x1, const IntervalVector& x2); static VectorOpValue fwd(const MatrixOpValue& x1, const VectorOpValue& x2); static void bwd(const IntervalVector& y, IntervalMatrix& x1, IntervalVector& x2); From a81e68d6e2de229280836bb18d85375a10fa2c92 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Sun, 15 Dec 2024 11:45:05 +0100 Subject: [PATCH 101/102] [ellips] updates (homogenization + Eigen optimizations) --- examples/ellipsoid_example/main.cpp | 87 +++++++++++-------- python/src/core/CMakeLists.txt | 1 + python/src/core/codac2_py_core.cpp | 2 + .../domains/ellipsoid/codac2_py_Ellipsoid.cpp | 23 +++-- .../ellipsoid/codac2_py_Ellipsoid_utils.cpp | 35 ++++++++ .../graphics/figures/codac2_py_Figure2D.cpp | 6 ++ .../domains/ellipsoid/codac2_Ellipsoid.cpp | 69 +++++++-------- src/core/domains/ellipsoid/codac2_Ellipsoid.h | 3 +- .../ellipsoid/codac2_Ellipsoid_utils.cpp | 53 ++++++----- .../ellipsoid/codac2_Ellipsoid_utils.h | 9 +- src/graphics/CMakeLists.txt | 1 - src/graphics/figures/codac2_Figure2D.cpp | 41 ++++++++- src/graphics/figures/codac2_Figure2D.h | 3 + .../figures/codac2_Figure2D_ellipsoid.cpp | 56 ------------ .../figures/codac2_OutputFigure2D.cpp | 4 +- 15 files changed, 226 insertions(+), 167 deletions(-) create mode 100644 python/src/core/domains/ellipsoid/codac2_py_Ellipsoid_utils.cpp delete mode 100644 src/graphics/figures/codac2_Figure2D_ellipsoid.cpp diff --git a/examples/ellipsoid_example/main.cpp b/examples/ellipsoid_example/main.cpp index 1c328c8e..c3cb3753 100644 --- a/examples/ellipsoid_example/main.cpp +++ b/examples/ellipsoid_example/main.cpp @@ -13,10 +13,11 @@ int main() { fig1.set_window_properties({0, 100}, {500, 500}); // initial ellipsoid - Vector mu({1., 0.}); - Matrix G({{0.05, 0.0}, - {0., 0.05}}); - Ellipsoid e1(mu, G); + Ellipsoid e1( + {1., 0.}, // mu + {{0.05, 0.0}, // G + {0., 0.05}} + ); fig1.draw_ellipsoid(e1, {Color::red(), Color::red(0.3)}); cout << "Initial ellipsoid e1 (red):" << endl; cout << e1 << endl; @@ -51,10 +52,10 @@ int main() { int Np = 200; for (int i = 0; i < Np; i++) { Vector x0 = e1.rand(); - fig1.draw_box(IntervalVector(x0).inflate(0.0001), {Color::black(), Color::black(0.3)}); + fig1.draw_point(x0, {Color::black(), Color::black(0.3)}); for (int j = 0; j < N; j++) { x0 = h.eval(x0).mid(); - fig1.draw_box(IntervalVector(x0).inflate(0.0001), {Color::black(), Color::black(0.3)}); + fig1.draw_point(x0, {Color::black(), Color::black(0.3)}); } } @@ -62,19 +63,24 @@ int main() { // ellipsoid projections // ---------------------------------------------------------- - Vector mu4({1., 0., 0.}); - Matrix G4({{1., 0.5, 0.}, - {0.5, 2., 0.2}, - {0., 0.2, 3.}}); - Ellipsoid e4(mu4, G4); - - Matrix G5 = 0.7 * G4; - Ellipsoid e5(mu4, G5); - - Matrix G6({{2., 0., 0.5}, - {0., 1., 0.2}, - {0., 0.2, 3.}}); - Ellipsoid e6(mu4, G6); + Ellipsoid e4 { + {1., 0., 0.}, // mu + {{1., 0.5, 0.}, // G + {0.5, 2., 0.2}, + {0., 0.2, 3.}} + }; + + Ellipsoid e5 { + e4.mu, // mu + 0.7 * e4.G // G + }; + + Ellipsoid e6 { + e4.mu, // mu + {{2., 0., 0.5}, // G + {0., 1., 0.2}, + {0., 0.2, 3.}} + }; Figure2D fig2("Projected ellipsoid xy", GraphicOutput::VIBES); Figure2D fig3("Projected ellipsoid yz", GraphicOutput::VIBES); @@ -102,11 +108,10 @@ int main() { // particle cloud (draw the evolution of 200 points in the ellipsoid e5) for (int i = 0; i < Np; i++) { - IntervalVector x5(e5.rand()); - x5.inflate(0.001); - fig2.draw_box(x5, {Color::black(), Color::black(0.3)}); - fig3.draw_box(x5, {Color::black(), Color::black(0.3)}); - fig4.draw_box(x5, {Color::black(), Color::black(0.3)}); + Vector x5 = e5.rand(); + fig2.draw_point(x5, {Color::black(), Color::black(0.3)}); + fig3.draw_point(x5, {Color::black(), Color::black(0.3)}); + fig4.draw_point(x5, {Color::black(), Color::black(0.3)}); } // ---------------------------------------------------------- @@ -149,10 +154,16 @@ int main() { fig5.set_axes(axis(0, {-0.5, 2}), axis(1, {-1.5, 1.})); fig5.set_window_properties({700, 600}, {500, 500}); - Ellipsoid e9(Vector({0., 0.5}), Matrix({{0.25, 0.}, - {0., 0.}})); - Ellipsoid e10(Vector({0., -0.5}), Matrix({{0.25, 0.}, - {0., 0.25}})); + Ellipsoid e9 { + {0., 0.5}, // mu + {{0.25, 0.}, // G + {0., 0.}} + }; + Ellipsoid e10 { + {0., -0.5}, // mu + {{0.25, 0.}, // G + {0., 0.25}} + }; fig5.draw_ellipsoid(e9, {Color::blue(), Color::red(0.3)}); fig5.draw_ellipsoid(e10, {Color::red(), Color::red(0.3)}); @@ -176,14 +187,12 @@ int main() { // particle cloud (draw the evolution of 200 points in the ellipsoid) for (int i = 0; i < Np; i++) { Vector x0 = e9.rand(); - fig5.draw_box(IntervalVector(x0).inflate(0.0001), {Color::black(), Color::black(0.3)}); - x0 = h2.eval(x0).mid(); - fig5.draw_box(IntervalVector(x0).inflate(0.0001), {Color::black(), Color::black(0.3)}); + fig5.draw_point(x0, {Color::black(), Color::black(0.3)}); + fig5.draw_point(h2.eval(x0).mid(), {Color::black(), Color::black(0.3)}); x0 = e10.rand(); - fig5.draw_box(IntervalVector(x0).inflate(0.0001), {Color::black(), Color::black(0.3)}); - x0 = h3.eval(x0).mid(); - fig5.draw_box(IntervalVector(x0).inflate(0.0001), {Color::black(), Color::black(0.3)}); + fig5.draw_point(x0, {Color::black(), Color::black(0.3)}); + fig5.draw_point(h3.eval(x0).mid(), {Color::black(), Color::black(0.3)}); } // ---------------------------------------------------------- @@ -193,8 +202,14 @@ int main() { // pendulum example AnalyticFunction h4{ {x}, vec(x[0] + 0.5 * x[1] , x[1] + 0.5 * (-x[1]-sin(x[0])))}; - Ellipsoid e13(Vector(2), Matrix(2,2)); - Ellipsoid e13_out(Vector(2), Matrix(2,2)); + Ellipsoid e13 { + Vector::zero(2), // mu + Matrix::zero(2,2) // G + }; + Ellipsoid e13_out { + Vector::zero(2), // mu + Matrix::zero(2,2) // G + }; int alpha_max = 1; if(stability_analysis(h4,alpha_max, e13, e13_out) == BoolInterval::TRUE) diff --git a/python/src/core/CMakeLists.txt b/python/src/core/CMakeLists.txt index c2d7a483..0bc86a5a 100644 --- a/python/src/core/CMakeLists.txt +++ b/python/src/core/CMakeLists.txt @@ -33,6 +33,7 @@ contractors/codac2_py_linear_ctc.cpp domains/ellipsoid/codac2_py_Ellipsoid.cpp + domains/ellipsoid/codac2_py_Ellipsoid_utils.cpp domains/interval/codac2_py_Interval.cpp domains/interval/codac2_py_Interval_operations.cpp domains/interval/codac2_py_IntervalMatrix.cpp diff --git a/python/src/core/codac2_py_core.cpp b/python/src/core/codac2_py_core.cpp index dbe2355c..89c071a9 100644 --- a/python/src/core/codac2_py_core.cpp +++ b/python/src/core/codac2_py_core.cpp @@ -53,6 +53,7 @@ void export_linear_ctc(py::module& m); // domains void export_BoolInterval(py::module& m); void export_Ellipsoid(py::module& m); +void export_Ellipsoid_utils(py::module& m); py::class_ export_Interval(py::module& m); void export_Interval_operations(py::module& m, py::class_& py_Interval); py::class_ export_IntervalRow(py::module& m); @@ -164,6 +165,7 @@ PYBIND11_MODULE(_core, m) // domains export_BoolInterval(m); export_Ellipsoid(m); + export_Ellipsoid_utils(m); auto py_Interval = export_Interval(m); export_Interval_operations(m, py_Interval); auto py_IR = export_IntervalRow(m); diff --git a/python/src/core/domains/ellipsoid/codac2_py_Ellipsoid.cpp b/python/src/core/domains/ellipsoid/codac2_py_Ellipsoid.cpp index a411561e..e1784a10 100644 --- a/python/src/core/domains/ellipsoid/codac2_py_Ellipsoid.cpp +++ b/python/src/core/domains/ellipsoid/codac2_py_Ellipsoid.cpp @@ -29,7 +29,7 @@ void export_Ellipsoid(py::module& m) .def_readwrite("G", &Ellipsoid::G, MATRIX_ELLIPSOID_G) - .def(py::init(), + .def(py::init(), ELLIPSOID_ELLIPSOID_INDEX, "n"_a) @@ -40,13 +40,6 @@ void export_Ellipsoid(py::module& m) .def(py::init(), "e"_a) - .def("__repr__", [](const Ellipsoid& e) { - std::ostringstream s; - s << e; - return string(s.str()); - }, - OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_ELLIPSOID_REF) - .def("size", &Ellipsoid::size, INDEX_ELLIPSOID_SIZE_CONST) @@ -60,8 +53,20 @@ void export_Ellipsoid(py::module& m) BOOLINTERVAL_ELLIPSOID_IS_CONCENTRIC_SUBSET_CONST_ELLIPSOID_REF_CONST, "e"_a) + .def("proj_2d", &Ellipsoid::proj_2d, + ELLIPSOID_ELLIPSOID_PROJ_2D_CONST_VECTOR_REF_CONST_VECTOR_REF_CONST_VECTOR_REF_CONST, + "d"_a, "v"_a, "u"_a) + + .def("__repr__", [](const Ellipsoid& e) { + std::ostringstream s; + s << e; + return string(s.str()); + }, + OSTREAM_REF_OPERATOROUT_OSTREAM_REF_CONST_ELLIPSOID_REF) + .def(py::self + py::self, - ELLIPSOID_OPERATORPLUS_CONST_ELLIPSOID_REF_CONST_ELLIPSOID_REF) + ELLIPSOID_OPERATORPLUS_CONST_ELLIPSOID_REF_CONST_ELLIPSOID_REF, + py::is_operator()) ; diff --git a/python/src/core/domains/ellipsoid/codac2_py_Ellipsoid_utils.cpp b/python/src/core/domains/ellipsoid/codac2_py_Ellipsoid_utils.cpp new file mode 100644 index 00000000..1fd51de1 --- /dev/null +++ b/python/src/core/domains/ellipsoid/codac2_py_Ellipsoid_utils.cpp @@ -0,0 +1,35 @@ +/** + * Codac binding (core) + * ---------------------------------------------------------------------------- + * \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_Ellipsoid_utils_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py): + +using namespace std; +using namespace codac2; +namespace py = pybind11; +using namespace pybind11::literals; + +void export_Ellipsoid_utils(py::module& m) +{ + m + + .def("stability_analysis", &codac2::stability_analysis, + BOOLINTERVAL_STABILITY_ANALYSIS_CONST_ANALYTICFUNCTION_VECTOROPVALUE_REF_UNSIGNED_INT_ELLIPSOID_REF_ELLIPSOID_REF_BOOL, + "f"_a, "alpha_max"_a, "e"_a, "e_out"_a, "verbose"_a=false) + + .def("solve_discrete_lyapunov", &codac2::solve_discrete_lyapunov, + MATRIX_SOLVE_DISCRETE_LYAPUNOV_CONST_MATRIX_REF_CONST_MATRIX_REF, + "A"_a, "Q"_a) + + ; +} \ No newline at end of file diff --git a/python/src/graphics/figures/codac2_py_Figure2D.cpp b/python/src/graphics/figures/codac2_py_Figure2D.cpp index 4a3e18d1..4c9e143f 100644 --- a/python/src/graphics/figures/codac2_py_Figure2D.cpp +++ b/python/src/graphics/figures/codac2_py_Figure2D.cpp @@ -65,6 +65,12 @@ void export_Figure2D(py::module& m) VOID_FIGURE2D_SET_AXES_CONST_FIGUREAXIS_REF_CONST_FIGUREAXIS_REF, "axis1"_a, "axis2"_a) + .def("i", &Figure2D::i, + CONST_INDEX_REF_FIGURE2D_I_CONST) + + .def("j", &Figure2D::j, + CONST_INDEX_REF_FIGURE2D_J_CONST) + .def("pos", &Figure2D::pos, CONST_VECTOR_REF_FIGURE2D_POS_CONST) diff --git a/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp b/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp index 8dd67f45..f7102e3a 100644 --- a/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp +++ b/src/core/domains/ellipsoid/codac2_Ellipsoid.cpp @@ -17,7 +17,7 @@ using codac2::Vector; namespace codac2 { Ellipsoid::Ellipsoid(Index n) - : mu(Vector(n)), G(Matrix(n, n)) { + : mu(Vector::zero(n)), G(Matrix::zero(n, n)) { assert_release(n > 0); } @@ -27,6 +27,7 @@ namespace codac2 { } Index Ellipsoid::size() const { + assert(mu.size() == G.cols() && G.is_squared()); return mu.size(); } @@ -89,13 +90,13 @@ namespace codac2 { return BoolInterval::TRUE; } - void Ellipsoid::projection2D(const Vector& d, const Vector& v, const Vector& u) + Ellipsoid Ellipsoid::proj_2d(const Vector& d, const Vector& v, const Vector& u) const { // from [Pope S. B. - Algorithms for Ellipsoids - 2008] - assert( d.size() == v.size()); - assert( d.size() == u.size()); - assert( d.size() == this->size()); - assert( (v.transpose()*u).norm() == 0); // u & v orthogonal + assert_release( d.size() == v.size()); + assert_release( d.size() == u.size()); + assert_release( d.size() == this->size()); + assert_release( (v.transpose()*u).norm() == 0); // u & v orthogonal // Normalized Projection matrix // the plane (d,u,v) is also the affine plan {x|x=d+Tt} with T = [u,v] @@ -104,22 +105,19 @@ namespace codac2 { T.col(1) = u/u.norm(); auto TTG = T.transpose() * this->G; - Eigen::BDCSVD bdcsvd(TTG, Eigen::ComputeFullU); - Matrix U(bdcsvd.matrixU()); - Matrix E((Eigen::MatrixXd) bdcsvd.singularValues().asDiagonal()); - this->G = U * E; - this->mu = T.transpose() * (d + T * T.transpose() * (this->mu - d)); + Eigen::BDCSVD bdcsvd(TTG); + auto U = bdcsvd.matrixU(); + auto E = bdcsvd.singularValues().asDiagonal(); + + return { + T.transpose() * (d + T * T.transpose() * (this->mu - d)), + U * E + }; } Ellipsoid operator+(const Ellipsoid &e1, const Ellipsoid &e2) { assert_release(e1.size() == e2.size()); - //if(e1.is_unbounded() || e2.is_unbounded()) - // return Ellipsoid(e1.size()); - - //if(e1.is_empty() || e2.is_empty()) - // return Ellipsoid::empty(e1.size()); - auto Q1 = e1.G * e1.G.transpose(); auto Q2 = e2.G * e2.G.transpose(); @@ -176,14 +174,13 @@ namespace codac2 { assert(G.is_squared() && J.is_squared() && J_box.is_squared()); assert(n == J.cols() && n == J_box.cols() && n == q.size()); - Matrix JG = J * G; // note: reliability may be lost here! - IntervalMatrix G_(G); - IntervalMatrix JG_ = IntervalMatrix(JG); - IntervalVector unit_box(G.rows()); unit_box.init(Interval(-1,1)); + auto JG = J * G; // note: reliability may be lost here! + auto G_ = G.template cast(); + IntervalVector unit_box = IntervalVector::constant(G.rows(), {-1,1}); // normal case - IntervalMatrix I_ = IntervalMatrix(Eigen::MatrixXd::Identity(G.rows(),G.cols())); - IntervalMatrix JG_inv_(inverse_enclosure(JG)); // non rigourous inversion + IntervalMatrix I_ = IntervalMatrix::eye(G.rows(),G.cols()); + IntervalMatrix JG_inv_ = inverse_enclosure(JG); // rigourous inversion Matrix M(JG); auto W = JG_inv_; auto Z = I_; @@ -199,28 +196,26 @@ namespace codac2 { assert(q.size() == G.rows()); // SVD decomposition of JG = U*E*V.T - Eigen::BDCSVD bdcsvd(JG,Eigen::ComputeFullU); - IntervalMatrix U_(bdcsvd.matrixU()); // which is also the right part - Vector Sv(bdcsvd.singularValues()); // vectors of singular values + Eigen::BDCSVD bdcsvd(JG); + auto U_ = bdcsvd.matrixU().template cast(); // which is also the right part + auto Sv = bdcsvd.singularValues(); // vectors of singular values // select new singular values - int dim = G.rows(); - IntervalVector s_box(U_.transpose()*J_box*G_*unit_box); - IntervalMatrix S_(Eigen::MatrixXd::Zero(dim,dim)); // diagonal matrix of the new singular value - IntervalMatrix S_pinv_(Eigen::MatrixXd::Zero(dim,dim)); // pseudo inverse of S - for(int i=0;itrig[1]){ // normal size singular values S_(i,i) = Interval(Sv[i]); - S_pinv_(i,i) = 1/S_(i,i); }else{ // for very small singular values (0 included) use s_box - double val = s_box[i].ub(); - S_(i,i) = Interval(q[i]*val); - S_pinv_(i,i)=1/S_(i,i); + S_(i,i) = Interval(q[i])*s_box[i].ub(); } + S_pinv_(i,i) = 1./S_(i,i); } M = (U_*S_).mid(); W = S_pinv_*U_.transpose(); - Z = W*JG_; + Z = W*JG.template cast(); } auto b_box = (W * J_box * G_ - Z) * unit_box; @@ -253,7 +248,7 @@ namespace codac2 { ostream& operator<<(ostream& os, const Ellipsoid& e) { - os << "Ellipsoid:\n" + os << "Ellipsoid " << e.size() << "d:\n" << " mu=" << e.mu << "\n" << " G=\n" << e.G; return os; diff --git a/src/core/domains/ellipsoid/codac2_Ellipsoid.h b/src/core/domains/ellipsoid/codac2_Ellipsoid.h index 9202861b..a7ac9b3a 100644 --- a/src/core/domains/ellipsoid/codac2_Ellipsoid.h +++ b/src/core/domains/ellipsoid/codac2_Ellipsoid.h @@ -96,8 +96,9 @@ namespace codac2 * \param d a point on the plane * \param v a vector of the plane * \param u a other vector of the plane, orthogonal to v + * \return the projected 2d ellipsoid */ - void projection2D(const Vector& d, const Vector& v, const Vector& u); + Ellipsoid proj_2d(const Vector& d, const Vector& v, const Vector& u) const; public: diff --git a/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.cpp b/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.cpp index 2416c949..f14d3f2c 100644 --- a/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.cpp +++ b/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.cpp @@ -18,53 +18,66 @@ using codac2::BoolInterval; namespace codac2 { - Matrix solve_discrete_lyapunov(const Matrix& a,const Matrix& q) + Matrix solve_discrete_lyapunov(const Matrix& A, const Matrix& Q) { // implementation of the scipy solver for the discrete lyapunov equation (real matrix only) // works well under dimension 10 // https://github.com/scipy/scipy/blob/v1.14.1/scipy/linalg/_solvers.py#L235-L323 // Solves the discrete Lyapunov equation :math:`AXA^H - X + Q = 0` - assert(a.rows() == a.cols()); - assert(a.rows() == q.rows()); - assert(a.cols() == q.cols()); + assert(A.is_squared() && Q.is_squared()); + assert(A.size() == Q.size()); - Eigen::MatrixXd lhs = Eigen::KroneckerProduct(a, a); - lhs = Eigen::MatrixXd::Identity(lhs.rows(),lhs.cols()) - lhs; - Eigen::MatrixXd x = lhs.colPivHouseholderQr().solve((Eigen::VectorXd)q.reshaped()); - return Matrix(x.reshaped(q.rows(),q.cols())); + Matrix lhs = Eigen::KroneckerProduct(A,A); + lhs = Matrix::eye(lhs.rows(),lhs.cols()) - lhs; + Matrix x = lhs.colPivHouseholderQr().solve((Vector)Q.reshaped()); + return Matrix(x.reshaped(Q.rows(),Q.cols())); } - BoolInterval stability_analysis(const AnalyticFunction &f, int alpha_max, Ellipsoid &e, Ellipsoid &e_out) + BoolInterval stability_analysis(const AnalyticFunction &f, unsigned int alpha_max, Ellipsoid &e, Ellipsoid &e_out, bool verbose) { assert_release(f.args().size() == 1 && "f must have only one arg"); // get the Jacobian of f at the origin - int n = f.input_size(); + Index n = f.input_size(); Vector origin(Eigen::VectorXd::Zero(n)); Matrix J = f.diff(IntervalVector(origin)).mid(); // solve the axis aligned discrete lyapunov equation J.T * P * J − P = −J.T * J - Matrix P = solve_discrete_lyapunov(J.transpose(),J.transpose()*J); // TODO solve the Lyapunov equation !!! - Matrix G0((P.inverse()).sqrt()); - int alpha = 0; + auto P = solve_discrete_lyapunov(J.transpose(),J.transpose()*J); // TODO solve the Lyapunov equation !!! + auto G0 = P.inverse().sqrt(); + unsigned int alpha = 0; + + if(verbose) + cout << "Stability analysis:" << endl; while(alpha <= alpha_max) { - e = Ellipsoid(origin, std::pow(10,-alpha) * G0); + e = Ellipsoid(origin, std::pow(10.,-(int)alpha) * G0); e_out = nonlinear_mapping(e,f); - cout << "\nwith alpha = " << alpha << endl; - cout << "e is\n" << e << endl; - cout << "e_out is\n" << e_out << endl; + + if(verbose) + { + cout << "\t with alpha = " << alpha << endl; + cout << "\t e is\n" << e << endl; + cout << "\t e_out is\n" << e_out << endl; + } if(e_out.is_concentric_subset(e) == BoolInterval::TRUE) { - cout << "The system is stable" << endl; - cout << "Domain of attraction :\n" << e_out << endl; + if(verbose) + { + cout << "\t The system is stable" << endl; + cout << "\t Domain of attraction :\n" << e_out << endl; + } return BoolInterval::TRUE; } + alpha++; } - cout << "The method is not able to conclude on the stability" << endl; + + if(verbose) + cout << "\t The method is not able to conclude on the stability" << endl; + return BoolInterval::UNKNOWN; } } \ No newline at end of file diff --git a/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.h b/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.h index 48265836..45259423 100644 --- a/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.h +++ b/src/core/domains/ellipsoid/codac2_Ellipsoid_utils.h @@ -20,16 +20,17 @@ namespace codac2 * \param alpha_max ... * \param e ... * \param e_out ... + * \param verbose ... * \return ... */ - BoolInterval stability_analysis(const AnalyticFunction& f, int alpha_max, Ellipsoid& e, Ellipsoid& e_out); + BoolInterval stability_analysis(const AnalyticFunction& f, unsigned int alpha_max, Ellipsoid& e, Ellipsoid& e_out, bool verbose = false); /** * \brief ... * - * \param a ... - * \param q ... + * \param A ... + * \param Q ... * \return ... */ - Matrix solve_discrete_lyapunov(const Matrix& a, const Matrix& q); + Matrix solve_discrete_lyapunov(const Matrix& A, const Matrix& Q); } \ No newline at end of file diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt index ca7d530e..c18ba4b8 100644 --- a/src/graphics/CMakeLists.txt +++ b/src/graphics/CMakeLists.txt @@ -12,7 +12,6 @@ ${CMAKE_CURRENT_SOURCE_DIR}/3rd/vibes/vibes.h ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_Figure2D.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_Figure2D_ellipsoid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_Figure2D.h ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_Figure2DInterface.h ${CMAKE_CURRENT_SOURCE_DIR}/figures/codac2_OutputFigure2D.cpp diff --git a/src/graphics/figures/codac2_Figure2D.cpp b/src/graphics/figures/codac2_Figure2D.cpp index b3af3ef9..9f9d210d 100644 --- a/src/graphics/figures/codac2_Figure2D.cpp +++ b/src/graphics/figures/codac2_Figure2D.cpp @@ -2,7 +2,7 @@ * codac2_Figure2D.cpp * ---------------------------------------------------------------------------- * \date 2024 - * \author Simon Rohou + * \author Simon Rohou, Morgan Louédec * \copyright Copyright 2024 Codac Team * \license GNU Lesser General Public License (LGPL) */ @@ -55,6 +55,16 @@ void Figure2D::set_axes(const FigureAxis& axis1, const FigureAxis& axis2) output_fig->update_axes(); } +const Index& Figure2D::i() const +{ + return axes()[0].dim_id; +} + +const Index& Figure2D::j() const +{ + return axes()[1].dim_id; +} + const Vector& Figure2D::pos() const { return _pos; @@ -199,6 +209,35 @@ void Figure2D::draw_ellipse(const Vector& c, const Vector& ab, double theta, con output_fig->draw_ellipse(c,ab,theta,s); } +void Figure2D::draw_ellipsoid(const Ellipsoid &e, const StyleProperties &s) { + // Author: Morgan Louédec + assert_release(this->size() <= e.size()); + + Index n = e.size(); + Ellipsoid proj_e(2); + + // 2d projection of the ellipsoid + if (n > 2) { + Vector v = Vector::zero(n); + v[i()] = 1; + Vector u = Vector::zero(n); + u[j()] = 1; + proj_e = e.proj_2d(Vector::zero(n), v, u); + } else { + proj_e = e; + } + + // draw the 2d ellipsoid + Eigen::JacobiSVD jsvd(proj_e.G, Eigen::ComputeThinU); + Matrix U(jsvd.matrixU()); + Vector ab(jsvd.singularValues()); + + double theta = std::atan2(U(1, 0), U(0, 0)); + + for(const auto& output_fig : _output_figures) + output_fig->draw_ellipse(proj_e.mu, ab, theta, s); +} + void Figure2D::draw_tank(const Vector& x, float size, const StyleProperties& s) { assert_release(this->size() <= x.size()+1); diff --git a/src/graphics/figures/codac2_Figure2D.h b/src/graphics/figures/codac2_Figure2D.h index 7ed01306..81e58764 100644 --- a/src/graphics/figures/codac2_Figure2D.h +++ b/src/graphics/figures/codac2_Figure2D.h @@ -70,6 +70,9 @@ namespace codac2 const std::vector& axes() const; void set_axes(const FigureAxis& axis1, const FigureAxis& axis2); + const Index& i() const; + const Index& j() const; + const Vector& pos() const; const Vector& window_size() const; void set_window_properties(const Vector& pos, const Vector& size); diff --git a/src/graphics/figures/codac2_Figure2D_ellipsoid.cpp b/src/graphics/figures/codac2_Figure2D_ellipsoid.cpp deleted file mode 100644 index 4d1c8373..00000000 --- a/src/graphics/figures/codac2_Figure2D_ellipsoid.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * codac2_Figure2D.cpp - * ---------------------------------------------------------------------------- - * \date 2024 - * \author Morgan Louédec - * \copyright Copyright 2024 Codac Team - * \license GNU Lesser General Public License (LGPL) - */ - -#include "codac2_Index.h" -#include "codac2_Figure2D.h" -#include "codac2_matrices.h" -#include "codac2_Matrix.h" - -using namespace std; -using codac2::Vector; -using codac2::Matrix; - -void codac2::Figure2D::draw_ellipsoid(const codac2::Ellipsoid &e, const codac2::StyleProperties &s) { - //assert_release(this->size() <= e.size()); - for (const auto &output_fig: _output_figures) { - Matrix G_draw(2, 2); - Vector mu_draw(2); - // 2d projection of the ellipsoid - if (e.size() > 2) { - // affine space of the projection - Vector d(Eigen::VectorXd::Zero(e.mu.rows())); - Matrix T(Eigen::MatrixXd::Zero(e.G.rows(), 2)); - T(output_fig->i(), 0) = 1; - T(output_fig->j(), 1) = 1; - - // project ellipsoid E(mu,Q) = {x in R^n | (x-mu).T*G.{-T}*G^{-1}*(x-mu)<1} - // on the affine plan A = {x|x=d+Tt} [Pope -2008] - // reduce the dimensions of mu and Q - - auto TTG = T.transpose().eval() * e.G; - Eigen::BDCSVD bdcsvd(Matrix(TTG.eval()), Eigen::ComputeFullU); - Matrix U(bdcsvd.matrixU()); - Matrix E((Eigen::MatrixXd) bdcsvd.singularValues().asDiagonal()); - G_draw = U * E; - mu_draw = T.transpose() * (d + T * T.transpose() * (e.mu - d)); - } else { - G_draw = e.G; - mu_draw = e.mu; - } - - // draw the 2d ellipsoid - Eigen::JacobiSVD jsvd(G_draw, Eigen::ComputeThinU); - Matrix U(jsvd.matrixU()); - Vector ab(jsvd.singularValues()); - - double theta = atan2(U(1, 0), U(0, 0)).mid(); - - output_fig->draw_ellipse(mu_draw, ab, theta, s); - } -} \ No newline at end of file diff --git a/src/graphics/figures/codac2_OutputFigure2D.cpp b/src/graphics/figures/codac2_OutputFigure2D.cpp index 56d37b26..32afc150 100644 --- a/src/graphics/figures/codac2_OutputFigure2D.cpp +++ b/src/graphics/figures/codac2_OutputFigure2D.cpp @@ -16,10 +16,10 @@ using namespace codac2; const Index& OutputFigure2D::i() const { - return _fig.axes()[0].dim_id; + return _fig.i(); } const Index& OutputFigure2D::j() const { - return _fig.axes()[1].dim_id; + return _fig.j(); } \ No newline at end of file From 49b972d21727540c9f332610f4f8ed16ed5115ca Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Sun, 15 Dec 2024 12:22:32 +0100 Subject: [PATCH 102/102] [git.actions] removed '-j4' build option (difficulty to compile Eigen templates?) --- .github/workflows/unixmatrix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unixmatrix.yml b/.github/workflows/unixmatrix.yml index 41c66bea..e5367d6c 100644 --- a/.github/workflows/unixmatrix.yml +++ b/.github/workflows/unixmatrix.yml @@ -147,7 +147,7 @@ jobs: if [ ${{ runner.os }} = Windows ]; then source ~/refreshenv.bashrc ; refreshenv ; export PATH=$BASHMINGWPATH:$PATH ; fi mkdir build ; cd build cmake -E env CXXFLAGS="${{ matrix.cfg.cmake_flags }}" CFLAGS="${{ matrix.cfg.cmake_flags }}" cmake ${{ matrix.cfg.cmake_params }} -D CMAKE_INSTALL_PREFIX="../codac" .. - cmake --build . -j 4 --config Debug --target install + cmake --build . --config Debug --target install cd .. sed_param=s/PATH_SUFFIXES\ /PATHS\ \$\{CMAKE_CURRENT_LIST_FILE\}\\/..\\/..\\/..\\/..\\/\ PATH_SUFFIXES\ / if [ ${{ runner.os }} = Windows ]; then sed -i "$sed_param" codac/share/codac/cmake/*.cmake ; fi

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