blog/algorithms/paths/bf-to-astar/bf/index.html

184 lines
234 KiB
HTML
Raw Normal View History

<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-algorithms docs-version-current docs-doc-page docs-doc-id-paths/2024-01-01-bf-to-astar/bf" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.1.1">
<title data-rh="true">BF | mf</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://blog.mfocko.xyz/algorithms/paths/bf-to-astar/bf/"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-algorithms-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-algorithms-current"><meta data-rh="true" property="og:title" content="BF | mf"><meta data-rh="true" name="description" content="Solving the shortest path problem with a naïve approach that turns into
something.
"><meta data-rh="true" property="og:description" content="Solving the shortest path problem with a naïve approach that turns into
something.
"><link data-rh="true" rel="icon" href="/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://blog.mfocko.xyz/algorithms/paths/bf-to-astar/bf/"><link data-rh="true" rel="alternate" href="https://blog.mfocko.xyz/algorithms/paths/bf-to-astar/bf/" hreflang="en"><link data-rh="true" rel="alternate" href="https://blog.mfocko.xyz/algorithms/paths/bf-to-astar/bf/" hreflang="x-default"><link data-rh="true" rel="preconnect" href="https://0VXRFPR4QF-dsn.algolia.net" crossorigin="anonymous"><link rel="search" type="application/opensearchdescription+xml" title="mf" href="/opensearch.xml">
<link rel="alternate" type="application/rss+xml" href="/blog/rss.xml" title="mf RSS Feed">
<link rel="alternate" type="application/atom+xml" href="/blog/atom.xml" title="mf Atom Feed">
<link rel="alternate" type="application/json" href="/blog/feed.json" title="mf JSON Feed">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css" integrity="sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM" crossorigin="anonymous"><link rel="stylesheet" href="/assets/css/styles.e1ac7597.css">
<script src="/assets/js/runtime~main.2135d25d.js" defer="defer"></script>
<script src="/assets/js/main.6e9790c2.js" defer="defer"></script>
</head>
<body class="navigation-with-keyboard">
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return localStorage.getItem("theme")}catch(t){}}();t(null!==e?e:"light")}(),function(){try{const c=new URLSearchParams(window.location.search).entries();for(var[t,e]of c)if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id="__docusaurus"><div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><b class="navbar__title text--truncate">mf</b></a><div class="navbar__item dropdown dropdown--hoverable"><a href="#" aria-haspopup="true" aria-expanded="false" role="button" class="navbar__link">Additional FI MU materials</a><ul class="dropdown__menu"><li><a aria-current="page" class="dropdown__link dropdown__link--active" href="/algorithms/">Algorithms</a></li><li><a class="dropdown__link" href="/c/">C</a></li><li><a class="dropdown__link" href="/cpp/">C++</a></li></ul></div><a class="navbar__item navbar__link" href="/contributions/">Contributions</a><a class="navbar__item navbar__link" href="/talks/">Talks</a></div><div class="navbar__items navbar__items--right"><a class="navbar__item navbar__link" href="/blog/">Blog</a><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type="button" disabled="" title="Switch between dark and light mode (currently light mode)" aria-label="Switch between dark and light mode (currently light mode)" aria-live="polite"><svg viewBox="0 0 24 24" width="24" height="24" class="lightToggleIcon_pyhR"><path fill="currentColor" d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" class="darkToggleIcon_wfgR"><path fill="currentColor" d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path></svg></button></div><div class="navbarSearchContainer_Bca1"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg width="20" height="20" class="DocSearch-Search-Icon" viewBox="0 0 20 20"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.
<p>We will <em>ease in</em> with our own algorithm to find the shortest path. We will
start by thinking about the ways we can achieve that. If we didn&#x27;t have the <code>*</code>
cells, we could&#x27;ve easily run a BFS<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup> and be done with it. Maybe it is a good
place to start, or isn&#x27;t, there is only one way to find out though.</p>
<p><em>How does the BFS work?</em> We know the vertex where we start and we know the
vertex we want to find the shortest path to. Given this knowledge we
incrementally visit all of our neighbours and we do that over and over until the
destination is found<sup><a href="#user-content-fn-2" id="user-content-fnref-2" data-footnote-ref="true" aria-describedby="footnote-label">2</a></sup>. Could we leverage this somehow?</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="naïve-approach">Naïve approach<a href="#naïve-approach" class="hash-link" aria-label="Direct link to Naïve approach" title="Direct link to Naïve approach"></a></h2>
<p>Well, we could probably start with all vertices being <em>unreachable</em> (having the
highest possible price) and try to improve what we&#x27;ve gotten so far until there
are no improvements. That sounds fine, we shall implement this. Since we are
going on repeat, we will name this function <code>bf()</code> as in <em>brute-force</em>, cause it
is trying to find it the hard way:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">static</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token plain">vector</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&lt;</span><span class="token plain">vertex_t</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&gt;</span><span class="token plain"> DIRECTIONS </span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token plain">vector</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain">std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">make_pair</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token number" style="color:hsl(35, 99%, 36%)">0</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token number" style="color:hsl(35, 99%, 36%)">1</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">make_pair</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token number" style="color:hsl(35, 99%, 36%)">0</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">-</span><span class="token number" style="color:hsl(35, 99%, 36%)">1</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">make_pair</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token number" style="color:hsl(35, 99%, 36%)">1</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token number" style="color:hsl(35, 99%, 36%)">0</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">make_pair</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token operator" style="color:hsl(221, 87%, 60%)">-</span><span class="token number" style="color:hsl(35, 99%, 36%)">1</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </s
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Relaxation</div><div class="admonitionContent_BuS1"><p>I have made a brief mention of the relaxation in the comment in the code. You&#x27;ve
been probably thought that <strong>relaxation of an edge</strong> means that you found
a better solution to the problem.</p><p>In general it is an approximation technique that <em>reduces</em> the problem of
finding the path <code>u → x1 → … → xn → v</code> to subproblems
<code>u → x1, x1 → x2, …, xn → v</code> such that the sum of the costs of each step is
<strong>minimal</strong>.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="correctness">Correctness<a href="#correctness" class="hash-link" aria-label="Direct link to Correctness" title="Direct link to Correctness"></a></h3>
<p><em>Is our solution correct?</em> It appears to be correct… We have rather complicated
map and our algorithm has finished in an instant with the following output:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Normal cost: 1</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Vortex cost: 5</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Graph:</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#############</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..#..*.*.**#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">##***.....**#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..########.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#...###...#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..#...##.#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..#.*.#..#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#D...#....#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">########*.*.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#S..........#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#############</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Cost: 22</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>If you have a better look at the map, you will realize that the cost <code>22</code> is the
one path skipping the <code>*</code> cells, since they cost more than going around.</p>
<p>We can play around a bit with it. The <code>*</code> cells can be even vortices that pull
you in with a negative price and let you <em>propel</em> yourself out <!-- -->😉<!-- --> Let&#x27;s
change their cost to <code>-1</code> then. Let&#x27;s check what&#x27;s the fastest path to the cell.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Normal cost: 1</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Vortex cost: -1</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Graph:</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#############</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..#..*.*.**#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">##***.....**#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..########.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#...###...#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..#...##.#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..#.*.#..#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#D...#....#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">########*.*.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#S..........#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#############</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>And we&#x27;re somehow stuck… The issue comes from the fact that <em>spinning around</em> in
the vortices allows us to lower the cost infinitely. That&#x27;s why after each
iteration there is still a possibility to lower the cost, hence the algorithm
doesn&#x27;t finish. <em>What can we do about this?</em></p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>This algorithm is correct as long as there are no negative loops, i.e. ways how
to lower the cost infinitely. Therefore we can also just lay a precondition that
requires no negative loops to be present.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="fixing-the-infinite-loop">Fixing the infinite loop<a href="#fixing-the-infinite-loop" class="hash-link" aria-label="Direct link to Fixing the infinite loop" title="Direct link to Fixing the infinite loop"></a></h3>
<p>Our issue lies in the fact that we can endlessly lower the cost. Such thing must
surely happen in some kind of a loop. We could probably track the relaxations
and once we spot repeating patterns, we know we can safely terminate with <em>some</em>
results at least.</p>
<p>This approach will not even work on our 2D map, let alone any graph. Problem is
that the <em>negative loops</em> lower the cost in <strong>each</strong> iteration and that results
in lowering of the costs to the cells that are reachable from the said loops.
That&#x27;s why this problem is relatively hard to tackle, it&#x27;s not that easy to spot
the repeating patterns algorithmically.</p>
<p>On the other hand, we can approach this from the different perspective. Let&#x27;s
assume the worst-case scenario (generalized for any graph):</p>
<blockquote>
<p>Let <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>K</mi><mi>n</mi></msub></mrow><annotation encoding="application/x-tex">K_n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07153em">K</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0715em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> be complete graph. Let <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi></mrow><annotation encoding="application/x-tex">P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal" style="margin-right:0.13889em">P</span></span></span></span> be the shortest path from <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">v_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mi>n</mi></msub></mrow><annotation encoding="application/x-tex">v_n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span>
such that <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi></mrow><annotation encoding="application/x-tex">P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal" style="margin-right:0.13889em">P</span></span></span></span> has <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo></mo><mn>1</mn></mrow><annotation encoding="application/x-tex">n - 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin"></span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">1</span></span></span></span> edges, i.e. the shortest path between the two chosen
vertices visits all vertices (not necessarily in order) and has the lowest
cost.</p>
<p>In such scenario assume the worst-case ordering of the relaxations (only one
<em>helpful</em> relaxation per iteration). In this case, in each iteration we find
the next edge on our path <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi></mrow><annotation encoding="application/x-tex">P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal" style="margin-right:0.13889em">P</span></span></span></span> as the last. This means that we need
<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal"></mi><mi>V</mi><mi mathvariant="normal"></mi><mo></mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\vert V \vert - 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"></span><span class="mord mathnormal" style="margin-right:0.22222em">V</span><span class="mord"></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin"></span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">1</span></span></span></span> iterations to find the shortest path <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi></mrow><annotation encoding="application/x-tex">P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal" style="margin-right:0.13889em">P</span></span></span></span>.</p>
<p>Because we have laid <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi></mrow><annotation encoding="application/x-tex">P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em"></span><span class="mord mathnormal" style="margin-right:0.13889em">P</span></span></span></span> as the shortest path from <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">v_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mi>n</mi></msub></mrow><annotation encoding="application/x-tex">v_n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> and it
visits all vertices, its prefixes are the shortest paths from <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">v_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span> to any
other vertex in our graph.</p>
<p>Therefore, we can safely assume that any relaxation after <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal"></mi><mi>V</mi><mi mathvariant="normal"></mi><mo></mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\vert V \vert - 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"></span><span class="mord mathnormal" style="margin-right:0.22222em">V</span><span class="mord"></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin"></span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">1</span></span></span></span>
iterations, is the effect of a negative loop in the graph.</p>
</blockquote>
<p><em>How can we leverage this?</em> We will go through the edges only as many times as
cells we have. Let&#x27;s adjust the code to fix the looping:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">auto</span><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">bf_finite</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> graph</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> g</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> vertex_t</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> source</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> vertex_t</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> destination</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">int</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// source must be within the bounds</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">assert</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">g</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">has</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">source</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// destination must be within the bounds</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">assert</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">g</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">has</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">destination</span><span class=
<p>And we get the following result:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Normal cost: 1</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Vortex cost: -1</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Graph:</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#############</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..#..*.*.**#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">##***.....**#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..########.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#...###...#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..#...##.#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#..#.*.#..#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#D...#....#.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">########*.*.#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#S..........#</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">#############</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">Cost: -236</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The negative cost means that there is a way to <em>propel</em> ourselves via some
vortices. Let&#x27;s adjust the cost of <em>vortices</em> back to the original <code>5</code> and check
whether our modified algorithm works as it did before. And it surely does yield
the <code>22</code> as before.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Refactoring</div><div class="admonitionContent_BuS1"><p>You can definitely notice some <em>deep nesting</em> in our code, to counter this
phenomenon I will convert the looping over <code>x</code> and <code>y</code> to one variable that can
be decomposed to <code>x</code> and <code>y</code>. It is a very common practice when working with 2D
arrays/lists to represent them as 1D. In our case:</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">i : 0 → width * height - 1</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">x = i % width</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">y = i / width</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="bellman-ford">Bellman-Ford<a href="#bellman-ford" class="hash-link" aria-label="Direct link to Bellman-Ford" title="Direct link to Bellman-Ford"></a></h2>
<p>If you have ever attended any Algorithms course that had path-finding in its
syllabus, you probably feel like you&#x27;ve seen the algorithm above before<sup><a href="#user-content-fn-3" id="user-content-fnref-3" data-footnote-ref="true" aria-describedby="footnote-label">3</a></sup>… And
yes, the first algorithm I have proposed is a very dumb version of the
<em>Bellman-Ford</em> algorithm, it&#x27;s dumb, because it loops <!-- -->😉<!-- --> After our “looping”
prevention we got to the point that is almost the <em>Bellman-Ford</em> with the one
exception that it doesn&#x27;t report whether there are any negative cycles, it just
ends.</p>
<p>Let&#x27;s have a look at a proper implementation of the Bellman-Ford algorithm:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">auto</span><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">bellman_ford</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> graph</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> g</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> vertex_t</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> source</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">-&gt;</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token plain">vector</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&lt;</span><span class="token plain">std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token plain">vector</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&lt;</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">int</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&gt;&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// source must be within the bounds</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">assert</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">g</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">has</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">source</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// we need to initialize the distances</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token plain">vector</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&lt;</span><span class="token plain">std</span><span class="token double-colon punctuation" style="color:hsl
<p>And if we run it with our negative cost of entering vortices:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">[Bellman-Ford] Found a negative loop</span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain">[Bellman-Ford] Cost: -240</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="on-the-bellman-ford">On the Bellman-Ford<a href="#on-the-bellman-ford" class="hash-link" aria-label="Direct link to On the Bellman-Ford" title="Direct link to On the Bellman-Ford"></a></h3>
<p>You might be surprised that we have managed to iterate from a brute-force method
that mindlessly tries to find a better path until there are no better paths left
all the way to the Bellman-Ford algorithm.</p>
<p>I always say that Bellman-Ford is a <em>smart</em> brute-force. BF is also an algorithm
that leverages <em>dynamic programming</em>. You might wonder how can it utilize DP if
it is “technically” a brute-force technique. Table with the shortest distances
is the thing that makes it DP.</p>
<blockquote>
<p>I might not know the shortest path yet, but I do remember all of other paths,
and I can improve them, if possible.</p>
</blockquote>
<p>That&#x27;s where the beauty of both <em>dynamic programming</em> and <em>relaxing</em> gets merged
together and does its magic.</p>
<p>Proof of the correctness of the BF is done via induction to the number of
iterations. I would suggest to try to prove the correctness yourself and
possibly look it up, if necessary.</p>
<p>Also the correctness of the BF relies on the conclusion we&#x27;ve made when fixing
the infinite-loop on our naïve BF solution.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="time-complexity">Time complexity<a href="#time-complexity" class="hash-link" aria-label="Direct link to Time complexity" title="Direct link to Time complexity"></a></h2>
<p>Let&#x27;s have a short look at the time complexities of the presented algorithms:</p>
<ol>
<li>
<p>naïve approach: given that there are no negative loops, we are bound by the
worst-case ordering of the relaxations which results in</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="script">O</mi><mo stretchy="false">(</mo><mi mathvariant="normal"></mi><mi>V</mi><mi mathvariant="normal"></mi><mo></mo><mi mathvariant="normal"></mi><mi>E</mi><mi mathvariant="normal"></mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\mathcal{O}(\vert V \vert \cdot \vert E \vert)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathcal" style="margin-right:0.02778em">O</span><span class="mopen">(</span><span class="mord"></span><span class="mord mathnormal" style="margin-right:0.22222em">V</span><span class="mord"></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin"></span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"></span><span class="mord mathnormal" style="margin-right:0.05764em">E</span><span class="mord"></span><span class="mclose">)</span></span></span></span></span>
</li>
<li>
<p>our naïve approach with the fixed count of iterations instead of the
<code>do-while</code> loop results in the same worst-case time complexity:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Θ</mi><mo stretchy="false">(</mo><mi mathvariant="normal"></mi><mi>V</mi><mi mathvariant="normal"></mi><mo></mo><mi mathvariant="normal"></mi><mi>E</mi><mi mathvariant="normal"></mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\Theta(\vert V \vert \cdot \vert E \vert)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord">Θ</span><span class="mopen">(</span><span class="mord"></span><span class="mord mathnormal" style="margin-right:0.22222em">V</span><span class="mord"></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin"></span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"></span><span class="mord mathnormal" style="margin-right:0.05764em">E</span><span class="mord"></span><span class="mclose">)</span></span></span></span></span>
</li>
<li>
<p>and finally the well-known Bellman-Ford&#x27;s algorithm time complexity:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Θ</mi><mo stretchy="false">(</mo><mi mathvariant="normal"></mi><mi>V</mi><mi mathvariant="normal"></mi><mo></mo><mi mathvariant="normal"></mi><mi>E</mi><mi mathvariant="normal"></mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\Theta(\vert V \vert \cdot \vert E \vert)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord">Θ</span><span class="mopen">(</span><span class="mord"></span><span class="mord mathnormal" style="margin-right:0.22222em">V</span><span class="mord"></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin"></span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord"></span><span class="mord mathnormal" style="margin-right:0.05764em">E</span><span class="mord"></span><span class="mclose">)</span></span></span></span></span>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="small-refactor">Small refactor<a href="#small-refactor" class="hash-link" aria-label="Direct link to Small refactor" title="Direct link to Small refactor"></a></h2>
<p>Since we are literally copy-pasting the body of the loops just for the sake of
relaxing, we can factor that part out into a separate function:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">static</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">auto</span><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">_check_vertex</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> graph</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> g</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token plain">vector</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&lt;</span><span class="token plain">std</span><span class="token double-colon punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token plain">vector</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&lt;</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">int</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&gt;&gt;</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> distances</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">int</span><span class="token plain"> v</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">bool</span><span class="token plain"> check_only </span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain"> </span><span class="token boolean" style="color:hsl(35, 99%, 36%)">false</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">bool</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">bool</span><span class="token plain"> improvement_found </span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain"> </span><span class="token boolean" style="color:hsl(35, 99%, 36%)">false</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// unpack the vertex coordinates</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><spa
<p>This function can be also used for checking the negative loops at the end of the
BF by using the <code>check_only</code> parameter to signal that we just want to know if
there would be any edge relaxed instead of performing the relaxation itself.</p>
<p>Then we can also see the differences between the specific versions of our
path-finding algorithms in a clear way:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">auto</span><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">bf</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> graph</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> g</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> vertex_t</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> source</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">const</span><span class="token plain"> vertex_t</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&amp;</span><span class="token plain"> destination</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">int</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// source must be within the bounds</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">assert</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">g</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">has</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">source</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// destination must be within the bounds</span><span class="token plain"></span><br></span><span class="token-line" style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">assert</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">g</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">has</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token plain">destination</span><span class="token punctuation
<hr>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>You might&#x27;ve noticed that I&#x27;ve been using abbreviation <em>BF</em> interchangeably for
both <em>Bellman-Ford</em> and <em>brute-force</em>. If you think about the way Bellman-Ford
algorithm works, you should realize that in the worst case it&#x27;s updating the
shortest path till there no shorter path exists, so in a sense, you could really
consider it a brute-force algorithm.</p></div></div>
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorWithStickyNavbar_LWe7 sr-only" id="footnote-label">Footnotes<a href="#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes"></a></h2>
<ol>
<li id="user-content-fn-1">
<p><a href="https://en.wikipedia.org/wiki/Breadth-first_search" target="_blank" rel="noopener noreferrer">Breadth-first search</a> <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-2">
<p>Of course, there are some technicalities like keeping track of the visited
vertices to not taint the shortest path by already visited vertices. <a href="#user-content-fnref-2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref"></a></p>
</li>
<li id="user-content-fn-3">
<p>or at least you should, LOL <a href="#user-content-fnref-3" data-footnote-backref="" aria-label="Back to reference 3" class="data-footnote-backref"></a></p>
</li>
</ol>
</section></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="theme-doc-footer-tags-row row margin-bottom--sm"><div class="col"><b>Tags:</b><ul class="tags_jXut padding--none margin-left--sm"><li class="tag_QGVx"><a class="tag_zVej tagRegular_sFm0" href="/algorithms/tags/cpp/">cpp</a></li><li class="tag_QGVx"><a class="tag_zVej tagRegular_sFm0" href="/algorithms/tags/brute-force/">brute force</a></li><li class="tag_QGVx"><a class="tag_zVej tagRegular_sFm0" href="/algorithms/tags/bellman-ford/">bellman ford</a></li><li class="tag_QGVx"><a class="tag_zVej tagRegular_sFm0" href="/algorithms/tags/dynamic-programming/">dynamic programming</a></li></ul></div></div><div class="theme-doc-footer-edit-meta-row row"><div class="col"><a href="https://github.com/mfocko/blog/tree/main/algorithms/11-paths/2024-01-01-bf-to-astar/01-bf.md" target="_blank" rel="noopener noreferrer" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_Z9Sw" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_vwxv"><span class="theme-last-updated">Last updated<!-- --> on <b><time datetime="2024-01-01T00:00:00.000Z">Jan 1, 2024</time></b></span></div></div></footer></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/algorithms/paths/bf-to-astar/"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">From BF to A*</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/algorithms/paths/bf-to-astar/dijkstra/"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Dijkstra&#x27;s algorithm</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#basic-idea" class="table-of-contents__link toc-highlight">Basic idea</a></li><li><a href="#naïve-approach" class="table-of-contents__link toc-highlight">Naïve approach</a><ul><li><a href="#correctness" class="table-of-contents__link toc-highlight">Correctness</a></li><li><a href="#fixing-the-infinite-loop" class="table-of-contents__link toc-highlight">Fixing the infinite loop</a></li></ul></li><li><a href="#bellman-ford" class="table-of-contents__link toc-highlight">Bellman-Ford</a><ul><li><a href="#on-the-bellman-ford" class="table-of-contents__link toc-highlight">On the Bellman-Ford</a></li></ul></li><li><a href="#time-complexity" class="table-of-contents__link toc-highlight">Time complexity</a></li><li><a href="#small-refactor" class="table-of-contents__link toc-highlight">Small refactor</a></li></ul></div></div></div></div></main></div></div></div><footer class="footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="col footer__col"><div class="footer__title">Git</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://github.com/mfocko" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://gitlab.com/mfocko" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitLab<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://git.mfocko.xyz/mfocko" target="_blank" rel="noopener noreferrer" class=
</body>
</html>