<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Matej Gazda</title>
<link>https://matejgazda.com/posts/</link>
<atom:link href="https://matejgazda.com/posts/index.xml" rel="self" type="application/rss+xml"/>
<description>Notes on machine learning, medical imaging, and the occasional engineering rabbit hole.</description>
<generator>quarto-1.9.37</generator>
<lastBuildDate>Thu, 14 May 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>Paper Map: NeurIPS / CVPR / ICLR / ICML 2024–2025</title>
  <dc:creator>Matej Gazda</dc:creator>
  <link>https://matejgazda.com/posts/paper-map.html</link>
  <description><![CDATA[ 





<p>Most of AI research in 2024–2025 is LLMs and diffusion. The imbalance is bigger than I expected.</p>
<p>I pulled the accepted-paper lists from CVPR, NeurIPS, ICML, and ICLR for 2024 and 2025 (main tracks only, no workshops). For each paper I took the title and abstract, embedded them, projected to 2D with UMAP, then ran HDBSCAN to find clusters. Cluster names come from the most distinctive words in the titles. <strong>26,741 papers, 509 clusters.</strong> Snapshot from May 2026.</p>
<p>Every dot is a paper. Nearby dots are about similar topics. Hover for the title, click the venue buttons to filter, zoom with the mouse. Full screen view: <a href="../papers_map.html">papers_map.html</a>.</p>
<iframe src="../papers_map.html" width="100%" height="900" style="border:1px solid var(--bs-border-color); border-radius:10px;" loading="lazy" title="Interactive paper map">
</iframe>
<section id="whats-actually-big" class="level2">
<h2 class="anchored" data-anchor-id="whats-actually-big">What’s actually big</h2>
<p>The biggest clusters each sit between 200 and 300 papers. Grouped roughly:</p>
<p><strong>Language</strong></p>
<ul>
<li>RLHF and preference alignment</li>
<li>LLM agents and code generation</li>
<li>LLM reasoning, math, chain-of-thought</li>
<li>In-context learning, induction heads</li>
<li>LoRA and parameter-efficient fine-tuning</li>
</ul>
<p><strong>Vision</strong></p>
<ul>
<li>Video understanding and temporal grounding</li>
<li>Human motion and hand interaction</li>
<li>Text-to-image generation</li>
<li>3D Gaussian splatting</li>
<li>Diffusion sampling, consistency models, flow matching</li>
</ul>
<p><strong>Methods, RL, theory</strong></p>
<ul>
<li>Continual / class-incremental learning</li>
<li>Linear attention and state-space models (Mamba etc.)</li>
<li>Federated learning</li>
<li>World models and goal-conditioned RL</li>
<li>Multi-agent RL, offline RL</li>
<li>Differential privacy, membership inference attacks</li>
<li>Conformal prediction, spiking neural networks</li>
<li>Molecular ML and drug discovery</li>
</ul>
<p>Crowded but a step down: time-series forecasting, point cloud segmentation, LiDAR/radar detection, pruning and sparsity. There’s also a surprisingly fat cluster around grokking, two-layer networks, and Kolmogorov-Arnold things, which I read as the small-theory subfield being healthier than people give it credit for.</p>
</section>
<section id="where-almost-nobody-is" class="level2">
<h2 class="anchored" data-anchor-id="where-almost-nobody-is">Where almost nobody is</h2>
<p>Tiny clusters, 7-10 papers each, the kind of niche where you can read everything in a weekend:</p>
<ul>
<li>Text-to-SQL</li>
<li>Event-based vision and depth</li>
<li>Face restoration and rigging</li>
<li>Protein conformational dynamics</li>
<li>Link prediction</li>
<li>DNA regulatory sequence design</li>
<li>Counterfactual generation</li>
<li>Self-supervised equivariance</li>
</ul>
<p>A few subfields barely register at these four venues. Event cameras and DNA sequence design are good examples. Either the community is publishing at specialized venues (NeurIPS Datasets &amp; Benchmarks, MICCAI, ISMB, CVPR workshops), or there genuinely isn’t enough work to fill a session.</p>
</section>
<section id="how-id-use-it" class="level2">
<h2 class="anchored" data-anchor-id="how-id-use-it">How I’d use it</h2>
<ul>
<li>If you’re about to claim your idea is new, look up where it would land on the map and read the closest five papers first. Cheaper than finding out during rebuttal.</li>
<li>If you’re picking a PhD topic, look for small islands sitting next to a big cluster. That’s usually a gap with a path back to the mainline.</li>
<li>If you’re reviewing, the map is a fast sanity check on the “underexplored” framing in someone’s introduction.</li>
</ul>
</section>
<section id="caveats" class="level2">
<h2 class="anchored" data-anchor-id="caveats">Caveats</h2>
<p>Embedding clusters reflect title and abstract wording. Two papers can sit in the same cluster and be doing completely different things, just because they share buzzwords. Two papers can sit far apart and be closer in practice than the map suggests. Use this as a starting point, not as a literature review.</p>
<p>Missing on purpose: workshops, datasets-and-benchmarks tracks, ACL, EMNLP, MICCAI, ISBI. Medical imaging venues are next on my list.</p>
<p>If your cluster looks wrong or you spot a paper that’s clearly mislabeled, ping me on <a href="https://github.com/BraveDistribution">GitHub</a>. I’ll rerun it.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>tools</category>
  <category>literature</category>
  <category>visualization</category>
  <guid>https://matejgazda.com/posts/paper-map.html</guid>
  <pubDate>Thu, 14 May 2026 00:00:00 GMT</pubDate>
  <media:content url="https://matejgazda.com/assets/paper-map-preview.png" medium="image" type="image/png" height="90" width="144"/>
</item>
<item>
  <title>TSP in Python: Christofides, 2-opt, 3-opt</title>
  <dc:creator>Matej Gazda</dc:creator>
  <link>https://matejgazda.com/posts/tsp-algorithms-2-opt-3-opt-in-python.html</link>
  <description><![CDATA[ 





<p>The travelling salesman problem (TSP) is one of those textbook problems that sounds simple and turns out not to be: given a list of cities and the distances between them, find the shortest tour that visits every city exactly once and returns to the start.</p>
<p>It’s NP-hard in the general case, so unless you have ten cities or a quantum computer, you’ll want an approximation. Below are the three algorithms I implemented in <a href="https://github.com/BraveDistribution/pytsp">pytsp</a>, with just enough math to understand what’s going on.</p>
<section id="christofides-the-1.5-approximation" class="level2">
<h2 class="anchored" data-anchor-id="christofides-the-1.5-approximation">Christofides (the 1.5-approximation)</h2>
<p>Christofides only works on metric TSP instances: distances must be symmetric and obey the triangle inequality. In return it gives you a tour guaranteed to be at most <strong>1.5× the optimal length</strong>. It is still the best constant-factor approximation known for metric TSP that doesn’t depend on exotic results.</p>
<p>The recipe:</p>
<ol type="1">
<li>Build a minimum spanning tree <code>T</code> of the graph.</li>
<li>Find the set <code>O</code> of vertices with odd degree in <code>T</code>.</li>
<li>Compute a minimum-weight perfect matching <code>M</code> on <code>O</code>.</li>
<li>Combine <code>T ∪ M</code> into a multigraph. Every vertex now has even degree.</li>
<li>Find an Eulerian circuit.</li>
<li>Shortcut repeated vertices (use the triangle inequality to make a Hamiltonian cycle out of it).</li>
</ol>
<p>The trickiest step is the matching. <code>networkx</code> ships <code>max_weight_matching</code>, which finds a <em>maximum</em>-weight matching, so to get the <em>minimum</em> one I flip the sign of the weights. That only works because the algorithm doesn’t drop edges with negative weights when you ask for maximum cardinality. Subtracting weights from a large constant is the cleaner trick if you want positive numbers.</p>
<p>For Euler circuits and MSTs, just use <code>networkx</code>. No need to reinvent.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pseudo-summary; full code in pytsp/christofides.py</span></span>
<span id="cb1-2">mst   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> prim(graph)</span>
<span id="cb1-3">odd   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [v <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> v <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> mst <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> mst.degree(v) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]</span>
<span id="cb1-4">match <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> min_weight_perfect_matching(graph, odd)</span>
<span id="cb1-5">H     <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.MultiGraph(mst)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> H.add_edges_from(match)</span>
<span id="cb1-6">tour  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">list</span>(nx.eulerian_circuit(H))</span>
<span id="cb1-7">tour  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> shortcut(tour)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># remove repeats</span></span></code></pre></div></div>
</section>
<section id="opt-the-workhorse" class="level2">
<h2 class="anchored" data-anchor-id="opt-the-workhorse">2-opt (the workhorse)</h2>
<p>2-opt is the simplest local-search heuristic for TSP. Start with any tour. Repeatedly: pick two non-adjacent edges, delete them, and reconnect the two resulting paths the other way. Keep the change if the new tour is shorter.</p>
<pre><code>... → A — B ... C — D → ...        (original)
... → A — C ... B — D → ...        (after a 2-opt swap)</code></pre>
<p>The middle segment between <code>B</code> and <code>C</code> gets reversed. The move costs <code>O(1)</code> to evaluate (<code>d(A,C) + d(B,D) − d(A,B) − d(C,D)</code>), and a full pass over all candidate pairs is <code>O(n²)</code>. The algorithm terminates at a local minimum where no swap improves the tour.</p>
<p>In practice 2-opt converges fast and gets within a few percent of the optimum on Euclidean instances. It’s the default starting point for any TSP code.</p>
</section>
<section id="opt-the-bigger-hammer" class="level2">
<h2 class="anchored" data-anchor-id="opt-the-bigger-hammer">3-opt (the bigger hammer)</h2>
<p>3-opt removes three edges instead of two, breaking the tour into three segments <code>A</code>, <code>B</code>, <code>C</code>. There are 8 ways to reconnect them (including the original), of which 4 are real 3-opt moves and 3 are equivalent to 2-opt moves. So you really only have 4 new moves to consider.</p>
<p>The cost-change function compares each reconnection’s total edge weight against the original. Whichever case wins, you splice the segments back in the right order (with some reversed). The cost per move is still <code>O(1)</code> to evaluate; the bottleneck is the <code>O(n³)</code> iteration over edge triples.</p>
<p>A small implementation sketch:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> i, j, k <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> triples(route):</span>
<span id="cb3-2">    best_case, best_gain <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> argmin_cases(graph, route, i, j, k)</span>
<span id="cb3-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> best_gain <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb3-4">        route <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> apply_case(route, i, j, k, best_case)</span></code></pre></div></div>
<p>3-opt finds better local optima than 2-opt, at the cost of <code>n</code> times more work per iteration. Use it when 2-opt is stuck and you can afford the runtime.</p>
</section>
<section id="what-to-use-when" class="level2">
<h2 class="anchored" data-anchor-id="what-to-use-when">What to use when</h2>
<ul>
<li><strong>Small symmetric metric instances, want a guarantee:</strong> Christofides.</li>
<li><strong>Any instance, fast and good enough:</strong> 2-opt from a greedy or random start.</li>
<li><strong>Squeezing the last few percent:</strong> 3-opt, or move to LKH / Concorde for serious work.</li>
</ul>
<p>Full implementations are on <a href="https://github.com/BraveDistribution/pytsp">GitHub: BraveDistribution/pytsp</a>. PRs welcome. The code is years old at this point and could use a Kruskal implementation, better tests, and a benchmark script.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<ul>
<li>Christofides, N. <em>Worst-case analysis of a new heuristic for the travelling salesman problem.</em> CMU Tech Report (1976).</li>
<li>Lin, S.; Kernighan, B. <em>An Effective Heuristic Algorithm for the Traveling-Salesman Problem.</em> Operations Research 21(2), 1973.</li>
<li>Helsgaun, K. <em>An effective implementation of the Lin–Kernighan traveling salesman heuristic.</em> EJOR 126(1), 2000.</li>
<li>TSP basics blog: <a href="https://tsp-basics.blogspot.com/" class="uri">https://tsp-basics.blogspot.com/</a></li>
</ul>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Back to top</a> ]]></description>
  <category>algorithms</category>
  <category>python</category>
  <guid>https://matejgazda.com/posts/tsp-algorithms-2-opt-3-opt-in-python.html</guid>
  <pubDate>Fri, 08 Feb 2019 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
