diff --git a/posts/04-square-joy-trapped-rain-water.tex b/posts/04-square-joy-trapped-rain-water.tex index 45e99bd..e91db19 100644 --- a/posts/04-square-joy-trapped-rain-water.tex +++ b/posts/04-square-joy-trapped-rain-water.tex @@ -2,8 +2,9 @@ \title{Square joy: trapped rainwater} \subtitle{Solving the trapped rainwater problem in J.} +\reddit{https://www.reddit.com/r/apljk/comments/ssyl00/blog_post_square_joy_trapped_rainwater/} \date{2022-02-15} -\modified{2022-02-15} +\modified{2024-03-03} \keyword{j} \keyword{arrays} @@ -11,7 +12,7 @@ \begin{document} \section* -In this article, we will explore one of my favorite programming puzzles using the \href{https://en.wikipedia.org/wiki/Array_programming}{array programming} paradigm. +In this article, we'll explore one of my favorite programming puzzles using the \href{https://en.wikipedia.org/wiki/Array_programming}{array programming} paradigm. \section{the-why}{But why?} @@ -19,29 +20,28 @@ \section{the-why}{But why?} My views on computing changed profoundly when I discovered the array programming paradigm a few years ago. For me, the hardest and the most rewarding part of array programming is coming up with simple idiomatic solutions. -This requires knowledge of many little tricks that array-wrangling wizards developed in their chambers over the last 50 years. +Idiomatic solutions require knowledge of many little tricks array-wrangling wizards developed in their chambers over the last fifty years. I would love to learn or rediscover these tricks, and I hope you might derive some pleasure and insights from reading about my little discoveries. -In this article, we will use the \href{https://www.jsoftware.com/#/}{\sc{j} programming language}. +In this article, we'll use the \href{https://www.jsoftware.com/#/}{\sc{j} programming language}. Why \sc{j} and not, say, \href{https://dyalog.com/}{\sc{apl}}? -\sc{apl} is a great language as well, but I have trouble running it on my machine. -\sc{j} is also much easier to type on most keyboards, and it is \href{https://github.com/jsoftware/jsource}{open source}. +\sc{j} is easier to type on most keyboards, and it's \href{https://github.com/jsoftware/jsource}{open source}. -If you are not familiar with \sc{j}, it will look like line noise to you. -I will explain most of the steps that we make, but it might still look like black magic at times. -That is normal when you are working with \sc{j}. -My goal is not to explain every aspect of the language, but rather demonstrate the approach to problem solving. +The code in this article will look like line noise if you aren't familiar with \sc{j}. +Don't be discouraged; this reaction is typical when working with \sc{j}. +I'll explain most of the steps, but the steps might still look like black magic sometimes. +My goal is not to explain every aspect of the language but to demonstrate the problem-solving approach. Time to have some fun! \section{the-problem}{The problem: heavy rains in Flatland} -Imagine that we live in a two-dimensional city, where all buildings have the same unit width and stand next to one another. -We do not like rains very much: the two-dimensional water gets stuck between the buildings forever, forming pools. -As the city architects, we know the heights in units of all the buildings. -We need to compute how much water (in square units) gets accumulated between the buildings after heavy rain. +Imagine living in a two-dimensional city where all buildings have the same unit width and stand next to one another. +We don't like rain very much: the two-dimensional water gets stuck between the buildings forever, forming pools. +As city architects, we know the heights in units of all the buildings. +We need to compute how much water (in square units) accumulates between the buildings after heavy rain. -More dryly: given an array of non-negative integers \em{H}, representing heights of unit-width bars placed next to one another, compute the total area of water trapped by the configuration after it rains. +More dryly: given an array of non-negative integers \em{H}, representing heights of unit-width bars placed next to one another, compute the total area of water trapped by the configuration after a rain. \subsection{example-2d}{Example} \begin{tabular*}{r l} @@ -58,35 +58,35 @@ \subsection{example-2d}{Example} \section{a-solution}{A solution} -A natural question to ask is what is the water level above each bar? +A natural first question is: what is the water level above each bar? If we knew that, summing contributions of levels above each bar would give us the answer. -So let us focus on a bar at an arbitrary index \math{i}. +So, let's focus on the bar at an arbitrary index \math{i}. What would stop the water from flowing out? -A bar that is higher than \math{H\[i\]}. +Another bar that is higher than \math{H\[i\]}. Furthermore, we need bars higher than \math{H\[i\]} on \em{both} sides of \math{i} for the water to stay. -So the level of water at index \math{i} is determined by the minimum of the highest bars on the left and on the right. +So, the water level at index \math{i} is determined by the minimum of the highest bars on the left and right. Computing the highest bar to the left and to the right for each index is not efficient: we would need to make \math{O(N\sup{2})} steps. -Luckily, there is a lot of duplication in this computation that we can eliminate. -Instead of running the search from each position in the array, we can precompute left and right maxima all positions in two sweeps. +Luckily, we can eliminate a lot of duplication in this computation. +Instead of running the search from each position in the array, we can precompute the left and right maxima for all positions in two sweeps. The algorithm to compute the running left maximum is called \href{https://en.wikipedia.org/wiki/Prefix_sum}{prefix scan}. We can compute the right maximum by running the same scan from right to left (i.e., performing a suffix scan). Taking the minimum of precomputed left and right maxima gives us the water level at each point. -The difference between the water level and the bar height gives us the amount of water trapped at this position. -Summing up these amounts gives us the answer. +The difference between the water level and the bar height gives us the volume of water trapped at this position. +Summing up all volumes gives us the answer. \section{translating-to-j}{Translating our idea to J} \sc{j} is an interpreted language and it has a \href{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop}{\sc{repl}}. -It is quite common for \sc{j} programmers to build solutions incrementally by trying snippets of code in the \sc{repl} and observing the effects. +It's pretty standard for \sc{j} programmers to build solutions incrementally by trying snippets of code in the \sc{repl} and observing the effects. The code in this article is also an interactive \sc{repl} session that you can replicate locally. Let us get some data to play with. \begin{code}[j] NB. Comments start with the symbol NB. - NB. I will use PascalCase for data (“nouns”) + NB. I use PascalCase for data (“nouns”) NB. and snake_case for functions (“verbs”). NB. User input is indented. @@ -108,7 +108,7 @@ \section{translating-to-j}{Translating our idea to J} Wait, where is all the code? Let me break it down. In \sc{j}, \href{https://code.jsoftware.com/wiki/Vocabulary/gtdot#dyadic}{\code{>.} (max)} is a verb (\sc{j} word for "function") that, when you use it dyadically (\sc{J} word for ``with two arguments''), computes the maximum of the arguments. -It is easy to guess that \href{https://code.jsoftware.com/wiki/Vocabulary/ltdot#dyadic}{\code{<.} (min)} is an analogous verb that computes the minimum. +It's easy to guess that \href{https://code.jsoftware.com/wiki/Vocabulary/ltdot#dyadic}{\code{<.} (min)} is an analogous verb that computes the minimum. The single character \href{https://code.jsoftware.com/wiki/Vocabulary/slash}{\code{/} (insert)} is an adverb (\sc{j} word for ``function modifier'') that takes a dyadic verb to the left and turns it into a verb that folds an entire array. Why is it called ``insert''? @@ -144,7 +144,7 @@ \section{translating-to-j}{Translating our idea to J} 0 1 1 2 2 2 2 3 2 2 2 1 \end{verbatim} -Now we need to subtract the bar heights and sum up the results. +We need to subtract the bar heights and sum up the results. We can get away with tools that we already know: \begin{verbatim}[j] @@ -158,9 +158,9 @@ \section{translating-to-j}{Translating our idea to J} 6 \end{verbatim} -This is a remarkably short solution. +This solution is remarkably concise. Believe it or not, we can make it even shorter. -Look at the argument that we have to repeat three times, and at all these parentheses. +Look at the argument we repeated three times and at all these parentheses! If only we could move some of those out\ldots \begin{verbatim}[j] @@ -169,7 +169,7 @@ \section{translating-to-j}{Translating our idea to J} \end{verbatim} Such terse expressions that combine functions without mentioning their arguments are called \href{https://www.jsoftware.com/help/jforc/tacit_programs.htm}{tacit}. -I will not explain here how to form these expressions, but I encourage you to learn more about it on your own. +I won't explain how to form these expressions here, but I encourage you to learn more about tacit programming independently. Let us bind our beautiful tacit expression to a name. @@ -180,25 +180,25 @@ \section{translating-to-j}{Translating our idea to J} \end{verbatim} The full implementation of our idea now fits into 12 \sc{ascii} characters. -One of the interesting properties of array languages is that often it is not worth it to name functions. -Their full body is shorter and more expressive than any name you can come up with. +One surprising property of array languages is that it's often not worth naming functions. +Their entire body is shorter and more expressive than any name we could come up with. \section{drawing-solutions}{Drawing solutions} -Knowing the answer is great, but being able to \em{see} it at a glance would be even better. -In this section, we will write some code to represent our solutions visually. +Knowing the answer is excellent, but being able to \em{see} it at a glance would be even better. +In this section, we'll write code to represent solutions visually. What would we like to see in that picture? -We want to tell the space from the buildings, and from the water pools. +We want to tell the space from the buildings and water pools. Let us start by drawing the original problem first. -We know how to compute maxima, that is just \code{>./ H}. +We know how to compute maxima: \code{>./ H}. Now we need to build a matrix \math{max(H)} rows by \math{length(H)} columns. The idiomatic way of doing this is using our old friend \href{https://code.jsoftware.com/wiki/Vocabulary/slash#dyadic}{\code{/} (table)} in a new disguise. When used as \code{noun1 verb/ noun1}, slash builds a \math{length(noun1)} by \math{length(noun2)} table, where each cell \math{i, j} is filled with the value computed as \math{noun1\[i\] verb noun2\[j\]}. -Let us make a multiplication table to get some feel of how it works. -We will also need \href{https://code.jsoftware.com/wiki/Vocabulary/idot}{\code{i.} (integers)}, the function that takes an integer and makes an arithmetic progression of that length starting at zero. +Let's make a multiplication table to understand how it works. +We'll also need \href{https://code.jsoftware.com/wiki/Vocabulary/idot}{\code{i.} (integers)}, the function that takes an integer and makes an arithmetic progression of the specified length starting at zero. \begin{code}[j] i. 10 @@ -221,11 +221,11 @@ \section{drawing-solutions}{Drawing solutions} 0 9 18 27 36 45 54 63 72 81 \end{code} -Note that there is no special boolean type in array languages. -They use integers instead: false is zero and true is one. +Note that there is no particular boolean type in array languages. +They use integers instead: false is zero, and true is one. \begin{code}[j] - NB. Here we build a table of using the verb “less” (<). + NB. Here, we build a table using the verb “less” (<). (i. 5) ./) ./\ <. >./\.)) + (i.@-@:(>./) . ((_1 & (|.!.0)) <. (1 & (|.!.0)) <. (_1 & (|.!.0)"1) <. (1 & (|.!.0)"1)) \end{verbatim} -To apply this function iteratively, we will use the \href{https://code.jsoftware.com/wiki/Vocabulary/hatco}{\code{^:} (power of verb)} conjunction (another \sc{j} word for ``verb modifier''). +To apply this function iteratively, we'll use the \href{https://code.jsoftware.com/wiki/Vocabulary/hatco}{\code{^:} (power of verb)} conjunction (another \sc{j} word for ``verb modifier''). If we raise a verb to power \math{N}, we get a verb that applies the original verb \math{N} times in a row. If we raise a verb to infinite power \href{https://code.jsoftware.com/wiki/Vocabulary/under}{\code{_} (infinity)}, the original verb gets applied until the computation reaches a fixed point. @@ -577,11 +580,11 @@ \section{back-to-2d}{Looking back at Flatland} Did we learn anything new about the Flatland after considering three dimensions? Yes: for each shortest path algorithm, there is an analogous solution for the two-dimensional case. -For example, the analog of the Bellmann-Ford algorithm looks like this: +For example, the analog of the Bellmann-Ford algorithm involves the following steps: \begin{itemize} \item Start with an array of the same shape as the input filled with infinities. \item - For each position, compute the minimum of the left and the right neighbors. + For each position, compute the minimum of its left and right neighbors. Take the maximum of that value and the height at this position. \item Repeat the previous step until convergence. \end{itemize} @@ -592,10 +595,10 @@ \section{back-to-2d}{Looking back at Flatland} 0 1 1 2 2 2 2 3 2 2 2 1 \end{code} -If it was the first solution I heard, I would be quite surprised that it works. -But once the three-dimensional case paved the way, this solution looks very natural, almost obvious. +I don't know about you, but if it were the first solution I heard of, I would be surprised it works. +But once the three-dimensional case paved the way, this solution looks natural and almost obvious. -What would be the analog of the Dijkstra algorithm then? +What would be the analog of the Dijkstra algorithm, then? Dijkstra gives rise to a very efficient ``two-pointer'' solution: \begin{itemize} @@ -603,12 +606,12 @@ \section{back-to-2d}{Looking back at Flatland} \item Keep track of the lowest boundary so far. \item Always move the pointer that looks at the lowest height. - The left pointer moves to the right, the right pointer moves to the left. - \item If one of the two pointers looks at height \em{M} that is greater than the lowest boundary, update the lowest boundary to be \em{M}. + The left pointer moves to the right; the right pointer moves to the left. + \item If one of the two pointers looks at height \em{M} greater than the lowest boundary, update the lowest boundary to be \em{M}. \end{itemize} -That is exactly how a Dijkstra graph search would propagate, always picking the shortest edge to proceed. -This solution does not map naturally to array languages, so I will write it below in C. +That is precisely how a Dijkstra graph search would propagate, always picking the shortest edge to proceed. +This solution does not map naturally to array languages, so I implemented it below in C. \begin{figure} \marginnote{mn-c-dijkstra}{The equivalent of the Dijkstra algorithm in the two-dimensional case.} @@ -633,12 +636,12 @@ \section{back-to-2d}{Looking back at Flatland} \end{figure} \section{where-to-go-next}{Where to go next} -That is all J magic for today! +That was all the \sc{j} magic for today! If you are confused and intrigued, I can recommend the following resources: \begin{itemize} \item Solve this problem on \href{https://leetcode.com/problems/trapping-rain-water/}{Leetcode}. - \item Watch \href{https://youtu.be/ftcIcn8AmSY}{Four Solutions to a Trivial Problem}, a talk by Guy Steele where he explores the same problem from different angles. + \item Watch \href{https://youtu.be/ftcIcn8AmSY}{Four Solutions to a Trivial Problem}, a talk by Guy Steele where he explores the problem from different angles. \item Read some \href{https://code.jsoftware.com/wiki/Books}{Books on \sc{j}}. \item Listen to the \href{https://arraycast.com/}{Arraycast podcast}. \end{itemize} diff --git a/posts/17-scaling-rust-builds-with-bazel.tex b/posts/17-scaling-rust-builds-with-bazel.tex index a87329a..933e1ba 100644 --- a/posts/17-scaling-rust-builds-with-bazel.tex +++ b/posts/17-scaling-rust-builds-with-bazel.tex @@ -2,6 +2,7 @@ \title{Scaling Rust builds with Bazel} \subtitle{Why DFINITY builds Rust with Bazel.} +\reddit{https://www.reddit.com/r/rust/comments/11xxffc/blog_post_scaling_rust_builds_with_bazel/} \date{2023-03-20} \modified{2023-03-20}