From e3f189a03752835d287c3d48d867c0f4a92c7796 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Keck <jean-baptiste.keck@univ-grenoble-alpes.fr>
Date: Sat, 24 Sep 2022 02:48:46 +0200
Subject: [PATCH] Fix jammy docker image, improve ci scripts, fix jammy cuda
 image

---
 ci/docker_images/ubuntu/jammy/Dockerfile      | 47 ++++++++++---------
 ci/docker_images/ubuntu/jammy_cuda/Dockerfile | 46 +++++++++++-------
 ci/scripts/build_and_debug.sh                 |  2 +-
 ci/scripts/config.sh                          |  2 +-
 ci/scripts/install.sh                         |  9 ++--
 ci/scripts/test.sh                            |  6 ++-
 hysop/core/graph/computational_graph.py       |  5 +-
 hysop/core/graph/graph.py                     |  5 +-
 requirements.txt                              |  2 +-
 9 files changed, 70 insertions(+), 54 deletions(-)

diff --git a/ci/docker_images/ubuntu/jammy/Dockerfile b/ci/docker_images/ubuntu/jammy/Dockerfile
index 44c391976..0ca263707 100644
--- a/ci/docker_images/ubuntu/jammy/Dockerfile
+++ b/ci/docker_images/ubuntu/jammy/Dockerfile
@@ -21,37 +21,38 @@ MAINTAINER Jean-Baptiste.Keck@imag.fr
 # parallel builds
 ARG NTHREADS
 ENV MAKEFLAGS "-j${NTHREADS}"
+ENV PYTHON_EXECUTABLE=python3.10
 
 # upgrade initial image
 ENV DEBIAN_FRONTEND noninteractive
 RUN apt-get update && apt-get full-upgrade -y
 
 # get build tools and required libraries
-RUN apt-get update && apt-get install -y --no-install-recommends expat unzip xz-utils automake libtool pkg-config cmake rsync git vim ssh curl wget ca-certificates gcc g++ gfortran lsb-core cpio libnuma1 libpciaccess0 libreadline-dev libblas-dev liblapack-dev libgcc-11-dev libgfortran-11-dev libgmp-dev libmpfr-dev libmpc-dev python3.9-dev opencl-headers swig libgmp-dev libmpfr-dev libmpc-dev libcairo-dev libcairomm-1.0-dev python3.9-tk
+RUN apt-get update && apt-get install -y --no-install-recommends expat unzip xz-utils automake libtool pkg-config cmake rsync git vim ssh curl wget ca-certificates gcc g++ gfortran lsb-core cpio libnuma1 libpciaccess0 libreadline-dev libblas-dev liblapack-dev libgcc-11-dev libgfortran-11-dev libgmp-dev libmpfr-dev libmpc-dev ${PYTHON_EXECUTABLE}-dev opencl-headers swig libgmp-dev libmpfr-dev libmpc-dev libcairo-dev libcairomm-1.0-dev ${PYTHON_EXECUTABLE}-tk
 
 # python-pip
 RUN cd /tmp && \
  curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \
- python3.9 get-pip.py && \
- python3.9 -m pip install --upgrade pip && \
+ ${PYTHON_EXECUTABLE} get-pip.py && \
+ ${PYTHON_EXECUTABLE} -m pip install --upgrade pip && \
  rm -f /tmp/get-pip.py
 
-RUN python3.9 -m pip install --upgrade numpy==1.21.5 setuptools cffi wheel pytest pybind11 cython
+RUN ${PYTHON_EXECUTABLE} -m pip install --upgrade numpy==1.21.5 setuptools cffi wheel pytest pybind11 cython
 
 # OpenMPI 4.1.2 + mpi4py (enable mpi1 compatibility for mpi4py)
 ENV MPI_ROOT "/usr/local"
 RUN cd /tmp && \
- wget https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-4.1.2.tar.gz && \
+ wget https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-4.1.4.tar.gz && \
  tar -xvzf openmpi-*.tar.gz && \
  rm -f openmpi-*.tar.gz && \
  cd openmpi-* && \
- ./configure --enable-shared --disable-static --with-threads=posix --enable-ipv6 --prefix="${MPI_ROOT}" --with-hwloc=internal --with-libevent=internal --enable-mpi1-compatibility && \
+ ./configure --enable-shared --disable-static --enable-ipv6 --prefix="${MPI_ROOT}" --with-hwloc=internal --with-libevent=internal --enable-mpi1-compatibility && \
  make && \
  make install && \
  rm -rf /tmp/openmpi-*
 
 ENV MPICC "${MPI_ROOT}/bin/mpicc"
