Sergio:Boterohttp://sergiobuj.github.io/2014-08-11T16:06:00-07:00Coding exercises2014-08-11T16:06:00-07:00Sergio Boterotag:sergiobuj.github.io,2014-08-11:coding-exercises/2014/08/11/coding-exercises/
<div tabindex="-1" id="notebook" class="border-box-sizing">
<div class="container" id="notebook-container">
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="Motivation">Motivation<a class="anchor-link" href="#Motivation">¶</a></h2>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>Working on the programming problems from <a href="https://rosalind.org">Rosalind</a> I decided to present some of the algorithms I used to solve some of them.</p>
<p>I will try to present the algorithm/code as a way to solve a general problem and not the actual problem because I don't want to spoil the fun for others.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="Graphs">Graphs<a class="anchor-link" href="#Graphs">¶</a></h2>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [1]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="c"># For all the following graph algorithms I will use the dictionary with integers as keys and sets as values.</span>
<span class="n">graph</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">0</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="mi">1</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">2</span><span class="p">]),</span>
<span class="mi">2</span><span class="p">:</span><span class="nb">set</span><span class="p">([])</span>
<span class="p">}</span>
<span class="c">#This Graph is just:</span>
<span class="c"># 0 -> 1 -> 2</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>I will also try to use <a href="http://networkx.github.io/">Networkx</a> to give a visual representation.</p>
<ul>
<li><a href="/coding-exercises/2014/07/27/using-tarjans-algorithm/">Strongly Connected Components in a graph</a></li>
<li><a href="/coding-exercises/2014/08/11/reach-all-vertices">Finding a node that can reach all graph</a></li>
</ul>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>Comments? let me know on <a href="https://twitter.com/sergiobuj">@sergiobuj</a></p>
</div>
</div>
</div>
</div>
</div>
Reach all vertices2014-08-11T16:05:00-07:00Sergio Boterotag:sergiobuj.github.io,2014-08-11:coding-exercises/2014/08/11/reach-all-vertices/
<div tabindex="-1" id="notebook" class="border-box-sizing">
<div class="container" id="notebook-container">
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="Can-I-reach-all-vertices-from-one-vertex?">Can I reach all vertices from one vertex?<a class="anchor-link" href="#Can-I-reach-all-vertices-from-one-vertex?">¶</a></h2>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>In another programming challenge from <a href="https://rosalind.org">Rosalind</a> I was asked to find a vertex, if any, from which all other vertices are reachable. In a DAG.</p>
<p>The very first solution that comes to mind is to simply go through the list of edges and have a couple of sets recording the <code>FROM</code> vertex and <code>TO</code> vertex of each edge.</p>
<p>After reviewing all the edges, a simple set difference (<code>FROM</code> - <code>TO</code>) will yield the vertices that have no incident edges.</p>
<p>If this difference set has more than one element, that means that those vertices won't be reachable from those other vertices.</p>
<p>This looks very easy, lets look at a couple of examples first and see if we can spot some weird cases.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [1]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="c"># Here I will set up networkx for the images and graph samples.</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="kn">as</span> <span class="nn">plt</span>
<span class="kn">import</span> <span class="nn">networkx</span> <span class="kn">as</span> <span class="nn">nx</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="kn">as</span> <span class="nn">np</span>
<span class="k">def</span> <span class="nf">showgraph</span><span class="p">(</span><span class="n">graph</span><span class="p">):</span>
<span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">G</span><span class="o">=</span><span class="n">nx</span><span class="o">.</span><span class="n">DiGraph</span><span class="p">()</span>
<span class="k">for</span> <span class="n">node</span><span class="p">,</span> <span class="n">edges</span> <span class="ow">in</span> <span class="n">graph</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">for</span> <span class="n">edge</span> <span class="ow">in</span> <span class="n">edges</span><span class="p">:</span>
<span class="n">G</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">edge</span><span class="p">)</span>
<span class="n">pos</span><span class="o">=</span><span class="n">nx</span><span class="o">.</span><span class="n">spring_layout</span><span class="p">(</span><span class="n">G</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_nodes</span><span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="n">pos</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">arrows</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_labels</span><span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="n">pos</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>Let's define 4 graphs. 1. Graph with cycles. 2. Graph with multiple vertices with no incident edges. 3. Ideal graph for our naive solution. 4. Graph with two separate cycles.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [2]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="n">graph1</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">0</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="mi">1</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">]),</span>
<span class="mi">2</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">3</span><span class="p">]),</span>
<span class="mi">3</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="mi">4</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
<span class="p">}</span>
<span class="n">showgraph</span><span class="p">(</span><span class="n">graph1</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area"><div class="prompt"></div>
<div class="output_png output_subarea ">
<img src="data:image/png;base64,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
hXjKAAAAAElFTkSuQmCC
">
</div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [3]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="n">graph2</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">0</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">5</span><span class="p">]),</span>
<span class="mi">1</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">5</span><span class="p">]),</span>
<span class="mi">2</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">5</span><span class="p">]),</span>
<span class="mi">3</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">5</span><span class="p">]),</span>
<span class="mi">4</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">5</span><span class="p">]),</span>
<span class="mi">5</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">5</span><span class="p">])</span>
<span class="p">}</span>
<span class="n">showgraph</span><span class="p">(</span><span class="n">graph2</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area"><div class="prompt"></div>
<div class="output_png output_subarea ">
<img src="data:image/png;base64,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
">
</div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [4]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="n">graph3</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">0</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="mi">1</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">3</span><span class="p">]),</span>
<span class="mi">2</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="mi">3</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">0</span><span class="p">]),</span>
<span class="mi">4</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">]),</span>
<span class="mi">5</span><span class="p">:</span><span class="nb">set</span><span class="p">([])</span>
<span class="p">}</span>
<span class="n">showgraph</span><span class="p">(</span><span class="n">graph3</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area"><div class="prompt"></div>
<div class="output_png output_subarea ">
<img src="data:image/png;base64,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
0aPHxU6dOt3w9fW9zDoTABFR9ZllFfT8y1nzV6/+wt/fP5JtqsaHwzkbkbaeouF1ODk5Je/cuXO8
v79/ZFZWlhXrPACVlZW6169f9665rGvXrldY5WEJ+/gbSXl5ub61tfXTW7dudbC1tU1nnaexzJ8/
f9H58+d7nTp16q3KykpdAwODMuz3Bxbi4uI8vby8YqtvW1lZZT19+tSaj38fscXfSH799df3O3bs
eJNPpU9EtGDBgoVisbg0ODh4i4+PT8zKlStnss4E/KR6AaGuXbte4WPpE6H4G01YWNgobbngSkMS
iUSKoKCgvXv27Bl7584dj6+++uq706dP92OdC/gnJibGp+Ztvu7mIcKunkZRWFho0qpVq8epqan2
zZs3f8Y6T2MqKioydnBweJiXl2dWvczc3Dz3+vXr3pp+uUloWtzd3e/Gx8e7Vd8+derUW/369TvN
MhMr2OJvBNHR0UP79u17hm+lT0RkbGxctH///sCaP1Ln5uaaDxs27FBZWZkBy2zAH0VFRcYJNS6o
IhAIuCZ/rP4LoPgbQXh4eABfjuapTf/+/Y8vWrRofs1l165d6/zZZ5/9wCoT8MvVq1e7cBwnqL7t
6uqaYGxsXMQyE0sofjV7+vSp9bVr1zp/8MEH/2GdhaWvv/7624EDBx6ruWz79u0fb9u2bSKrTMAf
2dnZls2aNSuovs3n/ftE2MevduvWrZt648aNTrt37x7LOgtrBQUFzbp06XL1/v37/38GXD09vYo/
/vjjDR8fnxiW2aDpi4+Pd33nnXdOfvvtt3McHBwe9uzZ8wLrTKxgi1/N+Ho0T22aNWtWcPjw4SE1
rzpWUVGh5+fnF5WTk2PBMhs0fVevXvV54403LowePXovn0ufCMWvVvfu3WuXnp5u26dPn7Oss2gK
Dw+POzt37hxfc1laWprdiBEjIqqqqnAKEVCbK1eudOX7Lp5qKH41Cg8PDxg+fPhPOjo6VayzaJLh
w4f/NG3atLU1l505c6bvnDlzlrLKBE0fiv9/sI9fTTiOEzg7OyeFhYWN4vNhY3WprKzUfeutt06d
P3++V83lUVFRfkOHDo3+448/3jj1229vPcvMbCHS1a2ysLF5MmTo0MNubm7xrDKD9iotLRWbmZnl
5eXlmYnF4lLWeZhjfXrQpjoxMTFdHB0dk5vqBVcaYjIzM61sbGyeEBFXPfp6emXtbGyeuEilxXMF
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
">
</div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [5]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="n">graph4</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">0</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">]),</span>
<span class="mi">1</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">2</span><span class="p">]),</span>
<span class="mi">2</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">0</span><span class="p">]),</span>
<span class="mi">3</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">4</span><span class="p">]),</span>
<span class="mi">4</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">5</span><span class="p">]),</span>
<span class="mi">5</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">3</span><span class="p">])</span>
<span class="p">}</span>
<span class="n">showgraph</span><span class="p">(</span><span class="n">graph4</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area"><div class="prompt"></div>
<div class="output_png output_subarea ">
<img src="data:image/png;base64,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
JhobGxds2bLl89ayZAUCSzZAK8MwDO/69etDg4ODA8LCwmaUl5e/7PdbIiIyMTHJl5aXS/bU1Iim
vM7rENE8Xd3aek/P34PCwmZkZ2d3j4mJ8WiItLQ069fJW1dXt27o0KHXG74RDB069DpXb/BSlZ6e
buXl5XXU1tY2Zc+ePR916NBBdWYNWhrbZx4EgmEYys7ONlu/fv2K3r17P6JmjLZ9fHwOnzp1aqJU
KhUkJCQ4GYnFVeeaGPk3hIKIWSkQ1Peztn5cVlZm0Fg+WVlZ5qGhoR/Onj17b8+ePdOaykk1dHV1
az08PKLXrFnzbUxMzMiamhoh258xm1FTUyOcM2fOHnt7+6SHDx/asZ0P14P1BBDcjZqaGmFYWNj0
8ePHn+Hz+fKmiqmTk1PCtm3bPi0uLu6s2telS5dGGOvrl3/P58sKX1H07xIx04TCGid7+6T8/HyT
5uaamZlpERIS4hcYGLjvTaaGhEJhTWZmpgXbnznbsWfPnjlGRkZFhw8f9mE7Fy4H6wkguBm//PLL
oo4dO5Y2VTCNjY0LlixZsvnu3bt9m+ozJSXFJnDGjEMSobDmQ5Go6igRc4mIuUDE7CNi3PX1y007
diz9duXKtZWVlXpvk39GRkaP/fv3+wcEBARZWlqmN/U+9PX1yxMSEgapcynothoJCQlOlpaW6V98
8cX/NvYMAITmA3P8wIrdu3fP/fjjjxu9qVYgEMgmTZp0IjAwMGj8+PFntbW1pa/Td0lJiWHQ3r1z
Yk6ceK+0tNRQW1tbamxqmucTGBg0efLk31+3v+bIyMiwvHTp0sjo6OhR0dHRo7KysiyU9/fq1StV
W1tbmpeXZ+ru7h47atSoaA8Pj5h+/frd5eIaQCUlJYZ+fn6hFRUV+uHh4dPb2xLWrR7bZx4Ed6Lh
KVAfffTRbolEUqqlpSUjpVHxgAEDEv/1r38tLiws7MJ2rm8b6enplkFBQQH+/v77zc3Ns3bs2PEJ
w7x4YEx4ePi0efPm/WZnZ/ewU6dOJe+///7vW7Zs+TwxMXGAXC7ns517S4VcLud/991333Tr1i3n
0qVLI9jOh0vBegKI9h9ZWVnm69at+9rGxiald+/ejzZs2LA8OzvbLDAwcJ+RkVHR4sWL/5WYmDiA
7Tw1FQqFgveyKZ68vLyuYWFh0+fNm/db7969H3Xq1Klk8uTJkVu2bPn89u3b/blwIjhz5sx4Y2Pj
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
AAAASUVORK5CYII=
">
</div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h3 id="graph-1">Graph 1</h3>
<p><code>graph1</code> presents a situation where we can use our naive approach to infer the solution. Why? because every vertex appears at least once in the <code>from</code> and <code>to</code> sides of an edge. The set difference in the end will yield an empty set.</p>
<p>An empty set with our approach means that we can use any vertex as the starting point and we could reach every other vertex using the cycles.</p>
<h3 id="graph-2">Graph 2</h3>
<p><code>graph2</code> is clearly a good graph for our naive approach since the difference set will have more than one element, meaning that there is no way to reach all vertices.</p>
<h3 id="graph-3">Graph 3</h3>
<p>This graph is a good fit for our approach since the difference set will leave us with the vertex labeled 4. From which we can reach all other vertices.</p>
<h3 id="graph-4">Graph 4</h3>
<p><code>graph4</code> is a case where our naive approach falls short. This is basically a mixture between <code>graph1</code> and <code>graph3</code>. In this kind of graph we have a couple of cycles with one edge from one cycle to the other.</p>
<p>For graphs that have a structure like the one presented on <code>graph4</code>. This is what I did.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="My-approach">My approach<a class="anchor-link" href="#My-approach">¶</a></h2>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>Making use of the Strongly Connected Components (I talked about it in <a href="/coding-exercises/2014/07/27/using-tarjans-algorithm/">Strongly Connected Components in a graph</a>) on a graph I reduced and simplified a graph from something like <code>graph4</code> to something more like <code>graph3</code>. Running Tarjan's algorithm over <code>graph4</code> will leave me with something like <code>graph5</code> (below), where I can easily use the naive approach and pick any of the vertices from the mega-vertex on the simplified graph.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [6]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="n">graph5</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">"0, 1, 2"</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="s">"3, 4, 5"</span><span class="p">]),</span>
<span class="s">"3, 4, 5"</span><span class="p">:</span><span class="nb">set</span><span class="p">([]),</span>
<span class="p">}</span>
<span class="n">showgraph</span><span class="p">(</span><span class="n">graph5</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area"><div class="prompt"></div>
<div class="output_png output_subarea ">
<img src="data:image/png;base64,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
">
</div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>From this new representation, we know that any node from the "0, 1, 2" vertex is a good answer for our problem.</p>
<p>In general, the steps were: 1. Reduce and simplify the graph with Tarjan's SCC algorithm. 2. Create the <code>FORM</code> and <code>TO</code> sets with the mega-vertices or components. 3. Check the <code>FROM-TO</code> set for elements, if it has one, pick any element from that component; if it has zero elements, pick any element from the whole graph; if it has more than one, there is no solution.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h3 id="note">Note:</h3>
<p>Remember Tarjan's SCC Algorithm I presented for the other problem at <a href="/coding-exercises/2014/07/27/using-tarjans-algorithm/">Strongly Connected Components in a graph</a>.</p>
<p>And here is the implementation for Tarjan's Algorithm I used before.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [7]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="k">def</span> <span class="nf">tarjan</span><span class="p">(</span><span class="n">graph</span><span class="p">):</span>
<span class="c">#input: graph G = (V, E)</span>
<span class="c">#output: Array of strongly connected components (sets of vertices)</span>
<span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">graph</span><span class="p">)</span>
<span class="n">sccs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">index</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">indexes</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span>
<span class="n">lows</span> <span class="o">=</span> <span class="p">[</span><span class="nb">float</span><span class="p">(</span><span class="s">'Inf'</span><span class="p">)]</span> <span class="o">*</span> <span class="n">n</span>
<span class="n">S</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span> <span class="nf">strongconnect</span><span class="p">(</span><span class="n">v</span><span class="p">):</span>
<span class="c"># Set the depth index for v to the smallest unused index</span>
<span class="n">indexes</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">index</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">index</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">index</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">S</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="c"># Consider successors of v</span>
<span class="k">for</span> <span class="n">chld</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">[</span><span class="n">v</span><span class="p">]:</span>
<span class="k">if</span> <span class="n">indexes</span><span class="p">[</span><span class="n">chld</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="c"># Successor chld has not yet been visited; recurse on it</span>
<span class="n">strongconnect</span><span class="p">(</span><span class="n">chld</span><span class="p">)</span>
<span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">],</span> <span class="n">lows</span><span class="p">[</span><span class="n">chld</span><span class="p">])</span>
<span class="k">elif</span> <span class="n">chld</span> <span class="ow">in</span> <span class="n">S</span><span class="p">:</span>
<span class="c"># Successor w is in stack S and hence in the current SCC</span>
<span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">],</span> <span class="n">lows</span><span class="p">[</span><span class="n">chld</span><span class="p">])</span>
<span class="c"># If v is a root node, pop the stack and generate an SCC</span>
<span class="k">if</span> <span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="n">indexes</span><span class="p">[</span><span class="n">v</span><span class="p">]:</span>
<span class="n">scc</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="n">v</span><span class="p">])</span>
<span class="n">w</span> <span class="o">=</span> <span class="n">S</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="k">while</span> <span class="n">w</span> <span class="o">!=</span> <span class="n">v</span><span class="p">:</span>
<span class="n">scc</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">w</span><span class="p">)</span>
<span class="n">w</span> <span class="o">=</span> <span class="n">S</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="n">sccs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">scc</span><span class="p">)</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">graph</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
<span class="k">if</span> <span class="n">indexes</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="n">strongconnect</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">return</span> <span class="n">sccs</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [8]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="k">def</span> <span class="nf">vertices_that_reach_all</span><span class="p">(</span><span class="n">graph</span><span class="p">):</span>
<span class="n">scc</span> <span class="o">=</span> <span class="n">tarjan</span><span class="p">(</span><span class="n">graph</span><span class="p">)</span>
<span class="n">ncomp</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">scc</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ncomp</span> <span class="o">></span> <span class="mi">1</span><span class="p">:</span>
<span class="n">sources</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="n">dests</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="k">for</span> <span class="n">incomp</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">ncomp</span><span class="p">):</span>
<span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">scc</span><span class="p">[</span><span class="n">incomp</span><span class="p">]:</span>
<span class="k">for</span> <span class="n">edge</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">[</span><span class="n">node</span><span class="p">]:</span>
<span class="k">for</span> <span class="n">outcomp</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">ncomp</span><span class="p">):</span>
<span class="k">if</span> <span class="n">incomp</span> <span class="o">!=</span> <span class="n">outcomp</span> <span class="ow">and</span> <span class="n">edge</span> <span class="ow">in</span> <span class="n">scc</span><span class="p">[</span><span class="n">outcomp</span><span class="p">]:</span>
<span class="n">sources</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">incomp</span><span class="p">)</span>
<span class="n">dests</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">outcomp</span><span class="p">)</span>
<span class="k">break</span>
<span class="n">sources</span><span class="o">.</span><span class="n">difference_update</span><span class="p">(</span><span class="n">dests</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sources</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">sources</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">scc</span><span class="p">[</span><span class="n">comp</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">graph</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [9]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="k">for</span> <span class="n">num</span><span class="p">,</span> <span class="n">graph</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">([</span><span class="n">graph1</span><span class="p">,</span> <span class="n">graph2</span><span class="p">,</span> <span class="n">graph3</span><span class="p">,</span> <span class="n">graph4</span><span class="p">]):</span>
<span class="k">print</span> <span class="s">"graph"</span><span class="p">,</span> <span class="n">num</span> <span class="p">,</span> <span class="n">vertices_that_reach_all</span><span class="p">(</span><span class="n">graph</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area"><div class="prompt"></div>
<div class="output_subarea output_stream output_stdout output_text">
<pre>
graph 0 [0, 1, 2, 3, 4]
graph 1 [-1]
graph 2 [4]
graph 3 [0, 1, 2]
</pre>
</div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>This method gives us what we expected to be, and for the test cases for the challenge on Rosalind, it ran pretty well.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h4 id="implementation-notes">Implementation notes:</h4>
<p>4 nested loops is a piece of code you usually never want to see and I am sure that changing the graph representation would simplify that procedure. In the meantime what I am trying to achieve with this is the following:</p>
<p>The loops are basically creating the <code>FROM</code> and <code>TO</code> sets, but to get to that simplification, I need to go through every vertex on every component. From every to-vertex on the edges, add the component instead of the vertex.</p>
<ol style="list-style-type: decimal">
<li>Visit every component.</li>
<li>Visit every vertex on the component.</li>
<li>Visit every edge for the vertex.</li>
<li>Visit components to see if the other vertex is a member.</li>
</ol>
<p>One way to remove one loop would be to add a 'lookup table' where we could easily get the component of a given vertex.</p>
<p>Any comments? Know another way to solve this problem? Let me know on <a href="https://twitter.com/sergiobuj">@sergiobuj</a></p>
</div>
</div>
</div>
</div>
</div>
From Octopress to Pelican2014-08-10T22:38:00-07:00Sergio Boterotag:sergiobuj.github.io,2014-08-10:blog/2014/08/10/from-octopress-to-pelican/<p>If I want to blog about something the last thing I need is the blogging
framework getting in the way.</p>
<p>I don't blog much, but every time I wanted to write something I had to
basically relearn everything about my previous 'blog framework' to get
that working.</p>
<p>I was spending way too much time on 'not writing', making me delaying any
idea I wanted to put up. I considered moving to <a href="http://www.tumblr.com/">tumblr</a> or something like
it, but that was being too radical about it (also I like to feel at least
some ownership on the process).</p>
<p>Recently I came across a blog post from <a href="http://mathamy.com/">Amy Hanlon</a> about <a href="http://mathamy.com/migrating-to-github-pages-using-pelican.html">Migrating to GitHub Pages using Pelican</a>.
The process was very easy and motivated me to migrate from <a href="http://octopress.org/">Octopress</a>.</p>
<p>The migration was really easy and this is what I did:</p>
<ol>
<li>I followed the <em><a href="http://docs.getpelican.com">Pelican</a> setup</em> instructions (I left the fabric part out).</li>
<li>I moved my Markdown files from the previous blog and changed the metadata for the Pelican fields.</li>
<li>Added a new section I never published with the previous blog.</li>
<li>I made a couple of modifications to the <code>pelicanconf.py</code> file.</li>
<li>Publish to Github.</li>
</ol>
<p>I had to spend some time on step #2 because I was basically editing out the metadata
fields, but that is something that you can get done pretty easily once you master some
keyboard shortcuts.</p>
<p>The new section I wanted to put up is based and constructed using <a href="http://ipython.org/notebook.html">IPython notebooks</a>. A notebook
can be exported as HTML and embedded into a blog. I added a couple of <code>meta</code> tags
to the HTML head and Pelican accepted it, no questions asked.</p>
<p>At this point I was really happy with the outcome and was ready to push the new
blog to Github, when I noticed something.</p>
<p>In the previous blog, the routes where:</p>
<div class="highlight"><pre><span class="nl">http:</span><span class="c1">//sergiobuj.github.io/blog/YEAR/MONTH/DAY/POST-TITLE/</span>
</pre></div>
<p>And now I had</p>
<div class="highlight"><pre><span class="nl">http:</span><span class="c1">//localhost:8888/POST-TITLE/</span>
</pre></div>
<p>In my case this is not very important because of the traffic, but there is a
fundamental idea about those resources 'posts' that I would be breaking if I had
let this happen.</p>
<p>Imagine someone bookmarked one of your blog posts that they really liked and want
to come back and read it again. It won't matter how much you payed a designed for
a beautiful 404 page, a 404 page is frustrating for an user.</p>
<p>It might not be my case, but I want consistency. And this turned out to be a very
easy fix in Pelican. I added the following to the <code>pelicanconf.py</code> file:</p>
<div class="highlight"><pre><span class="n">ARTICLE_URL</span> <span class="o">=</span> <span class="err">'</span><span class="p">{</span><span class="n">category</span><span class="p">}</span><span class="o">/</span><span class="p">{</span><span class="n">date</span><span class="o">:%</span><span class="n">Y</span><span class="p">}</span><span class="o">/</span><span class="p">{</span><span class="n">date</span><span class="o">:%</span><span class="n">m</span><span class="p">}</span><span class="o">/</span><span class="p">{</span><span class="n">date</span><span class="o">:%</span><span class="n">d</span><span class="p">}</span><span class="o">/</span><span class="p">{</span><span class="n">slug</span><span class="p">}</span><span class="o">/</span><span class="err">'</span>
<span class="n">ARTICLE_SAVE_AS</span> <span class="o">=</span> <span class="err">'</span><span class="p">{</span><span class="n">category</span><span class="p">}</span><span class="o">/</span><span class="p">{</span><span class="n">date</span><span class="o">:%</span><span class="n">Y</span><span class="p">}</span><span class="o">/</span><span class="p">{</span><span class="n">date</span><span class="o">:%</span><span class="n">m</span><span class="p">}</span><span class="o">/</span><span class="p">{</span><span class="n">date</span><span class="o">:%</span><span class="n">d</span><span class="p">}</span><span class="o">/</span><span class="p">{</span><span class="n">slug</span><span class="p">}</span><span class="o">/</span><span class="n">index</span><span class="p">.</span><span class="n">html</span><span class="err">'</span>
<span class="n">SLUGIFY_SOURCE</span> <span class="o">=</span> <span class="err">'</span><span class="n">title</span><span class="err">'</span>
</pre></div>
<p>These options, and many more, are explained in the <a href="http://docs.getpelican.com/en/3.4.0/settings.html#url-settings">Pelican settings</a>.</p>
<p>Last step was getting the generated files to the Github page. In the version of
Pelican I used, a Github pages support is already available, but before <code>make github</code>
can work I had to create the git project and add the remote.</p>Using Tarjan's Algorithm2014-07-27T10:39:00-07:00Sergio Boterotag:sergiobuj.github.io,2014-07-27:coding-exercises/2014/07/27/using-tarjans-algorithm/
<div tabindex="-1" id="notebook" class="border-box-sizing">
<div class="container" id="notebook-container">
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="Strongly-Connected-Components-with-Tarjan's-Algorithm">Strongly Connected Components with Tarjan's Algorithm<a class="anchor-link" href="#Strongly-Connected-Components-with-Tarjan's-Algorithm">¶</a></h2>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>When we deal with Directed Graphs we will sometimes find a Strongly Conected Graph. Such graph has a path between every pair of nodes (vertexes) in the graph going on both directions.</p>
<p>When we refer to Strongly Connected Components in a graph, we speak about a group of nodes in the graph that satisfies this condition.</p>
<p><a href="http://en.wikipedia.org/wiki/Strongly_connected_component">Wikipedia</a> is a good place to find more about it.</p>
<p>In order to get the Strongly Conected Components I will use a Python implementation of <a href="http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm">Tarjan's Algorithm</a>. The implementation is practically a straightforward translation of the pseudocode shown on the page.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [1]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="n">graph</span> <span class="o">=</span> <span class="p">{</span>
<span class="mi">0</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">]),</span>
<span class="mi">1</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">3</span><span class="p">]),</span>
<span class="mi">2</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">]),</span>
<span class="mi">3</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">0</span><span class="p">]),</span>
<span class="mi">4</span><span class="p">:</span><span class="nb">set</span><span class="p">([</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">]),</span>
<span class="mi">5</span><span class="p">:</span><span class="nb">set</span><span class="p">([])</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [2]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="c"># Using networkx I will draw a simple graph for demonstration purposes.</span>
<span class="c"># Note: I am starting with networkx, sure there are better ways to create a Directed Graph. This is one.</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="kn">as</span> <span class="nn">plt</span>
<span class="kn">import</span> <span class="nn">networkx</span> <span class="kn">as</span> <span class="nn">nx</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="kn">as</span> <span class="nn">np</span>
<span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">G</span><span class="o">=</span><span class="n">nx</span><span class="o">.</span><span class="n">DiGraph</span><span class="p">()</span>
<span class="k">for</span> <span class="n">node</span><span class="p">,</span> <span class="n">edges</span> <span class="ow">in</span> <span class="n">graph</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">for</span> <span class="n">edge</span> <span class="ow">in</span> <span class="n">edges</span><span class="p">:</span>
<span class="n">G</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">edge</span><span class="p">)</span>
<span class="n">pos</span><span class="o">=</span><span class="n">nx</span><span class="o">.</span><span class="n">spring_layout</span><span class="p">(</span><span class="n">G</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_nodes</span><span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="n">pos</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">arrows</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_labels</span><span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="n">pos</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
</pre></div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area"><div class="prompt"></div>
<div class="output_png output_subarea ">
<img src="data:image/png;base64,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
IPgBAHjm/wDac2V8/E+9kAAAAABJRU5ErkJggg==
">
</div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>The wider end on the adges represent an arrow, indicatin the direction of the relation.</p>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [3]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="k">def</span> <span class="nf">tarjan</span><span class="p">(</span><span class="n">graph</span><span class="p">):</span>
<span class="c">#input: graph G = (V, E)</span>
<span class="c">#output: Array of strongly connected components (sets of vertices)</span>
<span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">graph</span><span class="p">)</span>
<span class="n">sccs</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">index</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">indexes</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span>
<span class="n">lows</span> <span class="o">=</span> <span class="p">[</span><span class="nb">float</span><span class="p">(</span><span class="s">'Inf'</span><span class="p">)]</span> <span class="o">*</span> <span class="n">n</span>
<span class="n">S</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span> <span class="nf">strongconnect</span><span class="p">(</span><span class="n">v</span><span class="p">):</span>
<span class="c"># Set the depth index for v to the smallest unused index</span>
<span class="n">indexes</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">index</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">index</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">index</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">S</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="c"># Consider successors of v</span>
<span class="k">for</span> <span class="n">chld</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">[</span><span class="n">v</span><span class="p">]:</span>
<span class="k">if</span> <span class="n">indexes</span><span class="p">[</span><span class="n">chld</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="c"># Successor chld has not yet been visited; recurse on it</span>
<span class="n">strongconnect</span><span class="p">(</span><span class="n">chld</span><span class="p">)</span>
<span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">],</span> <span class="n">lows</span><span class="p">[</span><span class="n">chld</span><span class="p">])</span>
<span class="k">elif</span> <span class="n">chld</span> <span class="ow">in</span> <span class="n">S</span><span class="p">:</span>
<span class="c"># Successor w is in stack S and hence in the current SCC</span>
<span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">],</span> <span class="n">lows</span><span class="p">[</span><span class="n">chld</span><span class="p">])</span>
<span class="c"># If v is a root node, pop the stack and generate an SCC</span>
<span class="k">if</span> <span class="n">lows</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="n">indexes</span><span class="p">[</span><span class="n">v</span><span class="p">]:</span>
<span class="n">scc</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="n">v</span><span class="p">])</span>
<span class="n">w</span> <span class="o">=</span> <span class="n">S</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="k">while</span> <span class="n">w</span> <span class="o">!=</span> <span class="n">v</span><span class="p">:</span>
<span class="n">scc</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">w</span><span class="p">)</span>
<span class="n">w</span> <span class="o">=</span> <span class="n">S</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
<span class="n">sccs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">scc</span><span class="p">)</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">graph</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
<span class="k">if</span> <span class="n">indexes</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="n">strongconnect</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">return</span> <span class="n">sccs</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [4]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="n">scc</span> <span class="o">=</span> <span class="n">tarjan</span><span class="p">(</span><span class="n">graph</span><span class="p">)</span>
<span class="n">scc</span>
</pre></div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area"><div class="prompt output_prompt">
Out[4]:</div>
<div class="output_text output_subarea output_pyout">
<pre>
[{0, 1, 3}, {5}, {2, 4}]
</pre>
</div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing code_cell rendered">
<div class="input">
<div class="prompt input_prompt">
In [5]:
</div>
<div class="inner_cell">
<div class="input_area">
<div class="highlight"><pre><span class="n">colors</span> <span class="o">=</span> <span class="p">[</span><span class="s">'r'</span><span class="p">,</span> <span class="s">'g'</span><span class="p">,</span> <span class="s">'b'</span><span class="p">]</span>
<span class="k">for</span> <span class="n">component</span><span class="p">,</span> <span class="n">color</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">scc</span><span class="p">,</span> <span class="n">colors</span><span class="p">):</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_nodes</span><span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">nodelist</span> <span class="o">=</span> <span class="n">component</span><span class="p">,</span> <span class="n">node_color</span> <span class="o">=</span> <span class="n">color</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">arrows</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_labels</span><span class="p">(</span><span class="n">G</span><span class="p">,</span> <span class="n">pos</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
</pre></div>
</div>
</div>
</div>
<div class="output_wrapper">
<div class="output">
<div class="output_area"><div class="prompt"></div>
<div class="output_png output_subarea ">
<img src="data:image/png;base64,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
eAbBDwDAM/8HgpZhy/3PhtUAAAAASUVORK5CYII=
">
</div>
</div>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered">
<div class="prompt input_prompt">
</div>
<div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p>This algorithm besides being good for a problem that required just an implementation was very useful in the case where I needed to 'reduce' a graph into a simpler representation (without cycles and extra edges).</p>
<p>Any comments? Let me know on <a href="https://twitter.com/sergiobuj">@sergiobuj</a></p>
</div>
</div>
</div>
</div>
</div>
Learn by Cloning2013-10-27T00:00:00-07:00Sergio Boterotag:sergiobuj.github.io,2013-10-27:learn-by-cloning/2013/10/27/learn-by-cloning/<p>I want to learn many things and some of those are libraries and tools to work
with data and visualize it. I will use <a href='http://ipython.org/notebook.html' target='_blank'>IPyhton notebooks</a>.</p>
<h5>Cloning to learn matplotlib</h5>
<p><a href='http://matplotlib.org' target='_blank'>Matplotlib</a> is the preferred python plotting library for
2D figures and is a very strong open source project. I believe the best way to
learn something is by doing. In order to learn matplotlib, without actually
having to use it for work or a publication, I will try to reproduce different
charts and graphs I see.</p>
<ul>
<li>
<p>[Exercise 0] Search terms 'cat', 'dog' and 'fish' from 2012. See it
<a href='http://nbviewer.ipython.org/7076810/learning_cloning_matplotlib_0.ipynb' target='_blank'>here</a>.</p>
</li>
<li>
<p>[Exercise 1] I found a comparison graph about the most lucrative majors and this is how my clone looks like. <a href='http://nbviewer.ipython.org/7076810/learning_cloning_matplotlib_1.ipynb' target='_blank'>link</a>.</p>
</li>
<li>[Exercise 2] I somehow failed to clone a graph that shows some data about Software Sales from Apple. The topic comes from the news since Apple made available the latest OS X for free. <a href='http://nbviewer.ipython.org/7076810/learning_cloning_matplotlib_2.ipynb' target='_blank'>Attempt here</a></li>
<li>[Exercise 3] Simple plot for tablet OS market share. Missing the gradient. <a href='http://nbviewer.ipython.org/7076810/learning_cloning_matplotlib_3.ipynb' target='_blank'>Link here</a></li>
</ul>Small Victories2013-04-08T21:58:00-07:00Sergio Boterotag:sergiobuj.github.io,2013-04-08:blog/2013/04/08/small-victories/<p>Lately I have been working in optimizing and parallelizing the ClusterPy library and at the moment, I can celebrate some 'Small Victories'.</p>
<p>So far I have been making small changes in places that have huge impact -functions that get called a lot and unnecessary function calling- and the timer now stops a bit earlier.</p>Opportunity in Parallelism2013-03-11T20:41:00-07:00Sergio Boterotag:sergiobuj.github.io,2013-03-11:blog/2013/03/11/opportunity-in-parallelism/<p>Beginning this week I will be working for a period of 3 months with the people of the Research in Spatial Economics group (<a href="http://www.rise-group.org/">RiSE</a>) at Universidad EAFIT. They developed a library of spatially constrained clustering algorithms named <a href="http://www.rise-group.org/risem/clusterpy/index.html">ClusterPy</a>. I will be helping them in making some optimizations and basically, in changing a few things to make the library able to run on clusters and reduce running times.</p>
<p>At the moment I will start looking at the following algorithms:</p>
<ul>
<li><a href="http://www.rise-group.org/risem/clusterpy/clusterpy0_9_9/endogenous.html#maxp-description">max-p</a></li>
<li><a href="http://www.rise-group.org/risem/clusterpy/clusterpy0_9_9/exogenous.html#azpsa-description">AZP SA</a></li>
<li><a href="http://www.rise-group.org/risem/clusterpy/clusterpy0_9_9/exogenous.html#azpt-description">AZPtabu</a></li>
</ul>
<p>This work has a huge impact since the library is currently being used by many people and the algorithms have already started many discussions in the topic. I hope I can make a good contribution to the project.</p>Studying with MOOCs2013-02-12T17:03:00-08:00Sergio Boterotag:sergiobuj.github.io,2013-02-12:blog/2013/02/12/studying-with-moocs/<p>Looking forward to studying a Master's in Computer Science (I am still waiting to be admitted), I decided to start refreshing some concepts about parallel programming and theoretical computer science with two online courses from Udacity. This concept of Massive Open Online Course (MOOC) works great because you do not need to wait for the next week for another set of videos or assignments, this however, requires a lot of commitment and discipline.</p>
<p>Right now I am following a course called <strong>"Introduction to Theoretical Computer Science"</strong> taught by <strong>Sebastian Wernicke</strong>, a course that focuses on the basic concepts in Computer Science and solving tough algorithmic problems. I just started the first unit and I am really enjoying this course. I want to get quickly to the NP-Completeness and NP-Complete Units.</p>
<p>The other course I am taking is <strong>"Introduction to Parallel Programming"</strong> taught by <strong>John Owens</strong> from <em><strong>UC Davis</strong></em> (fingers crossed) and <strong>David Luebke</strong> from <strong>NVIDIA</strong>. This course has only uploaded up to unit 2 and I am half way through it. It has presented some interesting patterns in parallel programming using CUDA and although it took me some attempts to get the first assignment correct, CUDA seems like a very powerful tool that I think I will be studying a little more.</p>
<p>So far so good, I am dedicating my time mainly to the documentation of the <a href="http://www.github.com/lms4labs/labmanager">Labmanager</a> project that I started contributing while on my visit to the <strong>C.E.C.I. MIT</strong> and preparing part of a publication about the use of <strong>IMS LTI</strong> on it. Besides that I have this online courses and running whenever I can.</p>New year, a note to self2013-01-08T09:44:00-08:00Sergio Boterotag:sergiobuj.github.io,2013-01-08:blog/2013/01/08/new-year-a-note-to-self/<p>After being away from the project for the holidays I started again to work on it
last week and there is something I have to remember as a note to self: "When taking
over a project, finish the new feature first and then improve the project."</p>
<p>And by improving the project I mean this time I am right now where I wanted the
source code to be well organized, a better project structure, to refactor and many
things that will benefit the health of the project and also any future developer's
health.</p>
<p>So, next time, finish the work you are supposed to do, and then contribute.</p>
<p>That was just a reminder to myself.</p>Labmanager for Learning Management Systems2012-12-01T00:35:00-08:00Sergio Boterotag:sergiobuj.github.io,2012-12-01:blog/2012/12/01/labmanager-for-learning-management-systems/<p>Since October 2012 I have been visiting the <strong>CECI</strong> Lab at the <strong>MIT</strong> and contributing to a project to allow single sign-on between learning management systems (Moodle, Sakai, dotLRN, etc) and remote laboratories management systems.
This will provide access to remote laboratories and other activities to students while they are in their school's system.</p>
<p>When I started with the project, a beta version was already developed and used a combination of SCORM package + LMS custom modules (modules or blocks depending on the LMS) to get the authorization and communication.</p>
<p>At the moment I am implementing this Labmanager to be able to provide tools that conform to the Learning Tool Interoperability standard from <a href="http://www.imsglobal.org">IMS Global</a>.</p>
<p>The code for the project is on <a href="http://github.com/lms4labs">Github</a>. It is a web application using Python and the Micro-framework Flask.</p>Rosalind: Learning Bioinformatics2014-08-11T16:06:00-07:00Sergio Boterotag:sergiobuj.github.io,2012-11-20:blog/2012/11/20/rosalind-learning-bioinformatics/<p><a href="http://rosalind.info">Rosalind.info</a> is a great project to learn Bioinformatics by solving programming challenges. The system is similar to the one you would find in the <a href="http://code.google.com/codejam">Google Code Jam</a> in which you are given a problem and a sample input and output. When you think you have solved the problem, you are given a dataset to solve and you give the answer.</p>
<p>What makes Rosalind special to me is that I came across it a while after enabling a <a href="http://www.rocksclusters.org/">Rocks cluster</a> at the university to run Bioinformatics problems using the <a href="http://www.rocksclusters.org/roll-documentation/bio/">Rocks bio roll</a>. I never quite understood the kind of problems that it solved, what they mean and what the symbols represent. Rosalind is great in that sense, since it gives you the opportunity to just go straight to the coding part but also offers a brief background on the purpose of the algorithm you will have to implement.</p>
<p>I have solved only a few challenges, and due to a project that I am updating at the moment, I decided to solve the challenges using Python.</p>
<p>The code is on <a href="https://github.com/sergiobuj/rosalind">Github/sergiobuj/rosalind</a> and the progress on the challenges is on <a href="http://rosalind.info/users/sergiobuj/">Rosalind/sergiobuj</a>.</p>
<p>If you would like to learn about Bioinformatics and you enjoy programming, you should definitely go to Rosalind and check it out.</p>The Elements of Style2012-01-17T17:02:00-08:00Sergio Boterotag:sergiobuj.github.io,2012-01-17:blog/2012/01/17/the-elements-of-style/<p>In this post I would like to thank <a href="https://github.com/nhocki">Hock</a> (<a href="https://twitter.com/nhocki">nhocki</a> on twitter) for a great gift. A gift that will teach me a lot about writing and that will, with no doubt, make a good writer out of me (hopefuly).
The gift was a book from William Strunk Jr. and E.B. White and it is called <a href="http://www.amazon.com/Elements-Style-4th-William-Strunk/dp/0205313426/ref=sr_1_1?ie=UTF8&qid=1326839018&sr=8-1">The Elements of Style</a>.</p>
<p><img alt="The Elements of Style cover from amazon.com" src="http://ecx.images-amazon.com/images/I/51yQb9-P84L._SS400_.jpg" title="Cover image from Amazon.com" /></p>
<p>The only thing left to say is that I intend to write each post better than the previous (in terms of style, grammar, sense, vocabulary and structure) and that any comments about it are very welcome.</p>
<p>Sergio B.</p>
<p>(Took me about 38 minutes to get this post done, count the markdown refresher there)</p>Hubzero Submit Installation2011-11-01T16:45:00-07:00Sergio Boterotag:sergiobuj.github.io,2011-11-01:blog/2011/11/01/hubzero-submit-installation/<p>There are two machines/locations involved in the installation. The hub as <strong>HUB</strong> and the cluster controller as <strong>CLUSTER</strong>.
Through this installation the <strong>$HOME</strong> directory on <strong>CLUSTER</strong> will refer to the home directory of the user that will be used to submit the jobs to the cluster (for most purposes would be any user other than root).</p>
<h1>INSTALLATION</h1>
<h2>HUB</h2>
<div class="highlight"><pre><span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="n">hubzero</span><span class="o">-</span><span class="n">app</span><span class="o">-</span><span class="n">submit</span>
<span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="n">hubzero</span><span class="o">-</span><span class="n">submit</span><span class="o">-</span><span class="n">server</span>
<span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="n">hubzero</span><span class="o">-</span><span class="n">submit</span><span class="o">-</span><span class="n">distributor</span>
</pre></div>
<hr />
<h1>MOVING FILES AROUND</h1>
<p>Files can be easily transfered between <em>HUB</em> and <em>CLUSTER</em> using the <code>scp</code> command.</p>
<h2>HUB</h2>
<p><code>cd</code> to the submit directory (<code>/opt/submit</code> by default) and add the public key found in <code>ssh/submit_rsa.pem</code> to the authorized keys file on <em>CLUSTER</em> <em>$HOME</em><code>/.ssh/authorized_keys</code>.</p>
<h2>CLUSTER:</h2>
<p>Create directories <code>submit</code>, <code>log</code>, <code>bin</code> and <code>scratch</code>.</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">mkdir</span> <span class="o">-</span><span class="n">p</span> <span class="err">$</span><span class="n">HOME</span><span class="o">/</span><span class="n">submit</span><span class="o">/</span><span class="n">log</span>
<span class="err">$</span> <span class="n">mkdir</span> <span class="o">-</span><span class="n">p</span> <span class="err">$</span><span class="n">HOME</span><span class="o">/</span><span class="n">bin</span>
<span class="err">$</span> <span class="n">mkdir</span> <span class="o">-</span><span class="n">p</span> <span class="err">$</span><span class="n">HOME</span><span class="o">/</span><span class="n">scratch</span>
</pre></div>
<h2>HUB:</h2>
<p>Copy the scripts needed for the Batch System that is going to be used from <code>BatchMonitors/<YOUR BATCH SYSTEM></code> directory to <em>CLUSTER</em> <em>$HOME</em><code>/submit</code></p>
<p>Copy file <code>LogMessage.py</code> to <em>CLUSTER</em> <em>$HOME</em><code>/submit</code></p>
<p>Copy files from the <code>Scripts/<YOUR BATCH SYSTEM></code> directory to <em>CLUSTER</em> <em>$HOME</em><code>/bin</code></p>
<p>In case it exists, remove file <code>/etc/submit/config</code></p>
<h2>CLUSTER:</h2>
<p>Make sure the files in <em>$HOME</em><code>/bin</code> are executable, this can simply be done using:
<code>$ chmod +x $HOME/bin/*</code></p>
<h2>HUB:</h2>
<p>Check the ownership of the file <code>monitorJobDB</code>, it should belong to <code>gridman</code> and group <code>gridman</code>.
To change it simply <code># chown gridman.gridman monitorJobDB</code></p>
<p>Use <code>visudo</code> to give permissions over the <code>bin/update_known_hosts</code> file adding this entry:
<code>ALL ALL=NOPASSWD:/opt/submit/bin/update-known-hosts</code></p>
<ul>
<li>The path should be changed in case that the installation was made on a different directory.</li>
</ul>
<hr />
<h1>FILL IN CONFIGURATION FILES</h1>
<h2>HUB:</h2>
<p>Add information to <code>sites.dat</code></p>
<div class="highlight"><pre><span class="k">[venue_name]</span>
<span class="na">venues</span> <span class="o">=</span> <span class="s"><comma separated list of venues></span>
<span class="na">remoteBatchSystem</span> <span class="o">=</span> <span class="s"><PBS or CONDOR or...></span>
<span class="na">remotePpn</span> <span class="o">=</span> <span class="s"><Has to be specified, if unknown set to 1></span>
<span class="na">checkProbeResult</span> <span class="o">=</span> <span class="s">false</span>
<span class="na">remoteScratchDirectory</span> <span class="o">=</span> <span class="s"><path on CLUSTER $HOME/scratch></span>
<span class="na">siteMonitorDesignator</span> <span class="o">=</span> <span class="s">monitor_name</span>
<span class="na">venueMechanism</span> <span class="o">=</span> <span class="s"><ssh or local></span>
<span class="na">remoteUser</span> <span class="o">=</span> <span class="s"><username on the CLUSTER></span>
</pre></div>
<p>Add information to <code>monitors.dat</code></p>
<div class="highlight"><pre><span class="k">[monitor_name]</span>
<span class="na">venue</span> <span class="o">=</span> <span class="s"><venue_name></span>
<span class="na">remoteUser</span> <span class="o">=</span> <span class="s"><username on the CLUSTER></span>
<span class="na">venueMechanism</span> <span class="o">=</span> <span class="s"><ssh or local></span>
<span class="na">remoteMonitorCommand</span> <span class="o">=</span> <span class="s"><path on CLUSTER $HOME/submit/MONITOR-SCRIPT></span>
</pre></div>
<ul>
<li>Where <code>MONITOR-SCRIPT</code> should be changed to match the script according to your Batch System.</li>
</ul>
<hr />
<h1>EDIT FILES</h1>
<h2>HUB:</h2>
<p>Edit file <code>/etc/hubzero/maxwell.conf</code> and add the lines following lines (3) before the hub information.</p>
<div class="highlight"><pre><span class="n">visualization_params</span><span class="o">=</span><span class="s2">"""</span>
<span class="s2">submit_target tcp://<SUBMIT_SERVER_LOCATION>:830</span>
<span class="s2">"""</span>
</pre></div>
<h2>CLUSTER:</h2>
<p>Edit the monitor file on <em>$HOME</em><code>/submit/MONITOR-SCRIPT</code> to set this variables.</p>
<div class="highlight"><pre><span class="n">SITEDESIGNATOR</span> <span class="o">=</span> <span class="n">monitor_name</span> <span class="err">#</span><span class="n">Same</span> <span class="n">as</span> <span class="n">HUB</span> <span class="n">monitors</span><span class="p">.</span><span class="n">dat</span>
<span class="n">MONITORROOT</span> <span class="o">=</span> <span class="o"><</span><span class="n">Adjust</span> <span class="n">path</span> <span class="n">to</span> <span class="err">$</span><span class="n">HOME</span><span class="o">/</span><span class="n">submit</span><span class="o">></span>
<span class="n">MONITORLOGLOCATION</span> <span class="o">=</span> <span class="o"><</span><span class="n">Adjust</span> <span class="n">path</span> <span class="n">to</span> <span class="err">$</span><span class="n">HOME</span><span class="o">/</span><span class="n">submit</span><span class="o">/</span><span class="n">log</span><span class="o">></span>
</pre></div>
<p>If you are using CONDOR and the executables are already in the user PATH set this:</p>
<div class="highlight"><pre><span class="n">CONDOR_ROOT</span> <span class="o">=</span> <span class="s">""</span>
<span class="n">CONDOR_CONFIG</span> <span class="o">=</span> <span class="s">""</span>
</pre></div>
<hr />
<h1>DONE!</h1>
<p><em>HUB:</em> Start or Restart <code>submon</code> and <code>submit-server</code> daemons.</p>
<div class="highlight"><pre><span class="c"># /etc/init.d/submit-server start</span>
<span class="c"># /etc/init.d/submon start</span>
</pre></div>For the next 2.5 months2011-08-08T17:10:00-07:00Sergio Boterotag:sergiobuj.github.io,2011-08-08:blog/2011/08/08/for-the-next-25-months/<p>The Purdue University (IN, US) is working closely with EAFIT University (ANT, CO) on a project to set up a supercomputer on EAFIT and be able to support some of the current scientific research in Colombia by providing the computational capabilities needed to process large sets of data and the creation and visualization of simulations.</p>
<p>From October 5th 2011 until December 13th 2011, West Lafayette will be my home. Where I will be learning about the internals of the <a href="http://www.hubzero.org">Hubzero platform</a>, and how to replicate the success it's had.</p>
<p>More about the trip and stuff.</p>