Jekyll2018-07-15T15:12:49-04:00http://coollog.me/coollog.meBlogging about things I like to think about.Qingyang Chenqingyang.chen@gmail.comMy favorite protocol that makes the Internet useful2018-06-18T20:12:11-04:002018-06-18T20:12:11-04:00http://coollog.me/computer-science/my-favorite-protocol-that-makes-the-internet-useful<p>I remember when I was first dabbling in making online multiplayer video games. I ran into many issues of people “hacking” my game and stealing players’ passwords. Of course, this was a major issue, but I at the time had no clue how these “hackers” could get ahold of the passwords. It was later that I realized that all data sent over the Internet is public. Anyone could see the data that my game’s server sent to the players and vice versa. Whenever a player logged in, their game would send their password to my server for verification. This data was sent over the Internet, and anyone watching would be able to see the password.</p>
<p>So, I had a question.</p>
<p><em>If anything sent on the Internet could be seen by anyone, how are we able to do anything secure?</em></p>
<p>How are we able to log in to websites without others seeing our secret information? How are we able to read our emails without others being able to read them as well? How are we able to process financial transactions over the Internet?</p>
<p>At the time I had no clue. I vaguely remember reading some articles about <a href="https://www.google.com/search?q=secure+sockets+layer">SSL</a> and something about public and private keys, but I didn’t really understand how it all worked. It was not until I took a cryptography course in college that I discovered the protocol behind it all - the Diffie-Hellman key exchange.</p>
<p>To explain this protocol, I’ll present it as a puzzle.</p>
<p><em>Let’s pretend there’s 3 people - Alice, Bob, and Eve - sitting at a table. Alice and Bob want to agree on something without Eve knowing. Since they are all at the same table, anything Alice communicates to Bob and vice versa, Eve gets to know as well. Each person can also turn their backs to do things in secret, which no-one else can see. How can Alice and Bob achieve this?</em></p>
<p><img src="/../../assets/images/posts/table_alice_bob_eve.png" alt="table with Alice, Bob, and Eve" class="align-center" style="max-width: 400px;" /></p>
<p>Of course, neither Alice nor Bob would have any prior agreement Eve does not. This means that this is a symmetric system, where all participants are equal in terms of information. However, the goal is to have a protocol that can achieve informational asymmetry.</p>
<p>At first, this might seem impossible. How can Alice and Bob agree on something only they know when Eve can listen in on their whole conversation? Wouldn’t that mean that Eve would always have the same information as Alice and Bob? And thus there’s no way of breaking the information symmetry?</p>
<p>But there is a way. The key is that Alice and Bob can do things in <em>private</em>. The private actions break the overall information symmetry of the system.</p>
<p>For example, let’s say Alice, Bob, and Eve all start with no information. Then, Alice says “TRIANGLE!” Now, Alice, Bob, and Eve all know triangle. If Bob says “SQUARE!”, then Alice, Bob, and Eve now all know square as well.</p>
<p>This is still information symmetric. But, if Alice secretly thinks to herself “circle…”, then this breaks the information symmetry of the system. Alice now knows something that neither Bob nor Eve knows.</p>
<p><img src="/../../assets/images/posts/alice_bob_eve_knowledge_diagram.png" alt="Alice, Bob, and Eve knowledge diagram" class="align-center" style="max-width: 400px;" /></p>
<p>Okay, great. Now we’ve broken the information symmetry. But, this is not enough for what we need though. What we need is that both Alice and Bob share some piece of information that Eve doesn’t have. Therefore, Alice and Bob need to somehow leverage the secret information that they each have to create some secret information that Eve does not have.</p>
<p>The way we do this is Alice and Bob both choose their own secret number. Alice chooses 3 and Bob chooses 4. Alice then announces some number, say 5, to the table, meaning that everyone knows this number. Then, Bob multiplies his secret number 4 with the 5 that Alice announced to get 20. He then announces 20 back to the table. Alice multiplies her 3 with the public 5 to announce 15. Alice then multiplies her secret 3 with the 20 Bob announced, getting <strong>60</strong>. Bob’s secret number was 4, so he multiplies that with the 15 Alice announced and gets <strong>60</strong>. And there we have it, both Alice and Bob have the number <strong>60</strong>, and Eve does not.</p>
<p><img src="/../../assets/images/posts/diffie_hellman_example.png" alt="Diffie-Hellman example" class="align-center" /></p>
<p>Eve does not know 60 because the numbers that were announced were 5, 15, and 20. No matter how you multiply these numbers, you can’t get 60.</p>
<p>Oh wait.</p>
<p>Eve can actually guess 60 very easily. All she needs to do is divide 15 by 5 to get 3 and 20 by 5 to get 4, and now she can multiply 5 times 3 times 4 to get 60. We’ll need to do something further. Hmm.. how do we make it harder for Eve to guess… How about every time we multiply two numbers, we only take the remainder after it divides by 9.</p>
<p>This time, Alice still announces 5 to start, but instead of sending 20, Bob sends the remainder of 20 divided by 9, which is 2. Alice sends the remainder of 15 divided by 9, which is 6. Bob then multiplies his secret 4 with 6 and divides by 9 to get a remainder of <strong>6</strong>. Alice then multiplies her secret 3 with the 2 from Bob to get 6, which, when divided by 9, gets a remainder of <strong>6</strong> as well. Now, Eve has a much harder time finding this common secret (I explain more in <a href="#remarks">Remarks</a> below). Of course, this gets even harder when Alice and Bob use much larger numbers. Try finding what two numbers produce 893498529201 as a remainder when multiplied and divided by 2182841020912383.</p>
<p>Now that I’ve thoroughly confused you with all these numbers, let’s take a step back and see what really happened here. What really happened is that Alice and Bob <em>combined their asymmetries</em> with each other. This process of combining asymmetries produced a symmetry between just Alice and Bob and maintained asymmetry with Eve.</p>
<p><img src="/../../assets/images/posts/combining_asymmetries.png" alt="Combining informational asymmetries" class="align-center" /></p>
<p>Diffie-Hellman is essentially the same protocol, except that it uses exponentials rather than multiplication and large primes with primitive roots rather than just some small integers. In my example, I used a multiply-divide-get-remainder function, but this protocol works with any function that has these properties:</p>
<ol>
<li>The function takes two inputs and produces an output</li>
<li>The function is commutative and associative, meaning that applying it many times in any order produces the same output</li>
<li>The inputs are hard to find if given an output</li>
</ol>
<p>We can see that these properties help us because 1) and 2) help us combine the asymmetries of Alice and Bob, and 3) prevents Eve from doing the same.</p>
<p>To illustrate this protocol in a generic form with an example, let’s say the function is <script type="math/tex">f</script>. Alice chooses <script type="math/tex">x</script> as her secret and Bob chooses <script type="math/tex">y</script> as his secret. The publicly announced value is <script type="math/tex">z</script>. Alice announces <script type="math/tex">f(x, z)</script> and Bob announces <script type="math/tex">f(y, z)</script>. Then, Alice gets the secret from <script type="math/tex">f(x, f(y, z))</script> and Bob gets the secret from <script type="math/tex">f(y, f(x, z))</script>. These are the same value S (because <script type="math/tex">f</script> is commutative and associative), which Eve is not able to get. All Eve has is <script type="math/tex">z</script>, <script type="math/tex">f(x, z)</script>, and <script type="math/tex">f(y, z)</script>.</p>
<p>So, now that we have such a protocol, how does this enable secure communications over the Internet? Well, the shared information that Alice and Bob create can be a key for encryption. After the protocol, Alice can use the key to encrypt messages she sends to Bob, only send the encrypted message over the Internet, and when Bob receives the encrypted messages, he can use the key to decrypt them and read the original messages. Anyone without this key would not be able to see the contents of the messages. When you are browsing your favorite website, you are essentially going through a similar protocol to generate a key that only you and the website’s servers share. All the communications between you and the website are encrypted with this key. Just make sure the website uses HTTPS and has a valid TLS certificate, but that’s probably for another post.</p>
<p>And there you have it - the protocol that lets you do the useful things on the Internet, like posting to your Facebook wall or ordering that late night delivery from Grubhub.</p>
<h2 id="remarks">Remarks</h2>
<p>In the example with Alice, Bob, and Eve, why did taking the remainder make it harder for Eve to know what Alice and Bob’s secret numbers were?</p>
<p>Well, first, it’s trivial for Eve to find the secret numbers when the protocol involves just multiplication. Let’s say <script type="math/tex">z</script> is the publicly announced number, <script type="math/tex">x</script> is Alice’s secret, and <script type="math/tex">y</script> is Bob’s secret. Alice sends <script type="math/tex">x\times z</script> and Bob sends <script type="math/tex">y\times z</script>. Eve can calculate x by just doing <script type="math/tex">\frac{x\cdot z}{z}</script>, and likewise for <script type="math/tex">y</script>. This is because there can only be one <script type="math/tex">x</script> that could give <script type="math/tex">x\times z</script> and only one <script type="math/tex">y</script> that could give <script type="math/tex">y\times z</script>.</p>
<p>Now, taking a remainder changes this. Let’s represent taking the remainder after dividing by a number with the symbol <script type="math/tex">\%</script>. If you were to take any integer <script type="math/tex">x \% 3</script>, for example, the result can only be one of 3 values - 0, 1, or 2. This means that many <script type="math/tex">x</script>’s could result in a remainder of 0, and likewise for 1 and 2. This is essentially what in cryptography you’d call a hash function, where the function has a large domain but a small range. Of course, just taking the remainder is not a cryptographically secure hash function, but it increases the difficulty by which Eve can find the inputs - the secrets of Alice and Bob. This is because, given a divisor <script type="math/tex">d</script>, Alice would send <script type="math/tex">x\times z \% d</script> and Bob would send <script type="math/tex">y\times z \% d</script>. With just <script type="math/tex">x\times z \% d</script> and <script type="math/tex">y\times z \% d</script>, Eve would have a harder time finding which <script type="math/tex">x\times z</script> and <script type="math/tex">y\times z</script> produced those remainders.</p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"></script>Qingyang Chenqingyang.chen@gmail.comI remember when I was first dabbling in making online multiplayer video games. I ran into many issues of people “hacking” my game and stealing players’ passwords. Of course, this was a major issue, but I at the time had no clue how these “hackers” could get ahold of the passwords. It was later that I realized that all data sent over the Internet is public. Anyone could see the data that my game’s server sent to the players and vice versa. Whenever a player logged in, their game would send their password to my server for verification. This data was sent over the Internet, and anyone watching would be able to see the password.I made a mistake in a concurrent program2018-05-25T10:42:30-04:002018-05-25T10:42:30-04:00http://coollog.me/debugging/i-made-a-mistake-in-a-concurrent-program<p>I was working on the concurrency part of my main project at work today. The program executed a series of steps in order to accomplish its task. Many of these steps could run in parallel, but some steps could only run after certain other steps.</p>
<p>I organized these steps into a dependency graph. Each step defined previous steps it needed to wait on before running. Steps with no dependencies could run immediately. With this structure, many steps could run at the same time, but no step would run before they were supposed to.</p>
<p><img src="/../../assets/images/posts/execution_dependency_graph.png" alt="execution dependency graph" class="align-center" style="max-width: 300px;" /></p>
<p style="text-align: center"><em>Example of an execution dependency graph with steps A…F</em></p>
<p>Each step would submit itself to an execution manager to either run immediately (no dependencies) or run after some other steps (after its dependencies). Upon submission, this step would receive a <a href="https://en.wikipedia.org/wiki/Futures_and_promises">future</a>. Other steps would then use this future to retrieve the result of that step after it finishes. I decided to be a bit fancy and lazily initialize these futures, where the step would only submit itself to the execution manager if another step required it to run.</p>
<p>All seemed well. I added a check to make sure that a future is always finished before another step retrieves its result. This makes sure that I defined the dependencies for the steps correctly. This was important because if I did not define the the dependencies correctly, steps might unintentionally block threads from executing useful work. Unintentional blocking would decrease the efficiency of the parallel execution.</p>
<p>After running the tests a few times, the check failed. I must have set up the graph incorrectly somewhere. I must have forgotten to define some dependency… So, I went down a rabbit hole for a few hours, auditing each step to make sure I had all the necessary dependencies set. But, every so often, the check still failed.</p>
<p>I thought for a long time. And then it suddenly hit me. I figured it out. This whole time I had set up the dependency graph correctly. The problem lied not in my dependency graph, but rather in my lazy initialization.</p>
<p>The lazy initialization worked like this. Each step has a “future” variable and a “get future” method. The “future” variable is initially undefined. When another step calls the “get future” method the first time, the method submits the step to the execution manager and sets the “future” variable. Further calls to “get future” returns that submitted future.</p>
<p><img src="/../../assets/images/posts/get_future_method.png" alt=""get future" method" class="align-center" style="max-width: 600px; width: 100%" /></p>
<p style="text-align: center"><em>“get future” method</em></p>
<p>Each step calls its dependencies’ “get future” method to get the futures to wait upon. Therefore, this initialization design builds the dependency graph from the last step backwards.</p>
<p><img src="/../../assets/images/posts/backwards_initialization.png" alt="backwards initialization" class="align-center" style="max-width: 600px; width: 100%" /></p>
<p style="text-align: center"><em>Illustration of how the dependency graph is built backwards</em></p>
<p>From this, I noticed the flaw in this initialization method - it had a blaring race condition. For example, let’s take a look at a scenario where two steps depend on a single step:</p>
<p><img src="/../../assets/images/posts/race_dependency.png" alt="dependency with race condition" class="align-center" style="max-width: 200px;" /></p>
<p>Let’s say B and C happened to call A’s “get future” method at the same time. B’s call has A submit future 1 to the execution manager. C’s call has A submit future 2 to the execution manager. This causes A to set its “future” variable to future 1 and then change it to future 2. Later, B calls A’s “get future” method again. B receives future 2, and not future 1 as it had expected.</p>
<p>So, how do we solve this problem? By not doing this backwards initialization. Each step should just initialize itself. Each step would submit itself to the execution manager upon creation. This means that each step would only ever create one future. Each step’s “get future” method would always return the same future.</p>
<p>I made this fix, and the problem disappeared.</p>
<p>In essence, the real issue is that I had mutable state. All concurrent objects should be immutable. I ran into this problem here because I had concurrent objects (the steps) be able to mutate state (set a “future” variable). By setting the “future” variable upon construction of each step, I made each step immutable and therefore immune to any parallel execution problems.</p>
<p>So, yeah, make sure all your concurrent objects are immutable. And don’t try to do fancy stuff before thinking it through completely.</p>
<h2 id="remarks">Remarks</h2>
<p>This problem wouldn’t exist with the original initialization method had the dependency graph been a tree. This is because in a tree, each node has only one parent, and therefore each “get future” method could only be called at most one time. But, our dependency graph is a directed acyclic graph and, in practice, many nodes have several parents.</p>Qingyang Chenqingyang.chen@gmail.comI was working on the concurrency part of my main project at work today. The program executed a series of steps in order to accomplish its task. Many of these steps could run in parallel, but some steps could only run after certain other steps.The 25 Horses Problem2018-05-20T00:42:30-04:002018-05-20T00:42:30-04:00http://coollog.me/problem-solving/hard-google-interview-question-25-horses-problem<p>I recently came across a video titled <a href="https://www.youtube.com/watch?v=i-xqRDwpilM">HARD Google Interview Question - The 25 Horses Puzzle</a>. I don’t think Google asks any brain teaser problems so I decided to check it out. Although the problem was formulated like a brain teaser, I found it to actually be a very well-designed technical problem. I could actually apply various technical problem-solving techniques to solve this problem - although it involved no coding. The problem describes a scenario with a “real-world” setting, but it could be modeled nicely with graph theory and topological ordering. The video presented a nice intuitive explanation of the solution, but I want to show how certain techniques can be used to approach this problem step-by-step - techniques that could be applied to problems of all sorts.</p>
<p>So, the problem goes as such:</p>
<p><em>You want to find the fastest 3 horses in a group of 25 horses. You can only race 5 horses at a time. You don’t have a stopwatch, so you can only know the ranking of each horse within each race. How many races do you need?</em></p>
<p><img src="/../../assets/images/posts/25_horses_puzzle.png" alt="25 horses puzzle" class="align-center" /></p>
<p>I enjoyed this problem since it wasn’t one of those brain teasers where there’s some trick to solving it that wasn’t presented in the original problem. The solution didn’t involve adding elements of manipulation to the scenario (like you give steroids to horses to make them faster). There wasn’t some wisecrack answer like “just one race if we are lucky!”. The solution formulates itself completely within the scope of the problem. In fact, the problem could be reduced into a raw representation such that it could be modeled in a mathematical format.</p>
<p>To re-formulate the problem in a technical sense:</p>
<ul>
<li>There are 25 elements that have some ordering from fastest to slowest among them (a <em>strict</em> ordering).</li>
<li>You can perform some computation called <em>race</em> that can give the <em>relative</em> ordering of any 5 of those elements.
How many times do you need to run <em>race</em> in order to find the first 3 elements in the ordering?</li>
</ul>
<p>The intent of the problem isn’t for us to give a number of races needed, but rather to provide a <em>proof</em> as to the number of races. This proof is like one of those classic two-sided proofs where the goal is to prove an equality. In these proofs, to prove that the solution is exactly some value, you prove that the solution is at least that value and also at most that value - and therefore the solution must be exactly that value. However, in this case, the two proofs are 1) that a solution exists for some value and 2) that the solution must be at least that value - therefore, that value is the minimum possible value.</p>
<p>So, for this problem, I needed to prove that:</p>
<ol>
<li>I can find a small number of races that works, and that</li>
<li>The minimum number of races needed is that number</li>
</ol>
<p>I started with a naive answer to prove the first lemma (<em>there exists some number of races that works</em>). Since there are 25 horses, if I race every pair of horses, I can rank each of the horses in their exact order. Therefore if I race the 25 horses 25 times each, I have the exact ordering - this is 25<sup>2</sup> races. Then, I realize that there are a lot of duplicate races. Eliminating these duplicate races I find the actual number of pairings:</p>
<ol>
<li>The first horse has 24 other horses to pair.</li>
<li>The second horse has 23 other horses to pair. The pairing for the first horse is already covered.</li>
<li>The third horse has 22 other horses to pair…</li>
</ol>
<p>…</p>
<p> 24. The 24th horse has 1 other horse to pair.</p>
<p> 25. The 25th horse has no other horses to pair.</p>
<p>This linear summation can be easily expressed as <script type="math/tex">\frac{25(24+0)}{2}</script>, or 300. That’s quite a few races still.</p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"></script>
<p>So, then I tried to look for what other races I could eliminate (don’t take this out of context) - which ones did not need to happen - what <em>inefficiencies</em> my algorithm had. The two main inefficiencies were that:</p>
<ul>
<li>I was not utilizing the full potential of the <em>race</em> function. I am discarding useful results by just looking at the ordering for the first two of each <em>race</em> result, and that</li>
<li>I am finding the full ordering of all 25 horses, whereas I only need the ordering for the first 3.</li>
</ul>
<p>One technique I like to use is to represent the problem in a model I have worked with extensively before - one that I am familiar with and have solved other problems in. Doing so would helps me to apply techniques I’ve learned from working with that model. In this problem, we are trying to find the (ordering) relationship between pairs of horses. What better model to represent this than a graph.</p>
<p>For those unfamiliar with graphs in discrete math, a graph is just a bunch of nodes and edges that connect them. In other words, it is the colloquial equivalent of a network (like a social network, or a network of highways).</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/5/5b/6n-graf.svg" alt="graph example" class="align-center" style="max-width: 300px;" /></p>
<p style="text-align: center"><em>An example of a graph</em></p>
<p>In our case, the nodes are the horses, and each edge represents a pair of horses. We can have our graph be a “knowledge” graph. We start with 25 nodes with no edges. Then, every edge we add between two horses represents knowledge of the ordering between the two horses - knowledge of which horse is faster. That means that each race could add new edges to our graph.</p>
<p><img src="/../../assets/images/posts/25_dots.png" alt="25 nodes" class="align-center" style="max-width: 300px;" /></p>
<p style="text-align: center"><em>A 25-node graph with no edges</em></p>
<p>With this model, the original approach of running 300 races is equivalent to adding an edge between every node. In fact, there are exactly 300 edges if we were to connect all the nodes with edges (see <a href="https://en.wikipedia.org/wiki/Complete_graph">complete graph</a>). Many of these edges are not necessary. In fact, we only need two edges to know the fastest 3 horses - the edge between the fastest and second fastest, and the edge between the second fastest and third fastest.</p>
<p><img src="/../../assets/images/posts/first_second_third.png" alt="first second third" class="align-center" style="max-width: 300px;" /></p>
<p style="text-align: center"><em>We win if we find these edges</em></p>
<p>However, this does not mean that we only need one race. We could get lucky and have our top 3 horses be in the one race we hold, but the problem is asking for a solution that could work in <em>all</em> cases.</p>
<p>Now, it made sense to start building the solution from the bottom up and tackle the second lemma (<em>the number of races needed is at least some number</em>). The initial graph is 25 nodes with no edges. So, the first thing I realize is that no matter what, when we connect the nodes up no node can be left out (the graph needs to be <a href="https://en.wikipedia.org/wiki/Connectivity_(graph_theory)#Connected_graph">connected</a>). This is because any horse that is not connected to the others means that we don’t have any information about its ordering. Therefore, first, we must run at least 5 races to get some edge for each of the 25 horses. However, this results in 5 disjoint graphs.</p>
<p><img src="/../../assets/images/posts/5_races.png" alt="5 races" class="align-center" style="max-width: 300px;" /></p>
<p>We still need to connect these 5 disjoint graphs by picking <em>some</em> horse in each graph for another race (the 6th race). One way is to pick the fastest from each group. In fact, this will give us one of the key information that we need - the fastest horse overall.</p>
<p><img src="/../../assets/images/posts/6_races.png" alt="6 races" class="align-center" style="max-width: 300px;" /></p>
<p>However, we still need to know the second and third fastest. If we look at the current knowledge graph, the fastest horse is connected to two horses. Either of these horses could be the second fastest. Therefore, we need an edge between these two horses in order to know who is faster. We need a 7th race.</p>
<p>What if we didn’t pick the fastest horse to race from each group? For instance, let’s assume we raced the fastest horses from only 4 groups. In that case, we would not know if the horse we left out is the fastest overall unless we had some edge between that horse and the fastest of the other 4 we raced. To have that information, we need at least another race.</p>
<p>In both cases, we proved that there needs to be some number of races 7 or higher (lemma 2). So then, I tried to find a way to solve this with just 7 races.</p>
<p>After we raced the horses 6 times, we got this knowledge graph:</p>
<p><img src="/../../assets/images/posts/6_races.png" alt="6 races" class="align-center" style="max-width: 300px;" /></p>
<p>We can see that the only horses that could be the second fastest are the ones that are directly connected to the fastest horse. Likewise, we know that the only horses that could be the third fastest are the ones that are directly connected to the contenders for second place.</p>
<p><img src="/../../assets/images/posts/6_races_highlight.png" alt="6 races highlighted" class="align-center" style="max-width: 300px;" /></p>
<p>We are left with 6 horses that are still in the running for first, second, and third. Since we already know which horse is fastest, <em>we just need to race the 5 other horses to find the second and third fastest</em>.</p>
<p><img src="/../../assets/images/posts/7_races.png" alt="7 races" class="align-center" style="max-width: 300px;" /></p>
<p style="text-align: center"><em>Another race gives us the four edges we need</em></p>
<p>And there we have it, we found a way to solve the problem with 7 races and proved lemma 1 as well.</p>
<p>Therefore, the minimum number of races needed is 7.</p>
<p>The framework I used in solving this problem can be used to solve many other types of problems:</p>
<ol>
<li>Reformulate the problem to remove the cruft</li>
<li>Define what we need to prove</li>
<li>Model the problem to break it down and see what we actually need to solve</li>
<li>Start easy and gradually engineer the solution by:
<ol>
<li>Removing the unnecessary parts, and</li>
<li>Building from the ground up</li>
</ol>
</li>
</ol>
<h2 id="remarks">Remarks</h2>
<p>This problem is also recognizable as a topological ordering problem, but I decided not to present it in that way since I wanted to explain it in a more intuitive “knowledge graph” manner.</p>
<p>So, I’ll present the topological ordering model here. Let’s take the original “knowledge graph” and make it into a directed graph. For those who are unfamiliar, this just means that each edge points from one node to the other. In this case, we can point from the faster horse to the slower horse for each edge. Going back to the diagrams we had, after the 6th race, the edges would look like:</p>
<p><img src="/../../assets/images/posts/6_races_directed.png" alt="6 races directed" class="align-center" style="max-width: 300px;" /></p>
<p>Here, we can see that a path from horse A to horse B means that we know horse A is faster than horse B. A path is just a way to get from one node to another by only following edges in the direction they point.</p>
<p>The final 6 contending horses would look like:</p>
<p><img src="/../../assets/images/posts/7_races_directed.png" alt="7 races directed" class="align-center" style="max-width: 300px;" /></p>
<p>After the 6th race, we have a path from the fastest horse to any of the contenders for 2nd and 3rd place. The 7th race gives us the path among these contenders (making our directed graph <a href="http://mathworld.wolfram.com/ConnectedDigraph.html">strongly connected</a>).</p>Qingyang Chenqingyang.chen@gmail.comI recently came across a video titled HARD Google Interview Question - The 25 Horses Puzzle. I don’t think Google asks any brain teaser problems so I decided to check it out. Although the problem was formulated like a brain teaser, I found it to actually be a very well-designed technical problem. I could actually apply various technical problem-solving techniques to solve this problem - although it involved no coding. The problem describes a scenario with a “real-world” setting, but it could be modeled nicely with graph theory and topological ordering. The video presented a nice intuitive explanation of the solution, but I want to show how certain techniques can be used to approach this problem step-by-step - techniques that could be applied to problems of all sorts.