-RUN ldconfig && python3.9 -m pip install --upgrade mpi4py -vvv
+RUN ldconfig && ${PYTHON_EXECUTABLE} -m pip install --upgrade mpi4py -vvv
 
 # HPTT (CPU tensor permutation library)
 RUN cd /tmp && \
@@ -66,7 +67,7 @@ RUN cd /tmp && \
  make && \
  make install && \
  cd ../pythonAPI && \
- python3.9 -m pip install --upgrade . && \
+ ${PYTHON_EXECUTABLE} -m pip install --upgrade . && \
  cd /tmp && \
  rm -rf /tmp/hptt
 
@@ -80,16 +81,16 @@ RUN cd /tmp && \
  make && \
  make install && \
  rm -rf /tmp/hdf5-*
-RUN CC="${MPICC}" HDF5_MPI="ON" HDF5_VERSION="1.12.1" HDF5_DIR="${MPI_ROOT}" python3.9 -m pip install --upgrade --no-binary=h5py h5py -vvv
+RUN CC="${MPICC}" HDF5_MPI="ON" HDF5_VERSION="1.12.1" HDF5_DIR="${MPI_ROOT}" ${PYTHON_EXECUTABLE} -m pip install --upgrade --no-binary=h5py h5py -vvv
 
 # other python packages
-RUN python3.9 -m pip install --upgrade scipy sympy matplotlib gmpy2 psutil py-cpuinfo Mako editdistance portalocker colors.py tee pycairo argparse_color_formatter networkx pyvis zarr numcodecs jsonpickle memory-tempfile primefac
+RUN ${PYTHON_EXECUTABLE} -m pip install --upgrade scipy sympy matplotlib gmpy2 psutil py-cpuinfo Mako editdistance portalocker colors.py tee pycairo argparse_color_formatter networkx pyvis zarr numcodecs jsonpickle memory-tempfile primefac
 
 # llvm + numba + llvmlite (numba 0.55.1 only supports llvm 11 for now)
 RUN apt-get update && \
  apt-get install -y llvm-11-dev libclang-11-dev clang-11
 ENV LLVM_CONFIG=llvm-config-11
-RUN python3.9 -m pip install --upgrade numba llvmlite
+RUN ${PYTHON_EXECUTABLE} -m pip install --upgrade numba llvmlite
 
 # Intel experimental OpenCL platform with SYCL support
 # OclCpuExp 2021.12 and oneTBB 2021.5.0
@@ -128,10 +129,9 @@ RUN cd /tmp && \
  mv ./clinfo /bin/ && \
  rm -rf /tmp/clinfo-*
 
-# clpeak 1.1.0 RC2 (2019)
+# clpeak 1.1.2 (2022)
 RUN cd /tmp && \
- wget -O /usr/include/CL/cl.hpp https://www.khronos.org/registry/OpenCL/api/2.1/cl.hpp && \
- wget https://github.com/krrishnarraj/clpeak/archive/1.1.0.tar.gz && \
+ wget https://github.com/krrishnarraj/clpeak/archive/1.1.2.tar.gz && \
  tar -xvzf *.tar.gz && \
  rm -f *.tar.gz && \
  cd clpeak-* && \
@@ -146,11 +146,11 @@ RUN cd /tmp && \
 RUN cd /tmp && \
  git clone https://github.com/inducer/pyopencl.git && \
  cd pyopencl && \
- git checkout v2022.1 && \
+ git checkout v2022.2.3 && \
  git submodule update --init && \
- python3.9 configure.py && \
+ ${PYTHON_EXECUTABLE} configure.py && \
  make && \
- python3.9 -m pip install --upgrade . && \
+ ${PYTHON_EXECUTABLE} -m pip install --upgrade . && \
  cd - && \
  rm -rf /tmp/pyopencl
 
@@ -186,7 +186,7 @@ RUN cd /tmp && \
  git clone https://github.com/geggo/gpyfft.git && \
  cd gpyfft && \
  sed 's#finalize(self, _destroy_plan, self.plan)##' -i gpyfft/gpyfftlib.pyx && \
