<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Topological Data Analysis: Because Your Data Has More Shape Than You Think]]></title><description><![CDATA[Programmers often view data as numbers, but what if you treated it as shapes? This article explores how geometric features reveal hidden patterns in your datase]]></description><link>https://rodrigoalves.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Topological Data Analysis: Because Your Data Has More Shape Than You Think</title><link>https://rodrigoalves.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 07 Sep 2026 13:36:43 GMT</lastBuildDate><atom:link href="https://rodrigoalves.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Topological Data Analysis]]></title><description><![CDATA[Introduction
When thinking about data, the first thing that probably comes to your mind is numbers. You might picture standard metrics used to characterize datasets, like the mean, median, and standar]]></description><link>https://rodrigoalves.hashnode.dev/topological-data-analysis</link><guid isPermaLink="true">https://rodrigoalves.hashnode.dev/topological-data-analysis</guid><category><![CDATA[Data Science]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[Python]]></category><category><![CDATA[giotto-tda]]></category><category><![CDATA[Mathematics]]></category><category><![CDATA[Topological Data Analysis]]></category><category><![CDATA[time series]]></category><category><![CDATA[persistent-homology]]></category><category><![CDATA[data analysis]]></category><category><![CDATA[algorithmic trading]]></category><category><![CDATA[trading, ]]></category><category><![CDATA[s&p500]]></category><category><![CDATA[finance]]></category><category><![CDATA[data visualization]]></category><category><![CDATA[#Topology]]></category><category><![CDATA[computational-topology]]></category><dc:creator><![CDATA[Rodrigo Alves]]></dc:creator><pubDate>Mon, 31 Aug 2026 20:04:01 GMT</pubDate><content:encoded><![CDATA[<h2>Introduction</h2>
<p>When thinking about data, the first thing that probably comes to your mind is numbers. You might picture standard metrics used to characterize datasets, like the mean, median, and standard deviation. But what if you started analyzing your data through the lens of its <em>geometric features</em>? What if you could study the hidden "holes" that appear in your data?</p>
<p>To explain how such a magic trick can be performed, it is sensible to first look at what <strong>Topology</strong> actually means. Topology is a field of mathematics that deals with the study of shapes and their properties, more precisely, you can think of it as the study of how those properties behave when a shape is <em>stretched, twisted, or bent</em>. You might have seen a famous meme on your favorite nerd page claiming that a donut and a coffee mug are the exact same thing. It may sound strange at first glance, but if you imagine a donut made out of playdough, you can find a way to mold it into the shape of a coffee mug <em>without tearing it</em>.</p>
<p>If you are clever enough, you immediately noticed that another way to tell if a coffee mug and a donut are the same thing is to simply count the number of holes. Although I haven't mathematically defined what a "hole" is for you just yet, it is natural for you to look at a donut and a coffee mug and intuitively recognize it. We are going to apply that <em>exact same intuition</em> to numbers.</p>
<p>This article is divided into three sections where you will explore a practical example: studying the S&amp;P 500, the benchmark index tracking the stock performance of 500 of the largest U.S. companies, during the COVID-19 crisis. In the first section, I'll introduce you to the notion of <strong>simplicial complexes</strong> and explain how to build them. I will exemplify how to partition the time series into pieces and build simplicial complexes for each piece, which will give you a geometric representation of your data. In the second section, I will show you how to detect the holes in these shapes using a tool called <strong>homology</strong>, and I'll show you how to do it in practice with Python to obtain so-called <strong>persistent diagrams</strong>. In the last section, I will show you how to compare these diagrams and how they reveal the underlying patterns of your data.</p>
<p>💻 The full code for this post is available on <a href="https://github.com/crazy-maths/tda_sp500">GitHub</a>. Feel free to clone it and follow along.</p>
<hr />
<h2>1. From Time Series to Shapes: Building Simplicial Complexes</h2>
<h3>Time Series</h3>
<p>$$\text{A time series is a sequence } (x_t)_{t=0}^n \text{ of real numbers}.$$</p>
<p>That's the object you start with, nothing exotic yet! Here is the S&amp;P 500 time series, with values ranging from 1st January 2018 to 31st December 2023.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a940b0bbe6288afd9dd99b7/a0746f3c-c925-480c-ab2a-6852a37c2701.png" alt="" style="display:block;margin:0 auto" />

