{"id":505,"date":"2022-09-02T04:03:36","date_gmt":"2022-09-02T04:03:36","guid":{"rendered":"https:\/\/timallanwheeler.com\/blog\/?p=505"},"modified":"2022-09-02T04:04:59","modified_gmt":"2022-09-02T04:04:59","slug":"embedded-contours-with-marching-squares","status":"publish","type":"post","link":"https:\/\/timallanwheeler.com\/blog\/2022\/09\/02\/embedded-contours-with-marching-squares\/","title":{"rendered":"Embedded Contours with Marching Squares"},"content":{"rendered":"\n<p>I recently started working on new chapters for <a href=\"https:\/\/algorithmsbook.com\/optimization\/\">Algorithms for Optimization<\/a>, starting with a new chapter on quadratic programs. We already have a chapter on linear programs, but quadratic programs are sufficiently different and are ubiquitous enough that giving them their own chapter felt warranted.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"682\" height=\"282\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-9.png\" alt=\"\" class=\"wp-image-506\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-9.png 682w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-9-300x124.png 300w\" sizes=\"auto, (max-width: 682px) 100vw, 682px\" \/><figcaption>A simple example quadratic program.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The chapter starts with a general formulation for quadratic programs and transforms the problem a few times into simpler and simpler formulations, until we get a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Non-negative_least_squares\">nonnegative least squares problem<\/a>. This can be solved, and then we can use that solution to back our way up the transform stack back to a solution of our original solution.<\/p>\n\n\n\n<p>In texts, these problem transforms are typically solely the realm of mathematical manipulations. While math is of course necessary, I also tried hard to depict what these various problem representations looked like to help build an intuitive understanding of what some of the transformations were. In particular, there was one figure where I wanted to show how the equality constraints of a general-form quadratic program could be removed when formulating a lower-dimensional least squares program:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"431\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1-1024x431.png\" alt=\"\" class=\"wp-image-508\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1-1024x431.png 1024w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1-300x126.png 300w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1-768x323.png 768w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1.png 1176w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>A 3d general-form quadratic program with an equality constraint on the left, and a 2d least squares program on the right.<\/figcaption><\/figure>\n\n\n\n<p>This post is about this figure, and more specifically, about the blue contour lines on the left side.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is this Figure?<\/h2>\n\n\n\n<p>The figure on left shows the following quadratic program:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_342.png\" alt=\"\" class=\"wp-image-509\" width=\"304\" height=\"236\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_342.png 626w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_342-300x233.png 300w\" sizes=\"auto, (max-width: 304px) 100vw, 304px\" \/><figcaption>general-form quadratic program<\/figcaption><\/figure>\n<\/div>\n\n\n<p>As we can see, the quadratic program is constrained to lie within a square planar region \\(0 \\leq x \\leq 1\\), \\(0 \\leq x_3 \\leq 1\\), and \\(x_2 = x_3\\).  The feasible set is shown in blue.<\/p>\n\n\n\n<p>The right figure on the right shows the least-squares program that we get when we factor out the equality constraint. No need to get into the details here, it isn&#8217;t really important for this post, but we can use our one equality equation to remove one variable in our original problem, producing a 2d problem without any equality constraints:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_343.png\" alt=\"\" class=\"wp-image-513\" width=\"413\" height=\"199\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_343.png 741w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_343-300x145.png 300w\" sizes=\"auto, (max-width: 413px) 100vw, 413px\" \/><figcaption>least squares program<\/figcaption><\/figure>\n<\/div>\n\n\n<p>The original feasible set is rotated and stretched, and the objective function contours are rotated and stretched, but other than that we have a similar topology and a pretty standard problem that we can solve.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How do we Make the Figures?<\/h2>\n\n\n\n<p>I make the plots with<a href=\"https:\/\/github.com\/JuliaTeX\/PGFPlots.jl\"> PGFPlots.jl<\/a>, which uses the <a href=\"http:\/\/pgfplots.sourceforge.net\/\">pgfplots<\/a> LaTeX package under the hood. It is a nice synergy of Julia coding and LaTeX within the LaTeX textbook.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Right Plot<\/h3>\n\n\n\n<p>The right plot is pretty straight forward. It has a contour plot for the objective function:<\/p>\n\n\n\n<pre lang=\"julia\">Plots.Contour(x -> norm(A_lsi*x - b_lsi, 2),\n              xdomain, ydomain, xbins=600, ybins=600)<\/pre>\n\n\n\n<p>some over + under line plots and a fill-between for the feasible region:<\/p>\n\n\n\n<pre lang=\"julia\">x1_domain_feasible = (0.0, (0.5+\u221a2)\/2)\npush!(plots,\n      Plots.Linear(x1->max(-x1, x1 - sqrt(2)), x1_domain_feasible,\n                   style=\"name path=A, draw=none, mark=none\"))\npush!(plots,\n      Plots.Linear(x1->min(x1, 1\/2-x1), x1_domain_feasible,\n                   style=\"name path=B, draw=none, mark=none\"))\npush!(plots,\n      Plots.Command(\"\\\\addplot[pastelBlue!50] fill between[of=A and B]\"))<\/pre>\n\n\n\n<p>and a single-point scatter plot plus a label for the solution:<\/p>\n\n\n\n<pre lang=\"julia\">push!(plots,\n      Plots.Scatter([x_val[1]], [x_val[2]],\n      style=\"mark=*, mark size=1.25, mark options={solid, draw=black, fill=black}\"))\npush!(plots,\n      Plots.Command(\"\\\\node at (axis cs:$(x_val[1]),$(x_val[2])) [anchor=west] {\\\\small \\\\textcolor{black}{\\$y_2^\\\\star\\$}}\"))<\/pre>\n\n\n\n<p>These plots get added to an <code>Axis<\/code> and we&#8217;ve got our plot.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Left Plot<\/h3>\n\n\n\n<p>The left plot is in 3D. If we do away with the blue contour lines, its actually even simpler than the right plot. We simply have a square patch, a single-point scatter plot, and our label:<\/p>\n\n\n\n<pre lang=\"julia\">Axis([\n   Plots.Command(\"\\\\addplot3[patch,patch type=rectangle, faceted color=none, color=pastelBlue!40] coordinates {(0,0,0) (1,0,0) (1,1,1) (0,1,1)}\"),\n   Plots.Linear3([x_val[1]], [x_val[2]], [x_val[3]], mark=\"*\", style=\"mark size=1.1, only marks, mark options={draw=black, fill=black}\"),\n   Plots.Command(\"\\\\node at (axis cs:$(x_val[1]),$(x_val[2]),$(x_val[3])) [anchor=west] {\\\\small \\\\textcolor{black}{\\$x^\\\\star\\$}}\"),\n  ], \n  xlabel=L\"x_1\", ylabel=L\"x_2\", zlabel=L\"x_3\", width=\"1.2*$width\", \n  style=\"view={45}{20}, axis equal\",\n  legendPos=\"outer north east\"\n)<\/pre>\n\n\n\n<p>The question is &#8211; how do we create that contour plot, and how do we get it to lie on that blue patch?<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"253\" height=\"202\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-10.png\" alt=\"\" class=\"wp-image-514\"\/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">How do you Draw Contours?<\/h2>\n\n\n\n<p>Contour plots don&#8217;t seem difficult to plot, until you have to sit down and plot them. They are just lines of constant elevation &#8211; in this cases places where \\(\\|Ax &#8211; b\\| = c\\) for various constants \\(c\\). But, unlike line plots, where you can just increase \\(x\\) left to right and plot successive \\((x, f(x))\\) pairs, for contour plots you don&#8217;t know where your line is going to be ahead of time. And that&#8217;s assuming you only have one line per contour value &#8211; you might have multiple:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"260\" height=\"259\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-11.png\" alt=\"\" class=\"wp-image-520\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-11.png 260w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-11-150x150.png 150w\" sizes=\"auto, (max-width: 260px) 100vw, 260px\" \/><figcaption>A contour plot with multiple contour lines per level.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>So, uh, how do we do this?<\/p>\n\n\n\n<p>The first thing I tried was trying to write my function out the traditional way &#8211; as \\((x_1, f(x_1))\\) pairs. Unfortunately, this doesn&#8217;t work out, because the contours aren&#8217;t 1:1.<\/p>\n\n\n\n<p>The second thing I briefly considered was a search method. If I fix my starting point, say, \\(x_1 = 0, x_2 = 0.4\\), I can get the contour level \\(c = \\|Ax &#8211; b\\| \\). Then, I could search toward the right in an arc to find where the next contour line was, maybe bisect over an arc one step distance away and proceed that way:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"793\" height=\"153\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/09\/Selection_371.png\" alt=\"\" class=\"wp-image-548\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/09\/Selection_371.png 793w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/09\/Selection_371-300x58.png 300w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/09\/Selection_371-768x148.png 768w\" sizes=\"auto, (max-width: 793px) 100vw, 793px\" \/><figcaption>An iterative search procedure for following a contour line, proceeding left to right.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>I think this approach would have worked for this figure, since there were never multiple contour lines for the same contour value, but it would have been more finicky, especially around the boundaries, and it would not have generalized to other figures.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Marching Squares<\/h2>\n\n\n\n<p>I happened upon a talk by Casey Muratori on YouTube, &#8220;<a href=\"https:\/\/www.youtube.com\/watch?v=SDS5gLSiLg0&amp;ab_channel=PapersWeLove\">Papers I have Loved<\/a>&#8220;, a few weeks ago. One of the papers Casey talked about was <em>Marching Cubes, A High Resolution 3D Surface Construction Algorithm. <\/em>This 1987 paper by W. Lorenson and H. Cline presented a very simply way to generate surfaces (in 3D or 2D) in places of constant value: \\(f(x) = c\\).<\/p>\n\n\n\n<p>Casey talked about it in the context of rendering <em>metaballs<\/em>, but when I found myself presented with the contour problem, it was clear that marching cubes (or squares, rather, since its 2d) was relevant here too.<\/p>\n\n\n\n<p>The algorithm is a simple idea elegantly applied.<\/p>\n\n\n\n<p>The contour plot we want to make is on a 2d surface in a 3d plot, but let&#8217;s just consider the 2d surface for now. Below we show that feasible square along with our objective function, \\(f(x) = \\|Ax &#8211; b\\|\\):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"371\" height=\"363\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_349.png\" alt=\"\" class=\"wp-image-523\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_349.png 371w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_349-300x294.png 300w\" sizes=\"auto, (max-width: 371px) 100vw, 371px\" \/><figcaption>An image plot showing our object function. We want to find contour lines.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Our objective is to produce contour lines, the same sort as are produced when we make a PGFPlots contour plot:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"374\" height=\"366\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_350.png\" alt=\"\" class=\"wp-image-525\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_350.png 374w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_350-300x294.png 300w\" sizes=\"auto, (max-width: 374px) 100vw, 374px\" \/><\/figure>\n<\/div>\n\n\n<p>We already know that there might be multiple connected contour lines for a given level, so a local search method won&#8217;t be sufficient. Instead, marching squares uses a global approach combined with local refinement.<\/p>\n\n\n\n<p>We begin by evaluating a grid of points over our plot:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"364\" height=\"356\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_351.png\" alt=\"\" class=\"wp-image-526\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_351.png 364w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_351-300x293.png 300w\" sizes=\"auto, (max-width: 364px) 100vw, 364px\" \/><\/figure>\n<\/div>\n\n\n<p>We&#8217;ll start with a small grid, but for higher-quality images we&#8217;d make it finer.<\/p>\n\n\n\n<p>Let&#8217;s focus on the contour line \\(f(x) = 3\\). We now determine, for each vertex in our mesh, whether its value is above or below our contour target of 3. (I&#8217;ll plot the contour line too for good measure):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_352.png\" alt=\"\" class=\"wp-image-527\" width=\"372\" height=\"362\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_352.png 372w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_352-300x292.png 300w\" sizes=\"auto, (max-width: 372px) 100vw, 372px\" \/><figcaption>Blue points are where the objective function &lt;= 3, and yellow points are where it is &gt; 3.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Marching squares will now tile the image based on each 4-vertex square, and the binary values we just evaluated. Any squares with all vertices equal can simply be ignored &#8211; the contour line doesn&#8217;t pass through them. This leaves the following tiles:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"366\" height=\"369\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_364.png\" alt=\"\" class=\"wp-image-540\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_364.png 366w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_364-298x300.png 298w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_364-150x150.png 150w\" sizes=\"auto, (max-width: 366px) 100vw, 366px\" \/><figcaption>The white tiles are those that contain our contour line(s).<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Now, each remaining tile comes in multiple possible &#8220;flavors&#8221; &#8211; the various ways that its vertices can be above or below the objective value. There are \\(2^4\\) possible tiles, two of which we&#8217;ve already discarded, leaving 14 options. The <a href=\"https:\/\/en.wikipedia.org\/wiki\/Marching_squares\">Wikipedia article<\/a> has a great  set of images showing all of the tile combinations, but here we will concern ourselves with two more kinds: tiles with one vertex below or one vertex above, and tiles with two neighboring vertices above and two neighboring vertices below:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"371\" height=\"361\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_362.png\" alt=\"\" class=\"wp-image-537\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_362.png 371w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_362-300x292.png 300w\" sizes=\"auto, (max-width: 371px) 100vw, 371px\" \/><figcaption>The white squares have one vertex above or one vertex below. The gray squares have two neighboring vertices above and two neighboring vertices below. <\/figcaption><\/figure>\n<\/div>\n\n\n<p>Let&#8217;s start with the first type. These squares have two edges where the function value changes. We know, since we&#8217;re assuming our objective function is continuous, that our contour line must pass through those edges. As such, if we run a bisection search along each of those edges, we can quickly identify those crossing points:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"370\" height=\"364\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_361.png\" alt=\"\" class=\"wp-image-536\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_361.png 370w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_361-300x295.png 300w\" sizes=\"auto, (max-width: 370px) 100vw, 370px\" \/><figcaption>The red points are where bisection search has found a crossing point.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>We then get our contour plot, for this particular contour value, by drawing all of the line segments between these crossing points:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"367\" height=\"360\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_360.png\" alt=\"\" class=\"wp-image-535\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_360.png 367w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_360-300x294.png 300w\" sizes=\"auto, (max-width: 367px) 100vw, 367px\" \/><\/figure>\n<\/div>\n\n\n<p>We can get higher resolution contour lines by using a finer grid:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"363\" height=\"366\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-18.png\" alt=\"\" class=\"wp-image-538\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-18.png 363w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-18-298x300.png 298w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/image-18-150x150.png 150w\" sizes=\"auto, (max-width: 363px) 100vw, 363px\" \/><figcaption>The same contour line with double the resolution.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>To get our full contour plot, we simply run marching squares on multiple contour levels. To get the original plot, I run this algorithm to get all of the little tile line segments, then I render them as separate Linear3 line segments on top of the 3d patch. Pretty cool!<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"431\" src=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1-1024x431.png\" alt=\"\" class=\"wp-image-508\" srcset=\"https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1-1024x431.png 1024w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1-300x126.png 300w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1-768x323.png 768w, https:\/\/timallanwheeler.com\/blog\/wp-content\/uploads\/2022\/08\/Selection_341-1.png 1176w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>The created figure<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">What does the Code Look Like?<\/h2>\n\n\n\n<p>The code for marching squares is pretty elegant.<\/p>\n\n\n\n<p>We start off with defining our grid:<\/p>\n\n\n\n<pre lang=\"julia\">nbins = 41\nx1s = collect(range(0.0, stop=1.0, length=nbins))\nx2s = collect(range(0.0, stop=1.0, length=nbins))\nis_above = falses(length(x1s), length(x2s))<\/pre>\n\n\n\n<p>Next we define a bisection method for quickly interpolating between two vertices:<\/p>\n\n\n\n<pre lang=\"julia\">function bisect(\n    u_target::Float64, x1_lo::Float64, x1_hi::Float64, \n    x2_lo::Float64, x2_hi::Float64, k_max::Int=8)\n    f_lo = norm(A*[x1_lo, x2_lo, x2_lo]-b)\n    f_hi = norm(A*[x1_hi, x2_hi, x2_hi]-b)\n    \n    if f_lo > f_hi # need to swap low and high\n        x1_lo, x1_hi, x2_lo, x2_hi = x1_hi, x1_lo, x2_hi, x2_lo\n    end\n    \n    x1_mid = (x1_hi + x1_lo)\/2\n    x2_mid = (x2_hi + x2_lo)\/2\n    for k in 1 : k_max\n        f_mid = norm(A*[x1_mid, x2_mid, x2_mid] - b)\n        if f_mid > u_target\n            x1_hi, x2_hi, f_hi = x1_mid, x2_mid, f_mid\n        else\n            x1_lo, x2_lo, f_lo = x1_mid, x2_mid, f_mid\n        end\n        x1_mid = (x1_hi + x1_lo)\/2\n        x2_mid = (x2_hi + x2_lo)\/2\n    end\n    \n    return (x1_mid, x2_mid)\nend<\/pre>\n\n\n\n<p>In this case I&#8217;ve baked in the objective function, but you could of course generalize this and pass one in.<\/p>\n\n\n\n<p>We then iterate over our contour levels. For each contour level (u_target), we evaluate the grid and  then evaluate all of our square patches and add little segment plots as necessary:<\/p>\n\n\n\n<pre lang=\"julia\">for (i,x1) in enumerate(x1s)\n    for (j,x2) in enumerate(x2s)\n        is_above[i,j] = norm(A*[x1, x2, x2] - b) > u_target\n    end\nend\nfor i in 2:length(x1s)\n    for j in 2:length(x2s)\n        # bottom-right, bottom-left, top-right, top-left\n        bitmask = 0x00\n        bitmask |= (is_above[i,j-1] << 3)\n        bitmask |= (is_above[i-1,j-1] << 2)\n        bitmask |= (is_above[i,j] << 1)\n        bitmask |= (is_above[i-1,j])\n        plot = true\n        x1_lo1 = x1_hi1 = x2_lo1 = x2_hi1 = 0.0\n        x1_lo2 = x1_hi2 = x2_lo2 = x2_hi2 = 0.0\n        if bitmask == 0b1100 || bitmask == 0b0011\n            # horizontal cut\n            x1_lo1, x1_hi1, x2_lo1, x2_hi1 = x1s[i-1], x1s[i-1], x2s[j-1], x2s[j]\n            x1_lo2, x1_hi2, x2_lo2, x2_hi2 = x1s[i], x1s[i], x2s[j-1], x2s[j]\n        elseif bitmask == 0b0101 || bitmask == 0b1010\n            # vertical cut\n            x1_lo1, x1_hi1, x2_lo1, x2_hi1 = x1s[i-1], x1s[i], x2s[j-1], x2s[j-1]\n            x1_lo2, x1_hi2, x2_lo2, x2_hi2 = x1s[i-1], x1s[i], x2s[j], x2s[j]\n        elseif bitmask == 0b1000 || bitmask == 0b0111\n            # cut across bottom-right\n            x1_lo1, x1_hi1, x2_lo1, x2_hi1 = x1s[i-1], x1s[i], x2s[j-1], x2s[j-1]\n            x1_lo2, x1_hi2, x2_lo2, x2_hi2 = x1s[i], x1s[i], x2s[j-1], x2s[j]\n        elseif bitmask == 0b0100 || bitmask == 0b1011\n            # cut across bottom-left\n            x1_lo1, x1_hi1, x2_lo1, x2_hi1 = x1s[i-1], x1s[i], x2s[j-1], x2s[j-1]\n            x1_lo2, x1_hi2, x2_lo2, x2_hi2 = x1s[i-1], x1s[i-1], x2s[j-1], x2s[j]\n        elseif bitmask == 0b0010 || bitmask == 0b1101\n            # cut across top-right\n            x1_lo1, x1_hi1, x2_lo1, x2_hi1 = x1s[i-1], x1s[i], x2s[j], x2s[j]\n            x1_lo2, x1_hi2, x2_lo2, x2_hi2 = x1s[i], x1s[i], x2s[j-1], x2s[j]\n        elseif bitmask == 0b0001 || bitmask == 0b1110\n            # cut across top-left\n            x1_lo1, x1_hi1, x2_lo1, x2_hi1 = x1s[i-1], x1s[i], x2s[j], x2s[j]\n            x1_lo2, x1_hi2, x2_lo2, x2_hi2 = x1s[i-1], x1s[i-1], x2s[j-1], x2s[j]\n        else\n            plot = false\n        end\n        if plot\n            x1a, x2a = bisect(u_target, x1_lo1, x1_hi1, x2_lo1, x2_hi1)\n            x1b, x2b = bisect(u_target, x1_lo2, x1_hi2, x2_lo2, x2_hi2)\n            push!(contour_segments, \n                Plots.Linear3([x1a, x1b], [x2a, x2b], [x2a, x2b],\n                               style=\"solid, pastelBlue, mark=none\")\n            )\n        end\n    end\nend<\/pre>\n\n\n\n<p>In this code, all we ever do is figure out which two line segments to bisect over, and if we get then, run the bisection and plot the ensuing line. Its actually quite neat and compact.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>So there you have it - a home-rolled implementation for contour plotting turns out to be useful for embedding 2d contours in a 3d plot.<\/p>\n\n\n\n<p>Note that the implementation here wasn't <span id=\"su_tooltip_6a044ccaf184c_button\" class=\"su-tooltip-button su-tooltip-button-outline-yes\" aria-describedby=\"su_tooltip_6a044ccaf184c\" data-settings='{\"position\":\"top\",\"behavior\":\"hover\",\"hideDelay\":0}' tabindex=\"0\"><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">truly general<\/mark><\/span><span style=\"display:none;z-index:100\" id=\"su_tooltip_6a044ccaf184c\" class=\"su-tooltip\" role=\"tooltip\"><span class=\"su-tooltip-inner su-tooltip-shadow-no\" style=\"z-index:100;background:#222222;color:#FFFFFF;font-size:16px;border-radius:5px;text-align:left;max-width:300px;line-height:1.25\"><span class=\"su-tooltip-title\"><\/span><span class=\"su-tooltip-content su-u-trim\">Which is fine - it was sufficient to generate the figure. As long as we are aware of where we cut corners, we are okay.<\/span><\/span><span id=\"su_tooltip_6a044ccaf184c_arrow\" class=\"su-tooltip-arrow\" style=\"z-index:100;background:#222222\" data-popper-arrow><\/span><\/span>. In this case, we didn't handle some tile types, namely those where opposing corners have the same aboveness, but neighboring corners have differing aboveness. In those cases, we need to bisect across all four segments, and we typically need to remove ambiguity by sampling in the tile's center to determine which way the segments cross.<\/p>\n\n\n\n<p>I find it really satisfying to get to apply little bits of knowledge like this from time to time. Its part of computer programming that is endlessly rewarding. I have often been amazed by how a technique that I learned about in one context surprised me by being relevant in something else later on.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I recently started working on new chapters for Algorithms for Optimization, starting with a new chapter on quadratic programs. We already have a chapter on linear programs, but quadratic programs are sufficiently different and are ubiquitous enough that giving them their own chapter felt warranted. The chapter starts with a general formulation for quadratic programs [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-505","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/posts\/505","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/comments?post=505"}],"version-history":[{"count":31,"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/posts\/505\/revisions"}],"predecessor-version":[{"id":560,"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/posts\/505\/revisions\/560"}],"wp:attachment":[{"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/media?parent=505"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/categories?post=505"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/timallanwheeler.com\/blog\/wp-json\/wp\/v2\/tags?post=505"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}