- python3.9 -m pip install . && \
+ ${PYTHON_EXECUTABLE} -m pip install . && \
  cd - && \
  rm -rf /tmp/gpyfft
 
@@ -211,7 +211,7 @@ RUN cd /tmp && \
   make install && \
   cd - && \
   rm -rf arb-*
-RUN python3.9 -m pip install --upgrade python-flint -vvv
+RUN ${PYTHON_EXECUTABLE} -m pip install --upgrade python-flint -vvv
 
 # static fftw + pyfftw (with R2R transforms)
 # Weird pyfftw bug : not passing -O2 explicitely during build causes a segfault on import...
@@ -233,12 +233,13 @@ RUN cd /tmp && \
 RUN cd /tmp && \
  git clone https://github.com/pyFFTW/pyFFTW && \
  cd pyFFTW && \
- STATIC_FFTW_DIR="${FFTW_ROOT}/lib" CFLAGS="-Wl,-Bsymbolic -fopenmp -I${FFTW_ROOT}/include -O2" python3.9 setup.py build_ext --inplace && \
- python3.9 -m pip install --upgrade . && \
+ STATIC_FFTW_DIR="${FFTW_ROOT}/lib" CFLAGS="-Wl,-Bsymbolic -fopenmp -I${FFTW_ROOT}/include -O2" ${PYTHON_EXECUTABLE} setup.py build_ext --inplace && \
+ ${PYTHON_EXECUTABLE} -m pip install --upgrade . && \
  rm -rf /tmp/pyFFTW
 
-RUN python3.9 -m pip install ansicolors --ignore-installed
-RUN python3.9 -m pip install numpy==1.21.5
+RUN ${PYTHON_EXECUTABLE} -m pip install ansicolors --ignore-installed
+RUN ${PYTHON_EXECUTABLE} -m pip install numpy==1.21.5
+RUN ${PYTHON_EXECUTABLE} -m pip install sympy==1.10.0
 
 # ensure all libraries are known by the runtime linker
 RUN ldconfig
diff --git a/ci/docker_images/ubuntu/jammy_cuda/Dockerfile b/ci/docker_images/ubuntu/jammy_cuda/Dockerfile
index fe862b1e3..2ee796fd1 100644
--- a/ci/docker_images/ubuntu/jammy_cuda/Dockerfile
+++ b/ci/docker_images/ubuntu/jammy_cuda/Dockerfile
@@ -21,22 +21,23 @@ MAINTAINER Jean-Baptiste.Keck@imag.fr
 # parallel builds
 ARG NTHREADS
 ENV MAKEFLAGS "-j${NTHREADS}"
+ENV PYTHON_EXECUTABLE=python3.10
 
 # upgrade initial image
 ENV DEBIAN_FRONTEND noninteractive
 RUN apt-get update && apt-get full-upgrade -y
 
 # get build tools and required libraries
-RUN apt-get update && apt-get install -y --no-install-recommends expat unzip xz-utils automake libtool pkg-config cmake rsync git vim ssh curl wget ca-certificates gcc g++ gfortran lsb-core cpio libnuma1 libpciaccess0 libreadline-dev libblas-dev liblapack-dev libgcc-11-dev libgfortran-11-dev libgmp-dev libmpfr-dev libmpc-dev python3.10-dev opencl-headers swig libgmp-dev libmpfr-dev libmpc-dev libcairo-dev libcairomm-1.0-dev python3.10-tk
+RUN apt-get update && apt-get install -y --no-install-recommends expat unzip xz-utils automake libtool pkg-config cmake rsync git vim ssh curl wget ca-certificates gcc g++ gfortran lsb-core cpio libnuma1 libpciaccess0 libreadline-dev libblas-dev liblapack-dev libgcc-11-dev libgfortran-11-dev libgmp-dev libmpfr-dev libmpc-dev ${PYTHON_EXECUTABLE}-dev opencl-headers swig libgmp-dev libmpfr-dev libmpc-dev libcairo-dev libcairomm-1.0-dev ${PYTHON_EXECUTABLE}-tk
 
 # python-pip
 RUN cd /tmp && \
  curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \
- python3.10 get-pip.py && \
- python3.10 -m pip install --upgrade pip && \
+ ${PYTHON_EXECUTABLE} get-pip.py && \
+ ${PYTHON_EXECUTABLE} -m pip install --upgrade pip && \
  rm -f /tmp/get-pip.py
 