<p>To really get under the hood, we’ll switch to the time series of <strong>log returns</strong>. We do this because log returns normalize the data, turning compounding growth into a much easier, flat line of math to work with. Here’s the formula you can use to get there, and the updated chart.</p>
<p>$$r_t = \ln\left(\frac{P_t}{P_{t-1}}\right)$$</p>
<p>Where \(r_t\) is the log return at time \(\text{$t$}\) , \(P_t\) is the price at time \(\text{$t$}\) and \(P_{t-1}\) is the price at time \(t-1\).</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a940b0bbe6288afd9dd99b7/64d8a29a-ead5-45fa-beef-7c76f4637557.png" alt="" style="display:block;margin:0 auto" />

<details>
<summary>You will lose the first day of the time series!</summary>
<p>Because calculating log returns requires the previous day's price, you can't calculate a return for the very first day. As a result, the first value of our time series simply drops out.</p>
</details>

<p>Your goal in this section is to turn this sequence of numbers into an actual geometric shape you can study. To do that, let's define what kind of shape you're building towards: a <strong>simplicial complex</strong>.</p>
<h3>Simplicial Complexes</h3>
<p>An (abstract) simplicial complex \(\text{$K$}\) is a collection of finite subsets of a vertex set \(\text{$V$}\) , called simplices, such that \(\text{$K$}\) is closed under taking subsets:</p>
<p>$$\sigma \in K \text{ and } \tau \subseteq \sigma \Rightarrow \tau \in K$$</p>
<p>In plain terms: if a simplex is in the complex, all of its "sub-pieces" must be too.</p>
<p>Simplices have a dimension based on how many vertices they contain:</p>
<ul>
<li><p>a single vertex \(\lbrace v \rbrace\) is a <strong>0-simplex</strong> (a point)</p>
</li>
<li><p>a pair \(\lbrace v_1, v_2 \rbrace\) is a <strong>1-simplex</strong> (an edge)</p>
</li>
<li><p>a triple \(\lbrace v_1, v_2, v_3 \rbrace\) is a <strong>2-simplex</strong> (a filled triangle)</p>
</li>
<li><p>a quadruple \(\lbrace v_1, v_2, v_3, v_4 \rbrace\) is a <strong>3-simplex</strong> (a filled tetrahedron)</p>
</li>
<li><p>and so on in higher dimensions</p>
</li>
</ul>
<p>Take the 2-simplex \(\lbrace v_1, v_2, v_3 \rbrace\) as an example. Because a simplicial complex must be closed under subsets, all of its faces have to be included too: the three vertices \(\lbrace v_1 \rbrace\), \(\lbrace v_2 \rbrace\), \(\lbrace v_3 \rbrace\) , the three edges \(\lbrace v_1, v_2 \rbrace\), \(\lbrace v_1, v_3 \rbrace\), \(\lbrace v_2, v_3 \rbrace\), and the triangle itself.</p>
<p>Stitch enough of these simplices together, sharing vertices and edges, and you get a <em>simplicial complex</em>, a shape built entirely out of points, edges, triangles, and their higher-dimensional analogues. Here is an example shown in <a href="https://en.wikipedia.org/wiki/Simplicial_complex">Wikipedia</a>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a940b0bbe6288afd9dd99b7/679079b8-d367-4868-8fee-dff6a967d59e.svg" alt="" style="display:block;margin:0 auto" />

