<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: donovanrichardson</title>
    <description>The latest articles on Forem by donovanrichardson (@donovanrichardson).</description>
    <link>https://forem.com/donovanrichardson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F456019%2Fe9b82b83-393a-450f-a9af-edbf2b1b1ee6.jpeg</url>
      <title>Forem: donovanrichardson</title>
      <link>https://forem.com/donovanrichardson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/donovanrichardson"/>
    <language>en</language>
    <item>
      <title>(Re-)Districting</title>
      <dc:creator>donovanrichardson</dc:creator>
      <pubDate>Fri, 16 Oct 2020 18:18:02 +0000</pubDate>
      <link>https://forem.com/donovanrichardson/re-districting-3p42</link>
      <guid>https://forem.com/donovanrichardson/re-districting-3p42</guid>
      <description>&lt;p&gt;Here, I'll follow up on my &lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:6720682815366672384/"&gt;LinkedIn post&lt;/a&gt; on an algorithm that I've been designing to delineate cohesive "neighborhoods" or "districts" based on just a road network, for use with political redistricting, determining business service areas, or just approximating areas of common existence. &lt;strong&gt;Find it on GitHub &lt;a href="https://github.com/donovanrichardson/mander"&gt;here&lt;/a&gt;&lt;/strong&gt;. In the earlier post, I shared a few pictures of the districts that this algorithm created in Manhattan. Since then, I've made a few improvements to the algorithm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Previously due to a bug, the Python implementation of this algorithm could terminate unpredictably early, usually one or two iterations before it was supposed to.&lt;/li&gt;
&lt;li&gt;The big one: it seems that this algorithm now runs in O(n×log(n)) time on average. Previously it ran O(n&lt;sup&gt;2&lt;/sup&gt;) on average. One caveat: with a worst-case road network that is shaped like an asterisk, this algorithm will run in O(n&lt;sup&gt;2&lt;/sup&gt;) time; in that case, the old algorithm would have run in O(n&lt;sup&gt;3&lt;/sup&gt;) time. Yikes!&lt;/li&gt;
&lt;li&gt;The Python implementation now outputs the results of the algorithm to CSV. This lets you import the data into a GIS like ArcMap or QGIS in order to display it. I found this to be prettier, easier, faster, and more accessible than plotting a result graph as a figure in Python.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three of these things improved issues that I thought I just might have to live with. For the sake of my peace of mind, I'm glad that I've been able to fix them!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Algorithm
&lt;/h2&gt;

&lt;p&gt;In my LinkedIn post, I highlighted two soft constraints for this algorithm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;group areas that have small distances between them before grouping areas with long distances between them&lt;/li&gt;
&lt;li&gt;grouping core areas with peripheral areas before connecting different core areas with each other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal of these constraints is to approximate how different places might have real-life human connections. &lt;/p&gt;

&lt;p&gt;Keeping that in mind, here's some pseudocode for the algorithm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Break graph into &lt;em&gt;n&lt;/em&gt; subgraphs, where &lt;em&gt;n&lt;/em&gt; is the number of nodes in the graph.&lt;/li&gt;
&lt;li&gt;While there are more subgraphs than connected components (i.e. while there are still edges that connect different subgraphs):

&lt;ol&gt;
&lt;li&gt;For each edge &lt;em&gt;e&lt;/em&gt; which connects two separate subgraphs

&lt;ol&gt;
&lt;li&gt;Where &lt;em&gt;v1&lt;/em&gt; and &lt;em&gt;v2&lt;/em&gt; are the two vertices coincident with &lt;em&gt;e&lt;/em&gt;, &lt;em&gt;l1&lt;/em&gt; and &lt;em&gt;l2&lt;/em&gt; are the lengths of all edges coincident on &lt;em&gt;v1&lt;/em&gt; and &lt;em&gt;v2&lt;/em&gt; respectively, &lt;em&gt;lv&lt;/em&gt; is the least of these two lengths, and &lt;em&gt;le&lt;/em&gt; is the length of edge &lt;em&gt;e&lt;/em&gt;,  Calculate a score &lt;em&gt;c&lt;/em&gt; where c = &lt;em&gt;le&lt;/em&gt; * &lt;em&gt;lv&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Sort these edges based on their score (done with Postgres index in my implementation)&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;For each of the sorted edges in order:

