### Clone and Install Multipers with Pip Source: https://github.com/davidlapous/multipers/blob/main/docs/compilation.rst Clones the multipers repository from GitHub and installs it using pip. ```bash git clone https://github.com/DavidLapous/multipers cd multipers pip install . ``` -------------------------------- ### Install Core Dependencies Source: https://github.com/davidlapous/multipers/blob/main/docs/compilation.rst Installs essential build dependencies including Python, GUDHI, NumPy, Boost, TBB, pytest, and others using micromamba and pip. ```bash micromamba install python=3.12 gudhi>=3.10 numpy>=2 libboost tbb pytest pot scikit-learn matplotlib joblib tqdm scipy cmake ninja -c conda-forge pip install pykeops filtration-domination --upgrade ``` -------------------------------- ### Install multipers using pip Source: https://github.com/davidlapous/multipers/blob/main/docs/index.rst Install the multipers library using pip. Ensure you have Python 3.11 or a compatible version. ```bash pip install multipers ``` -------------------------------- ### Install Additional Dependencies for External Libraries Source: https://github.com/davidlapous/multipers/blob/main/docs/compilation.rst Installs additional dependencies like LLVM OpenMP, CGAL, GMP, MPFR, Eigen, CMake, and Ninja required for building external libraries. ```bash micromamba install llvm-openmp cgal cgal-cpp gmp mpfr eigen cmake ninja -c conda-forge ``` -------------------------------- ### Install multipers pre-release using pip Source: https://github.com/davidlapous/multipers/blob/main/README.md Install pre-release versions of the multipers library using pip. These may include bug fixes or unstable new features. ```sh pip install --pre multipers ``` -------------------------------- ### Install multipers dependencies using conda Source: https://github.com/davidlapous/multipers/blob/main/docs/index.rst Set up a conda environment with Python 3.11 and install necessary dependencies including numpy, matplotlib, gudhi, scikit-learn, scipy, tqdm, and shapely. ```bash conda create -n python311 conda activate python311 conda install python=3.11 numpy matplotlib gudhi scikit-learn scipy tqdm shapely -c conda-forge pip install filtration-domination pykeops --upgrade ``` -------------------------------- ### Example Zoo Toctree Directive Source: https://github.com/davidlapous/multipers/blob/main/docs/contributions.rst This reStructuredText directive is used to include examples in the documentation's example zoo. ```rst .. toctree:: :caption: Example zoo: ``` -------------------------------- ### Install C++ Compiler Source: https://github.com/davidlapous/multipers/blob/main/docs/compilation.rst Installs a C++ compiler toolchain within the conda environment, necessary for building native extensions. ```bash micromamba install cxx-compiler -c conda-forge ``` -------------------------------- ### Install multipers using conda Source: https://github.com/davidlapous/multipers/blob/main/README.md Install the multipers library using conda from the conda-forge channel. This is recommended for users who prefer the conda package manager. ```sh conda install multipers -c conda-forge ``` -------------------------------- ### Get and Plot Representative Cycles Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/representative_cycles.ipynb Retrieves the representative cycles for the identified nontrivial cycles and plots them on top of the density-colored point cloud. ```python cycles = s.get_representative_cycles()[1] # cycles = [cycles[i] for i in idx] plt.scatter(*X.T, c=1-density, cmap="viridis_r") plt.colorbar() for cycle in cycles: cycle = np.array(cycle) B = X[cycle[:,0]] D = X[cycle[:,1]] # plt.scatter(X[:,0],X[:,1], c=density) for (a,b) in zip(B,D): plt.plot([a[0],b[0]],[a[1],b[1]], c="r") ``` -------------------------------- ### Set up data loader and training parameters Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Configures the number of training epochs and batch size, then creates a `DataLoader` for the training dataset. ```python num_epoch = 100 batch_size = len(train_dataset) data_loader = DataLoader(train_dataset,batch_size=batch_size) ``` -------------------------------- ### Instantiate and display GraphModel Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Instantiates the `GraphModel` with specified parameters and displays the model architecture. The `_stuff` variable is assumed to be pre-loaded training data. ```python _stuff = train graphclassifier = GraphModel( in_channels = _stuff.x.shape[1], out_channels = np.unique(_stuff.y).shape[0], hidden_channels=10, num_layers=2, num_parameters=2, num_convolutions=2, resolution=10, ) graphclassifier ``` -------------------------------- ### Initialize and visualize an optimized point cloud Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/rips_density_autodiff.ipynb Creates a uniform random point cloud and visualizes it using the custom measure's density. The points are initialized with requires_grad=True for optimization. ```python x = np.random.uniform(size=(500,2)) x = torch.tensor(x, requires_grad=True) plt.scatter(*x.detach().numpy().T, c=custom_map(x).detach().numpy(), cmap="viridis_r") plt.colorbar() ``` -------------------------------- ### Create DataLoaders and Split Dataset Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Sets up a DataLoader for the dataset and splits it into training and testing sets. The dataset is shuffled before splitting to ensure randomness. ```python from torch_geometric.loader import DataLoader from sklearn.model_selection import train_test_split batch_size=len(dataset) # batch_size=100 shuffled_dataset = dataset.shuffle() dataset_size = len(dataset) split = int(0.9*dataset_size) train_dataset, test_dataset = dataset[:split], shuffled_dataset[split:] ``` -------------------------------- ### SimplexTreeMulti Initialization and Insertion Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Demonstrates the creation of a SimplexTreeMulti object and insertion of simplex data. This is useful for understanding the basic structure and data handling of SimplexTreeMulti before complex graph transformations. ```python st = mp.SimplexTreeMulti() st.insert_batch(np.array([0])[:,None],np.array([[1,1]])) st.insert_batch(np.array([0,1])[:,None],np.empty((0,0))) list(st) ``` -------------------------------- ### Instantiate SMConvLayer Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Instantiates the SMConvLayer with specified parameters. Ensure that `first_gcn.out_channels`, `topological_layer.degrees`, and `sms.dtype` are defined prior to execution. ```python vectorization_layer = SMConvLayer(num_parameters=first_gcn.out_channels, num_axis=len(topological_layer.degrees), dtype = sms.dtype, num_convolutions = 7, resolution = 5, out_channels=10) ``` -------------------------------- ### Define and Prepare Persistence Modules Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/ops/AIDA.ipynb Defines two persistence modules with different structures and prepares them for analysis using the Slicer and colexical ordering. ```python presentation1 = [[],[],[],[0,1],[0],[1],[2],[2],] dimension1 = [0,0,0,1,1,1,1,1] filtration_values1 = [[1,0],[0,1],[1,1],[1,1],[3,0],[0,3],[2,1],[1,2]] presentation2 = [[],[],[0],[1],[0,1], [0,1]] dimension2 = [0,0,1,1,1,1] filtration_values2 = [[1,0],[0,1],[3,0],[0,3],[2,1], [1,2]] s1 = mp.Slicer(return_type_only=True, vineyard=True)( presentation1, dimension1, filtration_values1 ).minpres(0).to_colexical() s2 = mp.Slicer(return_type_only=True, vineyard=True)( presentation2, dimension2, filtration_values2 ).minpres(0).to_colexical() ``` -------------------------------- ### Create Slicer and Get Length Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/degree_rips_interface.ipynb Creates a Slicer object from a simplextree and retrieves its size. ```python s = mp.Slicer(st_dim2) # mp.signed_measure(s, degree=1, plot=True) len(s) ``` -------------------------------- ### Build Documentation Script Source: https://github.com/davidlapous/multipers/blob/main/docs/contributions.rst This shell script builds the documentation for the multipers project using Sphinx. ```sh sh build_doc.sh ``` -------------------------------- ### Expand and Get Length of DegreeRips Filtration Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/degree_rips_interface.ipynb Expands a DegreeRips filtration to dimension 2 and retrieves its size. ```python st_dim2 = st.copy() st_dim2.expansion(2) len(st_dim2) ``` -------------------------------- ### Initialize Git Submodules Source: https://github.com/davidlapous/multipers/blob/main/docs/compilation.rst Initializes and updates all git submodules located under the ext/ directory, which are required for external libraries. ```bash git submodule update --init --recursive ``` -------------------------------- ### Include Custom CMake Modules Source: https://github.com/davidlapous/multipers/blob/main/CMakeLists.txt Includes several custom CMake modules for managing project dependencies, code generation, build processes, and installation. ```cmake include("${CMAKE_SOURCE_DIR}/cmake/MultipersDependencies.cmake") include("${CMAKE_SOURCE_DIR}/cmake/MultipersCodegen.cmake") include("${CMAKE_SOURCE_DIR}/cmake/MultipersBuild.cmake") include("${CMAKE_SOURCE_DIR}/cmake/MultipersInstall.cmake") ``` -------------------------------- ### Sample Point Cloud Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/delaunay_core_bifiltration.ipynb Generates a noisy point cloud dataset from three annuli with added outliers. Visualizes the generated point cloud. ```python num_pts = 1000 num_outliers = 1000 X = three_annulus(num_pts, num_outliers) fig, ax = plt.subplots(1, 1, figsize=(5, 5)) ax.scatter(*X.T, s=5, alpha=0.7) ax.set_aspect(1) plt.show() ``` -------------------------------- ### Get Maximum Degree of a Graph Dataset Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Calculates the maximum degree of nodes in a specified TUDataset. This function is used to determine the `max_degree` parameter for certain transformations. ```python def get_max_degree(dataset_name): from torch_geometric.utils import degree dataset = TUDataset(expanduser("~/Datasets/torch_geometric/"),dataset_name, use_node_attr=True,cleaned=True) num_nodes = dataset.edge_index.max()+1 # only this matters, we're computing max_degree assert not Data(edge_index=dataset.edge_index, num_nodes = num_nodes).is_directed() a= degree(index = dataset.edge_index[0]) b = degree(index = dataset.edge_index[1]) assert (a==b).all() # because is_directed I guess max_degree = a.max() return int(max_degree) ``` -------------------------------- ### Plot Module Approximations Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/ops/AIDA.ipynb Visualizes the module approximations for the two prepared persistence modules. ```python fig, (a,b) = plt.subplots(ncols=2, figsize=(10,4)) box=[[0,0],[4,4]] plt.sca(a) mp.module_approximation(s1, box=box).plot(0) plt.sca(b) mp.module_approximation(s2, box=box).plot(0) ``` -------------------------------- ### Convert Gudhi SimplexTree to SimplexTreeMulti Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/simplex_tree_by_hand.ipynb Converts an existing gudhi.SimplexTree object into a multipers.SimplexTreeMulti with a specified number of parameters. This is useful when starting with data already processed by gudhi. ```python st = gd.SimplexTree() st.insert([0,1],1) st.insert([1],0) # converts the simplextree into a multiparameter simplextree st_multi = mp.SimplexTreeMulti(st, num_parameters=2) list(st_multi) ``` -------------------------------- ### Plot Initial Module Approximation Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/time_series_classification.ipynb Visualizes the first module approximation generated from the simplextrees. ```python mods[0][0].plot() ``` -------------------------------- ### Generate a noisy annulus dataset Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/rhomboid_bifiltration.ipynb Creates a 2D dataset shaped like a noisy annulus using multipers.data.noisy_annulus. This is a common starting point for testing filtration algorithms. ```python np.random.seed(0) x = mp.data.noisy_annulus(200,0, dim=2) # dataset plt.scatter(*x.T) k_max = 50 # the maximum of ball intersection to look at degree=1 # homological degree ``` -------------------------------- ### Initialize and Optimize Point Cloud with DelaunayLowerstar Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/rips_density_autodiff.ipynb Initializes a point cloud, sets up an Adam optimizer, and performs gradient steps to optimize the point cloud based on signed measures from a DelaunayLowerstar filtration. The `flagify=True` option is used to weaken the Delaunay complex for better differentiability. Plots are generated at intervals to visualize the process. ```python from multipers.filtrations import DelaunayLowerstar xinit = np.random.uniform(size=(500,2)) # initial dataset x = torch.tensor(xinit, requires_grad=True) adam = torch.optim.Adam([x], lr=0.01) #optimizer losses = [] plt.scatter(*x.detach().numpy().T, c=custom_map(x, threshold=np.inf).detach().numpy(), cmap="viridis_r") plt.show() for i in range(101): # gradient steps # Little caveat of Delaunay, they are hard to differentiate. # We hence weaken the delaunay complex into a flag complex, which is easier to differentiate, # with the `flagify=True` flag. st = DelaunayLowerstar(points=x, function=custom_map(x), flagify=True) sm_diff, = mp.signed_measure(st, degree=1) # Rips version # st = RipsLowerstar(points=x,function=custom_map(x)) # st.collapse_edges(-1) # st.expansion(2) # sm_diff, = mp.signed_measure(st, degree=1) adam.zero_grad() loss = loss_function(x,sm_diff) loss.backward() adam.step() losses.append([loss.detach().numpy()]) with torch.no_grad(): if i %10 == 1: #plot part base=4 ncols=3 fig, (ax1, ax2, ax3) = plt.subplots(nrows=1, ncols=ncols, figsize=(ncols*base, base)) ax1.scatter(*x.detach().numpy().T, c=custom_map(x, threshold=np.inf).detach().numpy(), cmap="viridis_r", ) plot_signed_measure(sm_diff, ax=ax2) ax3.plot(losses, label="loss") plt.show() fig, (ax1, ax2, ax3) = plt.subplots(nrows=1, ncols=ncols, figsize=(ncols*base, base)) ax1.scatter(*xinit.T, c=custom_map(torch.tensor(xinit)).detach().numpy(),cmap="viridis_r") ax2.scatter(*x.detach().numpy().T, c=custom_map(x).detach().numpy(),cmap="viridis_r") ax3.plot(losses) plt.show() ``` -------------------------------- ### Build mpfree Standalone Binary Source: https://github.com/davidlapous/multipers/blob/main/docs/compilation.rst Builds the mpfree standalone binary from its source in ext/mpfree using CMake and Ninja, then copies the executable to the conda bin directory. ```bash cd ext/mpfree cmake -S . -B build -G Ninja cmake --build build --parallel cp build/mpfree $CONDA_PREFIX/bin/ cd .. ``` -------------------------------- ### Initialize SimplexTreeMulti from Point Cloud Data Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/simplex_tree_by_hand.ipynb Constructs a multipers.SimplexTreeMulti from a point cloud dataset. It first creates a Rips complex using gudhi and then converts it to a SimplexTreeMulti, initializing the first parameter with the Rips filtration. ```python # Dataset from multipers.data import noisy_annulus X = noisy_annulus(n1=200, n2=200) # 1000 points on the annulus, 500 points on the square. plt.scatter(X[:,0], X[:,1], s=5, c='k');plt.gca().set_aspect(1); # Gudhi SimplexTree st = gd.RipsComplex(points=X, sparse=.2).create_simplex_tree() # SimplexTreeMulti, with 2 parameters st = mp.SimplexTreeMulti(st, num_parameters=2) ``` -------------------------------- ### Define Dataset Path and List Files Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/immuno_img.ipynb Sets the path to the dataset and lists the CSV files available in the specified directory. Ensure the 'Datasets' directory exists and contains the expected files. ```python from pathlib import Path DATASET_PATH=Path("~/Datasets/").expanduser() !ls {DATASET_PATH}/LargeHypoxicRegion* ``` -------------------------------- ### Initialize and Manipulate SimplexTreeMulti Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/simplex_tree_by_hand.ipynb Initializes a SimplexTreeMulti object and demonstrates inserting, removing, and listing simplices. Ensure multipers and numpy are imported. ```python st = mp.SimplexTreeMulti(num_parameters=2, kcritical=True, dtype = np.float64) st.insert([0,1,2], [0,1]) st.insert([0,1,2], [1,0]) st.remove_maximal_simplex([0,1,2]) st.insert([0,1,2], [1,2]) st.insert([0,1,2], [2,1]) st.insert([0,1,2],[1.5,1.5]) st.insert([0,1,2], [2.5,.5]) st.insert([0,1,2], [.5,2.5]) list(st) ``` -------------------------------- ### Import necessary libraries Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/rips_density_autodiff.ipynb Imports the required libraries for the notebook, including multipers, gudhi, numpy, matplotlib, and torch. It also sets random seeds for reproducibility. ```python import multipers as mp from multipers.data import noisy_annulus, three_annulus import gudhi as gd import numpy as np import matplotlib.pyplot as plt import torch # t.autograd.set_detect_anomaly(True) from multipers.plots import plot_signed_measures, plot_signed_measure from tqdm import tqdm torch.manual_seed(1) np.random.seed(1) ``` -------------------------------- ### Import necessary libraries Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Imports the `one_hot` function from `torch.nn.functional` and `tqdm` for progress bars. ```python from torch.nn.functional import one_hot from tqdm import tqdm ``` -------------------------------- ### Expand and Prune Simplextree Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/degree_rips_interface.ipynb Demonstrates expanding a simplextree to higher dimensions and then pruning it back to a specific dimension. ```python print(len(st_multi)) st_multi.expansion(2) print(len(st_multi)) st_multi.prune_above_dimension(1) print(len(st_multi)) ``` -------------------------------- ### Import Libraries and Load Data Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/delaunay_core_bifiltration.ipynb Imports necessary libraries and loads the three_annulus dataset for point cloud analysis. Sets random seed for reproducibility. ```python import multipers as mp import matplotlib.pyplot as plt import numpy as np from multipers.data import three_annulus from multipers.filtrations import CoreDelaunay np.random.seed(0) ``` -------------------------------- ### Build function_delaunay Standalone Binary Source: https://github.com/davidlapous/multipers/blob/main/docs/compilation.rst Configures and builds the function_delaunay standalone binary. It modifies CMakeLists.txt to include Eigen3, then builds using CMake and Ninja, and finally copies the executable. ```bash cd function_delaunay sed -i "8i find_package(Eigen3 3.3 REQUIRED NO_MODULE)\nlink_libraries(Eigen3::Eigen)\n" CMakeLists.txt cmake -S . -B build -G Ninja cmake --build build --parallel cp build/main $CONDA_PREFIX/bin/function_delaunay cd .. ``` -------------------------------- ### Create and Squeeze Simplex Tree Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/invariants/birth_curves.ipynb Initializes a SimplexTreeMulti for two parameters and inserts simplices with associated filtration values. It then defines a grid and uses Slicer to squeeze the simplex tree onto this grid. ```python st = mp.SimplexTreeMulti(num_parameters=2) st.insert([0], [0.0, 0.0]) st.insert([1], [1.0, 0.0]) st.insert([2], [0.0, 1.0]) st.insert([0, 1], [1.0, 1.0]) st.insert([0, 2], [1.0, 1.0]) grid = (np.array([0.0, 1.0, 2.0]), np.array([0.0, 1.0, 2.0])) slicer = mp.Slicer(st, dtype=np.float64).grid_squeeze(grid) ``` -------------------------------- ### Plotting a Point Cloud with Density and Module Approximation Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/plots.ipynb Visualizes a point cloud with density information and a module approximation using plot_point_cloud. Requires multipers.plots and matplotlib. ```python from multipers.plots import plot_point_cloud radius = .25 codens = 2.85 plot_point_cloud(X, codensity,radius,codens, mma=mma,degree=1) plt.gcf().set_size_inches(9, 4) ``` -------------------------------- ### Compute and Visualize Data Density using KDE Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/multipers_intro.ipynb Calculates the data density using Kernel Density Estimation (KDE) and visualizes the points colored by their density. This step is crucial for identifying noise points. ```python from multipers.filtrations.density import KDE density = KDE(bandwidth=0.2).fit(X).score_samples(X) # a bit of renormalization density -= density.min() density /= density.max() plt.scatter(X[:,0], X[:,1], s=5, c=density, cmap="plasma") plt.gca().set_aspect(1); plt.colorbar(); ``` -------------------------------- ### Build Multipers with CMake and Ninja Source: https://github.com/davidlapous/multipers/blob/main/docs/compilation.rst Configures the build using CMake with the Ninja generator, sets the build type to Release, and enables export of compile commands. Builds the project in parallel and copies compile_commands.json. ```bash cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON cmake --build build --parallel # this may take some time cp build/compile_commands.json ./compile_commands.json pip install --no-build-isolation . ``` -------------------------------- ### Instantiate Graph2SMLayer Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Creates an instance of the Graph2SMLayer with specific normalization and degree settings. Use this to initialize the layer for processing graph data. ```python topological_layer = Graph2SMLayer(normalize = True, degrees=[0,1], n_jobs=1) ``` -------------------------------- ### Approximate Module with Vineyard Backend Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/immuno_img.ipynb Approximates a module using the Slicer with a vineyard backend and minimal presentation. Requires the 'matrix' backend for vineyard. ```python ## module_approximation needs a vineyard backend _s = mp.Slicer(cubical, backend="matrix", vineyard=True).minpres(degrees=[0,1]) mod = mp.module_approximation(_s) mod.plot(alpha =.8) ``` -------------------------------- ### Compute Minimal Presentation Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/multipers_intro.ipynb Computes the minimal presentation of degree 1 from the Density-Delaunay bifiltration using mpfree. The result is converted to colexical order for potential optimizations. ```python minimal_presentation = mp.Slicer(function_delaunay).minpres(degree=1).to_colexical() ## needs mpfree # Note. These two steps can be done faster by providing the degree to function_delaunay ``` -------------------------------- ### Generate and visualize point clouds Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/distances/matching_distance.ipynb Creates two distinct point clouds using make_blobs with different spread parameters and visualizes them using matplotlib. ```python np.random.seed(0) centers = [(-1.0, 0.0), (1.0, 0.0), (0.0, 1.4)] X = np.asarray(make_blobs(n_samples=1000, centers=centers, cluster_std=0.2, random_state=0)[0]) Y = np.asarray(make_blobs(n_samples=1000, centers=centers, cluster_std=0.3, random_state=1)[0]) fig, (a, b) = plt.subplots(1, 2, figsize=(9, 4)) a.scatter(*X.T) a.set_aspect(1) a.set_title("compact blobs") b.scatter(*Y.T) b.set_aspect(1) b.set_title("diffuse blobs") plt.show() ``` -------------------------------- ### Optimize Point Cloud with Rips Density and Autodiff Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/rips_density_autodiff.ipynb This snippet sets up an optimization loop using PyTorch's Adam optimizer to adjust a point cloud 'x' based on the Rips density's signed measure. It visualizes the loss and the point cloud's evolution during optimization. ```python x = torch.from_numpy(X).clone().requires_grad_(True) opt = torch.optim.Adam([x], lr=.01) losses = [] for i in range(100): opt.zero_grad() st = DelaunayLowerstar(points=x, function=custom_map(x), flagify=True) sm_diff, = mp.signed_measure(st, degree=1) loss = norm_loss(sm_diff) loss.backward() losses.append(loss) opt.step() if i % 10 == 0: with torch.no_grad(): base=4 ncols=3 fig, (ax1, ax2, ax3) = plt.subplots(nrows=1, ncols=ncols, figsize=(ncols*base, base)) ax1.scatter(*x.detach().numpy().T, c=custom_map2(x).detach().numpy(), cmap="viridis_r", ) plot_signed_measure(sm_diff, ax=ax2) ax3.plot(losses, label="loss") plt.show() ``` -------------------------------- ### Initialize GCN Model Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Initializes a GCN model with specified input channels, hidden channels, number of layers, and output channels. The `out_channels` is kept low for multiparameter persistence computation. ```python out_channels1 = 3 ## Note: this is the number of parameter on which to compute Multiparameter Persistence; keep it low! first_gcn = GCN(in_channels=train.x.shape[-1], hidden_channels=50, num_layers=5, out_channels=out_channels1) ``` -------------------------------- ### Load Graph Dataset Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/graph_classification.ipynb Loads the BZR graph dataset and lists its files. Assumes the dataset is in the specified path, which can be modified if necessary. ```python import multipers.data.graphs as mdg import multipers.ml.signed_measures as mms import networkx as nx from random import choice from os.path import expanduser import numpy as np np.random.seed(1) dataset = "graphs/MUTAG" path = mdg.DATASET_PATH+dataset !ls $path ## We assume that the dataset is in this folder. You can modify the variable `mdg.DATASET_PATH` if necessary ``` -------------------------------- ### Construct DegreeRips Filtration Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/degree_rips_interface.ipynb Constructs a DegreeRips filtration from point cloud data. The 'collapse' option applies filtration-domination preprocessing. ```python degrees = np.arange(500, dtype=int) # The associated DegreeRips filtration can be encoded in a (multicritical) simplextree. st_multi = mp.filtrations.DegreeRips(points = X, ks=degrees,threshold_radius=1.5, collapse=5) ``` -------------------------------- ### Compute and Plot Birth Curves Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/invariants/birth_curves.ipynb Computes the birth curves of the minimal presentation using mpi.birth_curves and plots them. It also re-plots the minimal presentation for visual reference. ```python mpi.birth_curves(minpres, plot=True) mp.plots.plot_presentation(minpres) ``` -------------------------------- ### Placeholder for Betti Table Calculation Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/invariants/betti_table.ipynb This is a placeholder for code that would calculate the Betti table. It is currently marked as TODO and does not contain functional code. ```python # TODO ``` -------------------------------- ### Fill Second Parameter with Co-Log-Density Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/simplex_tree_by_hand.ipynb Fills the second parameter of a SimplexTreeMulti with co-log-density values derived from the point cloud data using Kernel Density Estimation. This requires importing KernelDensity and fitting it to the data. ```python from multipers.filtrations.density import KDE as KernelDensity codensity = - KernelDensity(bandwidth=0.2).fit(X).score_samples(X) # parameter = 1 is the second parameter as python starts with 0. st.fill_lowerstar(codensity, parameter=1) # This fills the second parameter with the co-log-density ``` -------------------------------- ### Compute Minimal Presentation Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/representative_cycles.ipynb Creates a slicer from the simplicial complex with `vineyard=True` and computes the minimal presentation for dimension 1, keeping generators. ```python # [Minimal presentation](ops/minimal_presentations_resolutions.ipynb)'s change of basis needs to be recovered. # That's `keep_generators=True`, it needs `vineyard=True` s = mp.Slicer(simplextree, vineyard=True).minpres(1,keep_generators=True) ``` -------------------------------- ### Density Estimation and Grid Computation Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/immuno_img.ipynb Computes a grid and performs Kernel Density Estimation (KDE) for specified cell types to create image-like representations. This step requires the 'multipers' library and may default to CPU if CUDA is unavailable. ```python from multipers.filtrations.density import KDE ## to provide plots, we only consider 2 parameters. ## The rest of the code should still work without this constraint _labels = [0,2] # np.unique(labels) resolution=100 grid = mp.grids.compute_grid(np.asarray([[0,1.]]*X.shape[1]), strategy="regular", resolution=resolution) grid = mp.grids.todense(grid) densities = np.concatenate([KDE(bandwidth=.01, return_log=True).fit((x:=X[labels==idx])).score_samples(grid).reshape(*[resolution]*X.shape[1],1) for idx in _labels], axis=-1) ``` -------------------------------- ### Create Cubical Filtration from Densities Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/immuno_img.ipynb Constructs a Cubical filtration directly from image densities. Higher densities are prioritized by negating the input. ```python from multipers.filtrations import Cubical cubical = Cubical(-densities) ## higher densities appear first cubical ``` -------------------------------- ### Plotting a Noisy Annulus Point Cloud with Density Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/plots.ipynb Generates a noisy annulus point cloud and visualizes it using Kernel Density Estimation (KDE) to color points by their estimated density. Requires numpy and matplotlib. ```python import numpy as np import matplotlib.pyplot as plt from multipers.filtrations.density import KDE np.random.seed(1) X = noisy_annulus(n1=200, n2=200) codensity = - (KDE(bandwidth=0.2, return_log=True).fit(X).score_samples(X)) plt.scatter(X[:,0], X[:,1], s=20, c=-codensity); plt.gca().set_aspect(1); ``` -------------------------------- ### Compute Module Approximation Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/degree_rips_interface.ipynb Computes a module approximation from a minimal presentation, with options for verbose output and coordinate-based initialization. ```python mod = mp.module_approximation(d1, verbose=True, from_coordinates=True) mod.plot() ``` -------------------------------- ### Import Classifier and Pipeline Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/time_series_classification.ipynb Imports the Random Forest Classifier and Pipeline utilities from scikit-learn for building the classification model. ```python from sklearn.ensemble import RandomForestClassifier from sklearn.pipeline import Pipeline ``` -------------------------------- ### Create a DataLoader Batch Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Creates a single batch from the entire dataset using a DataLoader. This batch is used as input for the GCN model. ```python train = next(iter(DataLoader(dataset, batch_size=len(dataset)))) ``` -------------------------------- ### Build Delaunay core bifiltrations Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/distances/matching_distance.ipynb Constructs Delaunay core bifiltrations for two point clouds using specified parameters. This step is crucial for subsequent distance calculations. ```python ks = np.unique(np.linspace(1, min(len(X), len(Y)) // 2, num=200, dtype=int)).tolist() beta = 0.5 left = mp.filtrations.CoreDelaunay( points=X, beta=beta, ks=ks, ) right = mp.filtrations.CoreDelaunay( points=Y, beta=beta, ks=ks, ) ``` -------------------------------- ### Generate and Visualize Three Annulus Dataset Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/multipers_intro.ipynb Generates a synthetic three annulus dataset and visualizes it using kernel density estimation to highlight data concentration. ```python from multipers.data.synthetic import three_annulus X = three_annulus(25_000,25_000) density = KDE(bandwidth=0.15, return_log=True).fit(X).score_samples(X) plt.scatter(*X.T, c = -density, cmap="viridis_r") plt.gca().set_aspect(1); plt.colorbar() plt.title(f"Three annulus dataset (size {X.shape[0]})") ``` -------------------------------- ### Visualize Training Time Series Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/time_series_classification.ipynb Plots all training time series to visualize their patterns. ```python ## the time-series of the Coffee dataset plt.plot(xtrain.T, alpha=.2); ``` -------------------------------- ### Load and Preprocess Time Series Data Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/time_series_classification.ipynb Loads training and testing data for the Coffee dataset from TSV files and preprocesses labels. ```python DATASET_PATH=expanduser("~/Datasets/UCR/") dataset_path = DATASET_PATH + "Coffee/Coffee" xtrain = np.array(pd.read_csv(dataset_path+"_TRAIN.tsv", delimiter='\t', header=None, index_col=None, engine='python')) ytrain = LabelEncoder().fit_transform(xtrain[:,0]) xtrain = xtrain[:,1:] xtest = np.array(pd.read_csv(dataset_path + "_TEST.tsv", delimiter='\t', header=None, index_col=None, engine='python')) ytest = LabelEncoder().fit_transform(xtest[:,0]) xtest = xtest[:,1:] ``` -------------------------------- ### Initialize DelaunayLowerstar Filtration Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/representative_cycles.ipynb Initializes a DelaunayLowerstar filtration using the points and the computed density function. `recover_ids=True` ensures that point indices are preserved. ```python from multipers.filtrations import RipsLowerstar,DelaunayLowerstar # Rips # simplextree = RipsLowerstar(points=X, function = 1-density, threshold_radius=1.5) # this is a simplicial complex # Delaunay # Recover id, recover the points id in the simplextree. The indices may be reordered otherwise. simplextree = DelaunayLowerstar(points=X, function = 1-density, recover_ids=True) ``` -------------------------------- ### Generate Module Approximations Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/time_series_classification.ipynb Computes module approximations for each generated simplextree using the MMA (Module-Approximation) method. ```python import multipers.ml.mma as mma mods = mma.FilteredComplex2MMA().fit_transform(sts) ``` -------------------------------- ### Generate Point Cloud with KDE Codensity Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/rips_density_autodiff.ipynb Generates a point cloud by combining uniform noise and points from a noisy annulus. It then computes the codensity using Kernel Density Estimation (KDE) with a specified bandwidth and visualizes the points colored by their codensity. ```python from multipers.filtrations.density import KDE X = np.block([ [np.random.uniform(low=-0.1,high=.2,size=(100,2))], [mp.data.noisy_annulus(300,0, 0.85,1)] ]) bandwidth = .1 custom_map2 = lambda X : -KDE(bandwidth=bandwidth, return_log=True).fit(X).score_samples(X) codensity = custom_map2(X) plt.scatter(*X.T, c=-codensity) plt.gca().set_aspect(1) ``` -------------------------------- ### Creating a RipsLowerstar Simplicial Complex Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/plots.ipynb Constructs a RipsLowerstar simplicial complex from a point cloud and a density function. The collapse_edges and expansion methods are used to simplify the complex. Requires multipers. ```python from multipers.filtrations import RipsLowerstar st = RipsLowerstar(points=X, function=codensity).collapse_edges(-2).expansion(2) ``` -------------------------------- ### Density Estimation using KDE Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/representative_cycles.ipynb Applies Kernel Density Estimation (KDE) to the dataset to obtain density values, which are then normalized. This density can be used as a function for filtration. ```python from multipers.filtrations.density import KDE density = KDE(bandwidth=0.1, return_log=True).fit(X).score_samples(X) # a bit of renormalization density -= density.min() density /= density.max() # p = np.argsort(-density) # X=X[p] # density = density[p] plt.scatter(X[:,0], X[:,1], s=5, c=density, cmap="plasma") plt.gca().set_aspect(1); plt.colorbar(); ``` -------------------------------- ### Import Libraries Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/graph_autodiff.ipynb Imports necessary libraries for PyTorch, PyTorch Geometric, and multipers, including transforms and dataset utilities. Sets a manual seed for reproducibility and suppresses warnings. ```python import torch import torch_geometric.transforms as T import multipers as mp from torch_geometric.datasets import TUDataset from os.path import expanduser from torch_geometric.data import Data import torch.nn as nn import numpy as np import multipers.ml.signed_measures as mms import multipers.grids as mpg torch.manual_seed(1) ## TODO : fixme import warnings warnings.filterwarnings("ignore") ``` -------------------------------- ### Creating a DelaunayLowerstar Simplicial Complex and Module Approximation Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/plots.ipynb Constructs a DelaunayLowerstar simplicial complex and computes its module approximation. Requires multipers. ```python from multipers.filtrations import DelaunayLowerstar st_delaunay = DelaunayLowerstar(points = X, function=codensity) mma = mp.module_approximation(st_delaunay) ``` -------------------------------- ### Build with macOS CXXFLAGS Source: https://github.com/davidlapous/multipers/blob/main/docs/compilation.rst Configures and builds multipers with specific CXXFLAGS and CFLAGS to avoid compilation issues on older macOS versions related to the 'aligned-new' optimization. ```bash CXXFLAGS="-fno-aligned-new" CFLAGS="-fno-aligned-new" cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release cmake --build build --parallel ``` -------------------------------- ### Create RipsLowerstar Filtration from Density Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/rips.ipynb Computes a filtration based on Kernel Density Estimation (KDE) applied to the point data. The negative log-likelihood is used as the function, and a RipsLowerstar complex is constructed. Optimizations are applied. ```python from multipers.filtrations.density import KDE f= - KDE(bandwidth=.2, return_log=True).fit(X).score_samples(X) # minus to reverse the order. plt.scatter(*X.T, c=f, cmap="viridis_r") plt.gca().set_aspect(1) st = mpf.RipsLowerstar(points=X, function=f).collapse_edges(-1).expansion(2) # Same trick as previously ``` -------------------------------- ### Set C++ Standard and Compiler Options Source: https://github.com/davidlapous/multipers/blob/main/CMakeLists.txt Configures the C++ standard to C++20 and enables position-independent code and export compile commands. Also enables color diagnostics for compilers. ```cmake set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_COLOR_DIAGNOSTICS ON) ``` -------------------------------- ### Visualize Optimized vs Original Point Cloud Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/differentiability/rips_density_autodiff.ipynb This snippet visualizes the original point cloud 'X' and the optimized point cloud 'x' after the optimization loop has completed. It also plots the final loss curve. ```python with torch.no_grad(): fig, (ax1, ax2, ax3) = plt.subplots(nrows=1, ncols=ncols, figsize=(ncols*base, base)) ax1.scatter(*X.T, c=custom_map2(torch.tensor(X)).detach().numpy(),cmap="viridis_r") ax2.scatter(*x.detach().numpy().T, c=custom_map2(x).detach().numpy(),cmap="viridis_r") ax3.plot(losses) plt.show() ``` -------------------------------- ### Verify Indecomposable Module Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/ops/AIDA.ipynb Confirms that the second module is indecomposable by applying AIDA and comparing the result to the original module. ```python indec, = mp.ops.aida(s2) # the indecomposable s2.prune_above_dimension(1).to_colexical() == indec.to_colexical() ``` -------------------------------- ### Plotting a Point Cloud with Different Parameters Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/plots.ipynb Visualizes a point cloud with density information and a module approximation using plot_point_cloud with different radius and codensity. Requires multipers.plots and matplotlib. ```python from multipers.plots import plot_point_cloud radius = .6 codens = 2.85 plot_point_cloud(X, codensity,radius,codens, mma=mma,degree=1) plt.gcf().set_size_inches(9, 4) ``` -------------------------------- ### Import Libraries Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/ops/AIDA.ipynb Imports necessary libraries for numerical operations, AIDA, plotting, and data handling. ```python import numpy as np from multipers.ops import aida import matplotlib.pyplot as plt import multipers as mp import os from os.path import expanduser from pandas import read_csv from sklearn.preprocessing import LabelEncoder from tqdm import tqdm ``` -------------------------------- ### Compute and Plot Birth Curves Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/function_delaunay.ipynb Computes and plots the birth curves of the DelaunayLowerstar bifiltration. ```python mp.invariants.birth_curves(s, plot=True); ``` -------------------------------- ### Decompose Module with AIDA Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/ops/AIDA.ipynb Applies the AIDA algorithm to decompose the first persistence module into two components. ```python I1,I2 = mp.ops.aida(s1) # the two rectangles ``` -------------------------------- ### Compute bounding box and renormalize modules Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/invariants/fibered_barcode.ipynb Calculates the bounding box for the one-critical modules and then renormalizes them using the `renormalize_slicer` function. This step is crucial for consistent line slicing. ```python box = mp.grids.compute_bounding_box_from_iterable([left_oc, right_oc]) left_oc = renormalize_slicer(left_oc, box) right_oc = renormalize_slicer(right_oc, box) box = np.asarray([[0, 0], [1, 1]], dtype=float) ``` -------------------------------- ### Build Delaunay core bifiltrations and one-critical modules Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/invariants/fibered_barcode.ipynb Constructs Delaunay core bifiltrations for two point clouds and converts them into one-critical modules. This prepares the data for fibered barcode analysis. ```python ks = np.unique(np.linspace(1, min(len(X), len(Y)) // 2, num=200, dtype=int)).tolist() beta = 0.5 left = mp.filtrations.CoreDelaunay( points=X, beta=beta, ks=ks, ) right = mp.filtrations.CoreDelaunay( points=Y, beta=beta, ks=ks, ) degree = 0 left_oc = mp.ops.one_criticalify(left, degree=degree) right_oc = mp.ops.one_criticalify(right, degree=degree) ``` -------------------------------- ### Estimate density on a grid Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/cubical.ipynb Estimates the density of the point cloud on a specified grid using Kernel Density Estimation (KDE). The result is reshaped into a 2D array representing the density map. ```python resolution = [200,200] grid = mp.grids.todense([np.linspace(0,1,r) for r in resolution]) density = KDE(bandwidth=.04, return_log=True).fit(X).score_samples(grid).reshape(resolution) ``` -------------------------------- ### Construct Rips Complex and DegreeRips Filtration Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/degree_rips_interface.ipynb Constructs both a standard Rips complex and a DegreeRips filtration from point cloud data. ```python # A custom complex (gudhi simplextree) can be put there instead. st = gd.RipsComplex(points=X, max_edge_length=2,).create_simplex_tree() st = mp.filtrations.DegreeRips(points=X, threshold_radius=2, ks=np.arange(100, dtype=int), collapse=50) ``` -------------------------------- ### Generate a large point cloud Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/cubical.ipynb Creates a synthetic point cloud dataset using the 'three_annulus' function for demonstration purposes. The data is then scaled and shifted. ```python np.random.seed(0) X = three_annulus(50_000,50_000) X /= 4 X+=.5 ``` -------------------------------- ### Construct Delaunay Core Bifiltration Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/filtrations/delaunay_core_bifiltration.ipynb Initializes the CoreDelaunay bifiltration object with specified point cloud, beta parameter, and k-values. Sets max_alpha_square to 1. ```python k_max = len(X)/10 num_steps = 100 ks = np.unique(np.linspace(1, k_max, num=num_steps, dtype=int)) beta = 0.5 st = CoreDelaunay(points=X, beta=beta, ks=ks, max_alpha_square=1) ``` -------------------------------- ### Create SimplexTreeMulti with Multiparameter Syntax Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/simplex_tree_by_hand.ipynb Directly creates a multipers.SimplexTreeMulti using its own multiparameter syntax. This method allows for inserting simplices with specific filtration values for each parameter. ```python st = mp.SimplexTreeMulti(num_parameters=2) # multiparameter syntax st.insert([0],[0,1]) st.insert([1],[1,0]) st.insert([0,1],[1,1]) list(st) # list of (simplex, filtration) ``` -------------------------------- ### Construct Delaunay-Codensity filtrations Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/distances/signed_integral_distance.ipynb Builds Delaunay-codensity filtrations and their degree-1 minimal presentations for two point clouds. This step is crucial for subsequent invariant calculations. ```python f1 = mp.filtrations.DelaunayCodensity(points=X, bandwidth=0.1, reduce_degree=1).minpres( 1, full_resolution=1, ) f2 = mp.filtrations.DelaunayCodensity(points=Y, bandwidth=0.1, reduce_degree=1).minpres( 1, full_resolution=1, ) ``` -------------------------------- ### Importing Necessary Libraries Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/distances/integral_distance.ipynb Imports the required libraries for numerical operations, multipers functionalities, plotting, and specific distance functions. ```python import numpy as np import multipers as mp import matplotlib.pylab as plt from multipers.distances import integral_distance from multipers.data import noisy_annulus ``` -------------------------------- ### Signed Measure to Convolution Pipeline Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/example_zoo/molecular_embedding.ipynb Sets up and applies a pipeline to convert signed measures into convolutions (images) for further analysis. Parameters like resolution and bandwidth are configured. ```python out_resolution = 100 # The resolution of the images. One can increase this to get (slightly) better results bandwidth=1 # The bandwidth. As this is unsupervised, we have to fix it to 1. IMG = mms.SignedMeasure2Convolution( # This pipeline turns signed measures to signed measure convolutions bandwidth=bandwidth, flatten=True, resolution=out_resolution, # filtration_grid=filtration_grid, grid_strategy="regular_closest", ) all_imgs = IMG.fit_transform(all_smfs) # This compiles the image pipeline and infers its grid. imgs = mdm.apply_pipeline(pathes=smfs, pipeline=IMG) # This computes the convolution (or images) ``` -------------------------------- ### Compute and Plot Birth Curves for Delaunay Lower-star Source: https://github.com/davidlapous/multipers/blob/main/docs/notebooks/invariants/birth_curves.ipynb Computes and plots the birth curves for the Delaunay lower-star filtration. This visualizes the topological features captured by the construction. ```python delaunay_birth_curves = mpi.birth_curves(s, plot=True) ```