<p>You've probably noticed that you need a set of vertices before you can build that simplicial complex. In TDA, the trick is to slice your time series into <strong>moving windows</strong> of equal length (in this case 60 days). For each window, you build a set of vertices, often called a point cloud. You can choose any dimension you want, but just stick to 3 dimensions for now.</p>
<p>To make this happen in Python, you will use the <a href="https://giotto-ai.github.io/gtda-docs/latest/library.html"><code>giotto-tda</code></a> library. First, import the specific tools you need for the job:</p>
<pre><code class="language-python"># giotto-tda for tda tools
from gtda.time_series import SlidingWindow, TakensEmbedding
from gtda.homology import VietorisRipsPersistence
from gtda.diagrams import PairwiseDistance
</code></pre>
<p>Next, set up the moving windows. You are grabbing chunks of 60 days at a time. By setting <code>stride=1</code>, you just shift forward one single day to create your next window. Go ahead and apply this to your log returns array to chop it all up:</p>
<pre><code class="language-python"># create the sliding windows
windows = SlidingWindow(size=60, stride=1)

# fit and transform the log returns array
log_returns_windows = windows.fit_transform(log_returns_array)
</code></pre>
<p>Now for the fun part: turning those flat 60-day chunks into actual 3D point clouds using <strong>Takens Embedding</strong>. If you are wondering what that is, think of it as a mathematical trick that folds a 1D time series into a multi-dimensional shape. It does this by taking delayed copies of your data and using them as coordinates! Here is an example:</p>
<p>$$\begin{align} &amp;\text{Your first 60-day window: } W_0 = [r_1, r_2, r_3, r_4, \dots, r_{60}] \newline &amp;\text{Using } \text{dimension}=3 \text{ and } \text{time_delay}=1\text{, your 3D points become:} \newline &amp;p_1 = (r_1, r_2, r_3) \newline &amp;p_2 = (r_2, r_3, r_4) \newline &amp;p_3 = (r_3, r_4, r_5) \newline &amp;\dots \newline &amp;p_{58} = (r_{58}, r_{59}, r_{60}) \end{align}$$</p>
<p>In the code, you set <code>dimension=3</code> because you want 3D points. You also set <code>time_delay=1</code>, meaning you just use consecutive days to build the x, y, and z coordinates of each point. Set it up, run your windows through it, and you've got your vertices.</p>
<pre><code class="language-python"># create the takens embedding
takens_emb = TakensEmbedding(time_delay=1, dimension=3)

# fit and transform the sliding windows
log_returns_te = takens_emb.fit_transform(log_returns_windows)
</code></pre>
<p>Here is the result for the first window of 60 days:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a940b0bbe6288afd9dd99b7/c1522922-eebe-45a6-8d32-e87152235cbb.png" alt="" style="display:block;margin:0 auto" />

<h3>From point clouds to complexes: Čech Complex and Vietoris-Rips Complex</h3>
<p>So far, this has been pure combinatorics. To actually connect this to your data, you need to build simplicial complexes out of that set of vertices. As you can imagine, there are plenty of ways to pull this off. I'm going to show you two methods, starting with the Čech Complex.</p>
<p>Here is the recipe for the <strong>Čech Complex</strong>:</p>
<ul>
<li><p>Start with a point cloud (your set of vertices).</p>
</li>
<li><p>Pick a very small radius \(\text{$r$}\), and imagine a ball of radius \(\text{$r$}\) centered on every single point.</p>
</li>
<li><p>Now, let the radius \(\text{$r$}\) grow. Whenever the balls of \(\text{$n$}\) vertices all overlap (their intersection is non-empty), connect them to build an (n-1)-simplex.</p>
</li>
<li><p>This gives you a simplicial complex for every single radius r.</p>
</li>
</ul>
<p>Mathematically:</p>
<p>$$\begin{align} &amp;\text{Čech} _{r}(V) = \left\lbrace [v _{0}, v _{1}, \dots, v _{n}] \mid \bigcap _{i=0}^n B _{r}(v _{i}) \neq \varnothing \right\rbrace \end{align}$$</p>
<p>The image shows an example in 2D.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a940b0bbe6288afd9dd99b7/52bbcf8a-369b-49ec-8d68-9f0dd7154e56.png" alt="" style="display:block;margin:0 auto" />