-RUN python3.10 -m pip install --upgrade numpy==1.21.5 setuptools cffi wheel pytest pybind11 cython
+RUN ${PYTHON_EXECUTABLE} -m pip install --upgrade numpy==1.21.5 setuptools cffi wheel pytest pybind11 cython
 
 # OpenMPI 4.1.2 + mpi4py (enable mpi1 compatibility for mpi4py)
 ENV MPI_ROOT "/usr/local"
@@ -51,7 +52,7 @@ RUN cd /tmp && \
  rm -rf /tmp/openmpi-*
 
 ENV MPICC "${MPI_ROOT}/bin/mpicc"
-RUN ldconfig && python3.10 -m pip install --upgrade mpi4py -vvv
+RUN ldconfig && ${PYTHON_EXECUTABLE} -m pip install --upgrade mpi4py -vvv
 
 # HPTT (CPU tensor permutation library)
 RUN cd /tmp && \
@@ -66,7 +67,7 @@ RUN cd /tmp && \
  make && \
  make install && \
  cd ../pythonAPI && \
- python3.10 -m pip install --upgrade . && \
+ ${PYTHON_EXECUTABLE} -m pip install --upgrade . && \
  cd /tmp && \
  rm -rf /tmp/hptt
 
@@ -80,19 +81,27 @@ RUN cd /tmp && \
  make && \
  make install && \
  rm -rf /tmp/hdf5-*
-RUN CC="${MPICC}" HDF5_MPI="ON" HDF5_VERSION="1.12.1" HDF5_DIR="${MPI_ROOT}" python3.10 -m pip install --upgrade --no-binary=h5py h5py -vvv
+RUN CC="${MPICC}" HDF5_MPI="ON" HDF5_VERSION="1.12.1" HDF5_DIR="${MPI_ROOT}" ${PYTHON_EXECUTABLE} -m pip install --upgrade --no-binary=h5py h5py -vvv
 
 # other python packages
-RUN python3.10 -m pip install --upgrade scipy sympy matplotlib gmpy2 psutil py-cpuinfo Mako editdistance portalocker colors.py tee pycairo argparse_color_formatter networkx pyvis zarr numcodecs jsonpickle memory-tempfile primefac
+RUN ${PYTHON_EXECUTABLE} -m pip install --upgrade scipy sympy matplotlib gmpy2 psutil py-cpuinfo Mako editdistance portalocker colors.py tee pycairo argparse_color_formatter networkx pyvis zarr numcodecs jsonpickle memory-tempfile primefac
 
 # llvm + numba + llvmlite (numba 0.55.1 only supports llvm 11 for now)
 RUN apt-get update && \
  apt-get install -y llvm-11-dev libclang-11-dev clang-11
 ENV LLVM_CONFIG=llvm-config-11
-RUN python3.10 -m pip install --upgrade numba llvmlite
+RUN ${PYTHON_EXECUTABLE} -m pip install --upgrade numba llvmlite
+
+# Fix nvidia opencl icd loader
+ENV LIBRARY_PATH="/lib/x86_64-linux-gnu"
+RUN apt-get install -y ocl-icd-libopencl1 \
+ && rm /usr/local/cuda/targets/x86_64-linux/lib/libOpenCL.so* \
+ && ln -s /lib/x86_64-linux-gnu/libOpenCL.so.1 /lib/x86_64-linux-gnu/libOpenCL.so \
+ && ldconfig \
+ && mkdir -p /etc/OpenCL/vendors \
+ && echo "/lib/x86_64-linux-gnu/libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd
 
 # clinfo 3.0.21.02.21 (2021)
-ENV LIBRARY_PATH="/usr/local/cuda/targets/x86_64-linux/lib"
 RUN cd /tmp && \
  wget https://github.com/Oblomov/clinfo/archive/refs/tags/3.0.21.02.21.tar.gz && \
  tar -xvzf *.tar.gz && \
@@ -122,9 +131,9 @@ RUN cd /tmp && \
  cd pyopencl && \
  git checkout v2022.2.3 && \
  git submodule update --init && \
- python3.10 configure.py && \
+ ${PYTHON_EXECUTABLE} configure.py && \
  make && \
- python3.10 -m pip install --upgrade . && \
+ ${PYTHON_EXECUTABLE} -m pip install --upgrade . && \
  cd - && \
  rm -rf /tmp/pyopencl
 