&lt;ol&gt;
&lt;li&gt;join subgraphs incident on this edge if both subgraphs have not been joined in this iteration (each iteration begins on line &lt;code&gt;2.&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Make a record of the subgraphs existing at the end of this iteration (otherwise the algorithm will terminate as one subgraph for each connected component, with no information on how the graph was delineated into districts)&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The cause of the O(n&lt;sup&gt;2&lt;/sup&gt;) problem was that the loop in &lt;code&gt;2.1.&lt;/code&gt; was previously nested within the loop of &lt;code&gt;2.2&lt;/code&gt;; instead of two separate loops iterating through each edge, the nested loops iterated through each edge to calculate the score for just one edge. This error was unnecessary and wasteful, since the result of the loop in &lt;code&gt;2.1&lt;/code&gt; will essentially be the same within the same iteration, except for results concerning newly-connected components which are not considered in &lt;code&gt;2.2&lt;/code&gt; anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gallery
&lt;/h2&gt;

&lt;p&gt;With 9606 junctions and 15882 road segments on OpenStreetMap, &lt;strong&gt;San Francisco&lt;/strong&gt; was too large for my O(n&lt;sup&gt;2&lt;/sup&gt;) algorithm to run within a reasonable time. With the improved algorithm, it was possible to delineate this city into districts. I'll be posting follow-ups with other regions/cities, so be sure to check back!&lt;/p&gt;

&lt;h3&gt;
  
  
  districts at 7th iteration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FTrehpvk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf7_xbm8x6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FTrehpvk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf7_xbm8x6.png" alt="San Francisco districts at 7th iteration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  districts at 9th iteration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5waUAPgv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf9_iqbwip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5waUAPgv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf9_iqbwip.png" alt="San Francisco districts at 9th iteration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  districts at 11th iteration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cIHJDU92--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf11_snlsml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cIHJDU92--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf11_snlsml.png" alt="San Francisco districts at 11th iteration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  districts at 13th iteration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tLU_WamL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf13_s8luux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tLU_WamL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf13_s8luux.png" alt="San Francisco districts at 13th iteration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  districts at 14th iteration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8cPanH11--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf14_tcvqpy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8cPanH11--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf14_tcvqpy.png" alt="San Francisco districts at 14th iteration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  districts at 15th (penultimate) iteration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bpzG1XrC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf15_hhgsko.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bpzG1XrC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/donovanrichardson/image/upload/v1602870927/sf15_hhgsko.png" alt="San Francisco districts at 15th iteration"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>python</category>
      <category>datascience</category>
      <category>database</category>
    </item>
    <item>
      <title>Adding a New Remote and Merging Unrelated Branches</title>
      <dc:creator>donovanrichardson</dc:creator>
      <pubDate>Thu, 20 Aug 2020 23:01:59 +0000</pubDate>
      <link>https://forem.com/donovanrichardson/adding-a-new-remote-and-merging-unrelated-branches-1mkm</link>
      <guid>https://forem.com/donovanrichardson/adding-a-new-remote-and-merging-unrelated-branches-1mkm</guid>
      <description>&lt;p&gt;For my first blog post here, I'll address something that's come up a few times during my time as a student at General Assembly's software engineering program: merging branches with unrelated histories.&lt;/p&gt;

&lt;p&gt;When I have to merge unrelated histories, it's usually because I need to push to a remote repo that already has some content. A good use case is when you have made a new GitHub repo with a readme, but now you need to push a totally different local repo to this GitHub repo. These repositories are not related to each other and can't be merged using the default settings.&lt;/p&gt;

&lt;p&gt;Let's walk through how to merge unrelated histories!&lt;/p&gt;

&lt;h2&gt;
  
  
  Fetching a remote repository
&lt;/h2&gt;

&lt;p&gt;When you need to sync local and remote repositories, you'll have to add the remote repo as a &lt;code&gt;remote&lt;/code&gt; of your local one. You can do this using the command &lt;code&gt;git remote add &amp;lt;remote name&amp;gt; &amp;lt;remote url&amp;gt;&lt;/code&gt;. You can fill in whatever name you like for the name of your new remote. For this exercise, I called my remote &lt;code&gt;part3&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597961600%2Fremote-add_ricjjl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597961600%2Fremote-add_ricjjl.png" alt="git remote add part3 https://my-repo-url.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, you'll have to fetch this repository using &lt;code&gt;git fetch part3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F2_aavdob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F2_aavdob.png" alt="git fetch part3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard part: merging
&lt;/h2&gt;

&lt;p&gt;Unlike when dealing with related branches, when you try &lt;code&gt;git merge part3/master&lt;/code&gt; with two unrelated branches, Git won't be able to merge these branches. Instead, Git offers a "fatal" message that seems designed to give users horrible nightmares.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F3a_atgews.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F3a_atgews.png" alt="fatal: refusing to merge unrelated histories"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;What this means is that Git is not able to tell how the files in these two repos should relate to each other, and cannot perform a conventional merge.&lt;/p&gt;

&lt;p&gt;But this doesn't mean that Git cannot perform any merge. In fact, all you need to do to merge unrelated branches is to use the flag &lt;code&gt;--allow-unrelated-histories&lt;/code&gt;. This tells Git to combine all the files and commits of both unrelated branches into one branch, as long as there are no file conflicts. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F3b_l3r6ed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F3b_l3r6ed.png" alt="there are conflicts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When there are file conflicts, you'll have to use the normal Git workflow to resolve them. &lt;/p&gt;

&lt;h1&gt;
  
  
  File conflicts
&lt;/h1&gt;

&lt;p&gt;During my exercise, I had one conflict: README.md existed in both repositories, and it was not possible for Git to automatically merge the content of each file. In my situation, I needed only the remote README.md, so I used Visual Studio Code's user-friendly merge conflict tool to resolve the conflicts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F4a_c6knev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F4a_c6knev.png" alt="I chose "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Commit and push
&lt;/h1&gt;

&lt;p&gt;After fixing the merge conflicts, all you have to do to resolve the unrelated histories is commit. Then push and... voila! Your content from both repositories is now integrated into one GitHub repo. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F5a_wcexk3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F5a_wcexk3.png" alt="committing"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F5b_lphy5d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdonovanrichardson%2Fimage%2Fupload%2Fv1597960673%2F5b_lphy5d.png" alt="pushing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you have one less thing to worry about when using Git. Use the &lt;code&gt;--allow-unrelated-histories&lt;/code&gt; flag the next time you find yourself needing to merge two unrelated branches.&lt;/p&gt;

</description>
      <category>github</category>
      <category>git</category>
      <category>generalassembly</category>
      <category>unrelatedhistories</category>
    </item>
  </channel>
</rss>