<p>Here is the recipe for the <strong>Vietoris-Rips Complex</strong>:</p>
<ul>
<li><p>Start with your point cloud (your set of vertices).</p>
</li>
<li><p>Pick a small radius \(\text{$r$}\), and imagine a ball of radius \(\text{$r$}\) centered on every single point.</p>
</li>
<li><p>Let the radius \(\text{$r$}\) grow. Whenever the balls of \(\text{$n$}\) vertices overlap pairwise (meaning every single ball in the group touches every other ball in the group), connect them to build an (n-1)-simplex.</p>
</li>
<li><p>It doesn't matter if there is an empty space in the middle of them all, if they all touch each other pairwise, you build the simplex!</p>
</li>
</ul>
<p>Mathematically:</p>
<p>$$\begin{align} &amp;VR _{r}(V) = \left\lbrace [v _{0}, v _{1}, \dots, v _{n}] \mid \forall _{i, j} ~ d(v _{i}, v _{j}) \le 2r \right\rbrace \end{align}$$</p>
<p>The image shows an example in 2D.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a940b0bbe6288afd9dd99b7/b8d48045-7987-419f-b5cb-bb35330a1047.png" alt="" style="display:block;margin:0 auto" />

<p>Notice that on the right side of the image, those 3 balls don't even need a shared, non-empty intersection to form a 2-simplex. Pairwise overlap is all it takes!</p>
<p>So, what is the point of growing these balls and building all these complexes? As your radius increases and the simplices connect, you will notice holes starting to form in your shape. As the radius keeps growing, those holes eventually fill in and disappear. By keeping track of exactly when a hole is born and when it dies, you capture its "lifetime". That lifespan is the exact hidden information you are going to use to analyze your data.</p>
<hr />
<h2>2. Finding the Holes: Homology and Persistence Diagrams</h2>
<h3>What is Homology?</h3>
<p>Now that you have your expanding balls and your simplicial complexes, you need a way to track the empty space left behind. In topology, the mathematical tool used to count and classify these empty spaces is called <strong>Homology</strong>.</p>
<p>Don't let the formal name intimidate you. Homology is just a rigorous way of asking, "How many holes are in this shape, and what kind of holes are they?". As your radius grows and your vertices connect, Homology simply acts as a ledger, keeping track of every time a gap forms and every time a gap fills in.</p>
<h3>The dimension of holes</h3>
<p>Not all holes are the same. A gap between two isolated dots is mathematically different from the hole in the middle of a donut. Homology categorizes features by their dimension, using homology groups, denoted as \(H_n\). To actually count how many of these features exist in each dimension, we use a metric called the <strong>Betti number</strong>, denoted as \(\beta_n\). If that is a bit too much mathematics for you, just ignore the hard words, all you really need to remember is that we are simply counting the empty spaces. Here are the three you will see most often:</p>
<ul>
<li><p>\(H_0\) <strong>(Connected Components):</strong> Think of these as isolated islands of data. When the radius is tiny, every single vertex is its own \(H_0\) component. As the radius grows, these islands merge together until everything is just one giant clump.</p>
</li>
<li><p>\(H_1\) <strong>(1D Voids / Loops):</strong> This is your classic "donut hole" or rubber band. It happens when a chain of edges forms a closed ring with empty space in the exact middle.</p>
</li>
<li><p>\(H_2\) <strong>(2D Voids / Cavities):</strong> Think of the hollow inside of a ping-pong ball or a balloon. This is a trapped pocket of empty space completely surrounded by filled-in triangles (2-simplices).</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/6a940b0bbe6288afd9dd99b7/ac391c3f-d7c5-4881-a7ab-bc15b908ef33.png" alt="" style="display:block;margin:0 auto" />