@@ -160,7 +169,7 @@ RUN cd /tmp && \
  git clone https://github.com/geggo/gpyfft.git && \
  cd gpyfft && \
  sed 's#finalize(self, _destroy_plan, self.plan)##' -i gpyfft/gpyfftlib.pyx && \
- python3.10 -m pip install . && \
+ ${PYTHON_EXECUTABLE} -m pip install . && \
  cd - && \
  rm -rf /tmp/gpyfft
 
@@ -185,7 +194,7 @@ RUN cd /tmp && \
   make install && \
   cd - && \
   rm -rf arb-*
-RUN python3.10 -m pip install --upgrade python-flint -vvv
+RUN ${PYTHON_EXECUTABLE} -m pip install --upgrade python-flint -vvv
 
 # static fftw + pyfftw (with R2R transforms)
 # Weird pyfftw bug : not passing -O2 explicitely during build causes a segfault on import...
@@ -207,12 +216,13 @@ RUN cd /tmp && \
 RUN cd /tmp && \
  git clone https://github.com/pyFFTW/pyFFTW && \
  cd pyFFTW && \
- STATIC_FFTW_DIR="${FFTW_ROOT}/lib" CFLAGS="-Wl,-Bsymbolic -fopenmp -I${FFTW_ROOT}/include -O2" python3.10 setup.py build_ext --inplace && \
- python3.10 -m pip install --upgrade . && \
+ STATIC_FFTW_DIR="${FFTW_ROOT}/lib" CFLAGS="-Wl,-Bsymbolic -fopenmp -I${FFTW_ROOT}/include -O2" ${PYTHON_EXECUTABLE} setup.py build_ext --inplace && \
+ ${PYTHON_EXECUTABLE} -m pip install --upgrade . && \
  rm -rf /tmp/pyFFTW
 
-RUN python3.10 -m pip install ansicolors --ignore-installed
-RUN python3.10 -m pip install numpy==1.21.5
+RUN ${PYTHON_EXECUTABLE} -m pip install ansicolors --ignore-installed
+RUN ${PYTHON_EXECUTABLE} -m pip install numpy==1.21.5
+RUN ${PYTHON_EXECUTABLE} -m pip install sympy==1.10.0
 
 # ensure all libraries are known by the runtime linker
 RUN ldconfig
diff --git a/ci/scripts/build_and_debug.sh b/ci/scripts/build_and_debug.sh
index cb76cd3b6..ec507fb54 100755
--- a/ci/scripts/build_and_debug.sh
+++ b/ci/scripts/build_and_debug.sh
@@ -16,7 +16,7 @@
 ##
 set -feu -o pipefail
 
-PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE:-"$(which python3.9)"}
+PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE:-"$(which python3)"}
 PYTHON_INCLUDE_DIR=$(${PYTHON_EXECUTABLE} -c "import sysconfig as sc; print(sc.get_paths()['include'])")
 PYTHON_LIBRARY=$(${PYTHON_EXECUTABLE} -c "import sysconfig as sc, os; print(os.path.normpath(os.path.sep.join(sc.get_config_vars('LIBDIR', 'INSTSONAME'))))")
 
diff --git a/ci/scripts/config.sh b/ci/scripts/config.sh
index 57a33d84c..b8f7dde37 100755
--- a/ci/scripts/config.sh
+++ b/ci/scripts/config.sh
@@ -16,7 +16,7 @@
 ##
 set -feu -o pipefail
 
-PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE:-"$(which python3.9)"}
+PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE:-"$(which python3)"}
 PYTHON_INCLUDE_DIR=$(${PYTHON_EXECUTABLE} -c "import sysconfig as sc; print(sc.get_paths()['include'])")
 PYTHON_LIBRARY=$(${PYTHON_EXECUTABLE} -c "import sysconfig as sc, os; print(os.path.normpath(os.path.sep.join(sc.get_config_vars('LIBDIR', 'INSTSONAME'))))")
 
diff --git a/ci/scripts/install.sh b/ci/scripts/install.sh
index f294ddc2b..06daa6b38 100755
--- a/ci/scripts/install.sh
+++ b/ci/scripts/install.sh
@@ -16,7 +16,8 @@
 ##
 set -feu -o pipefail
 
-PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE:-"$(which python3.9)"}
+PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE:-"$(which python3)"}
+PYTHON_VERSION=$(${PYTHON_EXECUTABLE} -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
 
 if [ $# -ne 2 ]; then
     echo "Usage ./install build_folder install_folder"
@@ -39,12 +40,12 @@ INSTALL_FOLDER="$2"
 cd "${BUILD_FOLDER}"
 make install
 
-if [ ! -d "${INSTALL_FOLDER}/lib/python3.9/site-packages/hysop" ]; then
-    echo "${INSTALL_FOLDER}/lib/python3.9/site-packages/hysop was not created."
+if [ ! -d "${INSTALL_FOLDER}/lib/python${PYTHON_VERSION}/site-packages/hysop" ]; then
+    echo "${INSTALL_FOLDER}/lib/python${PYTHON_VERSION}/site-packages/hysop was not created."
     exit 1
 fi
 
-export PYTHONPATH="${INSTALL_FOLDER}/lib/python3.9/site-packages"
+export PYTHONPATH="${INSTALL_FOLDER}/lib/python${PYTHON_VERSION}/site-packages"
 "${PYTHON_EXECUTABLE}" -c 'import hysop; print(hysop)'
 
 exit 0
diff --git a/ci/scripts/test.sh b/ci/scripts/test.sh
index 1a8fec26f..621d7386b 100755
--- a/ci/scripts/test.sh
+++ b/ci/scripts/test.sh
@@ -16,7 +16,8 @@
 ##
 set -feu -o pipefail
 
-PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE:-"$(which python3.9)"}
+PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE:-"$(which python3)"}
+PYTHON_VERSION=$(${PYTHON_EXECUTABLE} -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
 
 if [ $# -lt 2 ]; then
     echo "Usage ./test install_folder hysop_folder [cache_dir] [backup_cache_dir]"
@@ -82,7 +83,7 @@ if [ "${HAS_CACHE_DIR}" = true ]; then
 fi
 
 # Environment variables
-export PYTHONPATH="${INSTALL_DIR}/lib/python3.9/site-packages:${INSTALL_DIR}"
+export PYTHONPATH="${INSTALL_DIR}/lib/python${PYTHON_VERSION}/site-packages:${INSTALL_DIR}"
 export PYTHONHASHSEED=42  # get consistent hashes accross MPI processes
 export PYOPENCL_COMPILER_OUTPUT=0
 export MPLBACKEND='cairo'
@@ -133,6 +134,7 @@ example_test() {
      echo
 }
 
+
 if [ "$RUN_TESTS" = true ]; then
     hysop_test "core/arrays/tests/test_array.py"
     hysop_test "core/graph/tests/test_graph.py"
diff --git a/hysop/core/graph/computational_graph.py b/hysop/core/graph/computational_graph.py
index fb68c2240..34c971e69 100644
--- a/hysop/core/graph/computational_graph.py
+++ b/hysop/core/graph/computational_graph.py
@@ -872,7 +872,10 @@ class ComputationalGraph(ComputationalGraphNode, metaclass=ABCMeta):
         net = self.to_pyvis()
         if (net is None):
             return
-        net.write_html(path)
+
+        html = net.generate_html()
+        with open(path, "w+") as f:
+            f.write(html)
 
     @graph_built
     def to_pyvis(self, width=None, height=None, with_custom_nodes=True):
diff --git a/hysop/core/graph/graph.py b/hysop/core/graph/graph.py
index 718fb64a5..35bbe1db0 100644
--- a/hysop/core/graph/graph.py
+++ b/hysop/core/graph/graph.py
@@ -79,9 +79,8 @@ def generate_vertex_colors():
         import matplotlib
     except ImportError:
         return None
-    from matplotlib import cm
-    c0 = cm.get_cmap('tab20c').colors
-    c1 = cm.get_cmap('tab20b').colors
+    c0 = matplotlib.colormaps['tab20c'].colors
+    c1 = matplotlib.colormaps['tab20b'].colors
     colors = []
     for i in (2, 3, 0, 1):
         colors += c0[i::4] + c1[i::4]
diff --git a/requirements.txt b/requirements.txt
index 7aad1a2cc..5bd420b40 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
 wheel
 numpy==1.21.5
+sympy==1.10.0
 scipy
-sympy
 h5py
 psutil
 py-cpuinfo
-- 
GitLab