<h3>Reading the Persistence Diagram</h3>
<p>So, you are tracking \(H_0\), \(H_1\), and \(H_2\) as your radius expands. How do you actually visualize all that data? You plot it on a <strong>Persistence Diagram</strong>.</p>
<p>A Persistence Diagram is just a 2D scatter plot where every single topological feature (every component, loop, or cavity) gets its own dot. Here is how you read it:</p>
<ul>
<li><p><strong>The X-Axis (Birth):</strong> This records the exact radius size where the hole first appeared.</p>
</li>
<li><p><strong>The Y-Axis (Death):</strong> This records the exact radius size where the hole finally filled in and vanished.</p>
</li>
<li><p><strong>The Diagonal Line (x=y):</strong> This is the most important part of the diagram. If a hole is born and then dies almost immediately after, its dot will plot right next to this diagonal line. We usually consider these short-lived dots to be topological <strong>noise</strong>.</p>
</li>
<li><p><strong>The Persistent Features:</strong> If a hole is born early but survives a long time before filling in, its dot will plot high up and far away from the diagonal line. These dots represent strong, real, <strong>persistent</strong> structures in your data!</p>
</li>
</ul>
<p>Now it is time to bring the theory to life and calculate the Homology of your 3D point clouds using <code>giotto-tda</code>.</p>
<pre><code class="language-python"># create the homology requirements (holes of dimension 0, 1 and 2, prime field with p=2)
homology = VietorisRipsPersistence(metric='euclidean', homology_dimensions=(0, 1, 2), coeff=2)

# calculate the persistent homology
log_returns_homology = homology.fit_transform(log_returns_te)
</code></pre>
<ul>
<li><p><code>homology_dimensions=(0, 1, 2)</code>: This tells the algorithm to track the exact \(H_0\), \(H_1\), and \(H_2\) features you just learned about. If you want to speed up the calculation and don't care about 2D cavities, update this explicitly to <code>(0, 1)</code>.</p>
</li>
<li><p><code>metric='euclidean'</code>: This uses standard straight-line distance to check for overlapping balls. You can change this to other distance metrics like <code>'manhattan'</code> or <code>'cosine'</code> if you are experimenting.</p>
</li>
</ul>
<p>With the math done, generating the actual Persistence Diagram is just a single line of code.</p>
<pre><code class="language-python"># show persistent diagram of the window
homology.plot(log_returns_homology, window_index)
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6a940b0bbe6288afd9dd99b7/815cead4-498f-4220-a5e6-ca8e74b07c31.png" alt="" style="display:block;margin:0 auto" />

<p>The different colors map directly to the different dimensions of holes. Can you see some dots hugging that diagonal line? That is just short-lived topological noise. But look at the dots further away from the line. Those represent holes that lived a long time before filling in. Those are the persistent, underlying structural features for this specific 60-day window in the market.</p>
<h3>A quick note on the math</h3>
<p>The actual machinery behind homology is significantly deeper and more complex than just expanding balls and counting holes. If you want to dive into the rigorous, formal mathematics, I highly recommend checking out Žiga Virk's <a href="https://zigavirk.gitlab.io/teaching.html">freely available book</a>. You can also find mathematical breakdowns directly in the <a href="https://giotto-ai.github.io/gtda-docs/0.5.1/theory/glossary.html">giotto-tda documentation</a>.</p>
<hr />
<h2>3. Comparing Shapes: What Persistence Diagrams Tell Us About the Market</h2>
<p>You now have a rolling sequence of Persistence Diagrams, one for every single 60-day window in your dataset. But looking at thousands of scatter plots isn't going to help you. You need a way to mathematically measure how much the topological shape of the market changes from one day to the next.</p>
<p>To do this, you calculate the <strong>distance between consecutive Persistence Diagrams</strong>. If the market is behaving normally, today's 60-day window will have almost the exact same topological shape as yesterday's, and the distance will be near zero. If the market suddenly crashes, the geometry shatters, new holes form, and the distance between the diagrams will spike.</p>
<p>There are two main ways to calculate this distance:</p>
<ul>
<li><strong>Wasserstein Distance:</strong> This measures the total overall change. It calculates the total work or energy required to shift every single dot in the first diagram to match the dots in the second diagram. Given two diagrams \(D_1\) and \(D_2\) and the diagonal \(\Delta\), consider all bijections (one-to-one correspondence) \(\phi \colon D_1 \cup \Delta \to D_2 \cup \Delta\), and the norm \(||-|| _{\infty}\) in \(\mathbb{R}^2\) , the p-Wasserstein distance between the diagrams is defined as:</li>
</ul>
<p>$$\inf _{\phi} \left( \sum _{x \in D _{1} \cup \Delta} ||x - \phi(x)|| _{\infty}^p \right)^{1/p}$$</p>
<ul>
<li><strong>Bottleneck Distance:</strong> This is actually a special, extreme case of the Wasserstein distance (specifically, the \(\infty\)-Wasserstein distance). Instead of summing up all the small shifts, it ignores the small stuff and isolates only the single largest, most extreme movement between any matched pair of dots. Because it only cares about the maximum disruption, it is perfect for spotting sudden, violent market shocks.</li>
</ul>
<p>$$\inf _{\phi} \sup _{x \in D _{1} \cup \Delta} ||x - \phi(x)|| _{\infty}$$</p>
<p>To calculate this in <code>giotto-tda</code>, you use the distance tools to compare your rolling sequence of homologies.</p>
<pre><code class="language-python"># specify bottleneck distance to compare persistence diagrams
distances = PairwiseDistance(metric='bottleneck')

# calculate only sequential bottleneck distances (diagram i vs diagram i+1)
log_returns_bottleneck = np.array([distances.fit_transform(log_returns_homology[i:i+2])[0, 1] for i in range(len(log_returns_homology) - 1)])
</code></pre>
<ul>
<li>Change <code>metric='bottleneck'</code> to <code>metric='wasserstein'</code> if you want to measure the total geometric shift rather than the single maximum disruption.</li>
</ul>
<p>Once you have that array of distances, it is time to plot them directly over your actual market prices to see the topological regime changes in action.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a940b0bbe6288afd9dd99b7/e897737d-f39d-47de-b42e-10afe9c73752.png" alt="" style="display:block;margin:0 auto" />

<p>When you look at the plot, the connection between topology and market behavior becomes undeniable. During steady bull runs or sideways chop, the Bottleneck distance stays relatively flat and quiet. The shape of the market is stable.</p>
<p>But look at what happens right as the market drops. The Bottleneck distance violently spikes. The underlying 3D point cloud of your price data has fundamentally transformed, opening up new topological holes and cavities. By tracking the birth and death of these shapes, you aren't just looking at a moving average, you are mathematically measuring the exact moment the structure of the market breaks.</p>
<hr />
<h2>Conclusion</h2>
<p>Let’s be honest, staring at a standard line chart of stock prices is a great way to go cross-eyed and learn absolutely nothing new. But look at what you just pulled off instead.</p>
<p>You took that flat, boring price data, folded it into a 3D point cloud using Takens embedding, and blew up expanding mathematical bubbles around every single point just to see where the empty spaces were. You tracked the exact moment those topological holes were born and when they died, plotting them onto a Persistence Diagram like a weird, geometric heart monitor for the market.</p>
<p>Then, instead of just crossing your fingers or squinting at a lagging moving average to guess if a crash was coming, you used the Bottleneck distance to measure the exact moment the market's underlying structure snapped in half.</p>
<p>Financial markets are messy, irrational, and mostly driven by panic. But underneath all that noise, the chaos actually has a shape. And now, you have the Python code to mathematically measure exactly when that shape breaks.</p>
<p>Thanks for reading! You can connect with me on <a href="https://www.linkedin.com/in/rodrigo-alves-2066271ba/">LinkedIn</a> and <a href="https://github.com/crazy-maths">GitHub</a>.</p>
<hr />
<h2>References</h2>
<ul>
<li><p>S&amp;P Dow Jones Indices LLC, S&amp;P 500 [SP500], retrieved from FRED, Federal Reserve Bank of St. Louis; <a href="https://fred.stlouisfed.org/series/SP500">https://fred.stlouisfed.org/series/SP500</a>, August 30, 2026.</p>
</li>
<li><p>Ž. Virk. Introduction to Persistent Homology. Založba UL FRI, University of Ljubljana, 2022, <a href="https://zigavirk.gitlab.io/teaching.html">doi: 10.51939/0002</a>.</p>
</li>
<li><p>giotto-tda: A Topological Data Analysis Toolkit for Machine Learning and Data Exploration, Tauzin <em>et al</em>, <a href="https://arxiv.org/abs/2004.02551">arXiv:2004.02551</a>, 2020.</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>