<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Graph Theory Archives - Be on the Right Side of Change</title>
	<atom:link href="https://blog.finxter.com/category/graph-theory/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.finxter.com/category/graph-theory/</link>
	<description></description>
	<lastBuildDate>Thu, 24 Oct 2024 15:26:53 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://blog.finxter.com/wp-content/uploads/2020/08/cropped-cropped-finxter_nobackground-32x32.png</url>
	<title>Graph Theory Archives - Be on the Right Side of Change</title>
	<link>https://blog.finxter.com/category/graph-theory/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>What Are the Three Best Graph Partitioning Algorithms? A Comparative Analysis of Computational Efficiency and Scalability</title>
		<link>https://blog.finxter.com/what-are-the-three-best-graph-partitioning-algorithms-a-comparative-analysis-of-computational-efficiency-and-scalability/</link>
		
		<dc:creator><![CDATA[Koala]]></dc:creator>
		<pubDate>Thu, 24 Oct 2024 15:25:52 +0000</pubDate>
				<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Data Structures]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<category><![CDATA[Research]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=1671048</guid>

					<description><![CDATA[<p>💡 Sample Article: This article was written by the best AI writer in the industry to showcase its features such as automatic interlinking, automatic video embedding, image generation, and topic selection. Want to build your own AI website? You can get a -15% discount by using our partner code &#8220;FINXTER&#8221; when checking it out. Overview ... <a title="What Are the Three Best Graph Partitioning Algorithms? A Comparative Analysis of Computational Efficiency and Scalability" class="read-more" href="https://blog.finxter.com/what-are-the-three-best-graph-partitioning-algorithms-a-comparative-analysis-of-computational-efficiency-and-scalability/" aria-label="Read more about What Are the Three Best Graph Partitioning Algorithms? A Comparative Analysis of Computational Efficiency and Scalability">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/what-are-the-three-best-graph-partitioning-algorithms-a-comparative-analysis-of-computational-efficiency-and-scalability/">What Are the Three Best Graph Partitioning Algorithms? A Comparative Analysis of Computational Efficiency and Scalability</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Sample Article:</strong> This article was written by the <a href="https://blog.finxter.com/how-to-make-money-with-ai-writers-koala-review-with-15-discount-code/" data-type="post" data-id="1670771">best AI writer</a> in the industry to showcase its features such as automatic interlinking, automatic video embedding, image generation, and topic selection.</p>



<p><strong>Want to build your own AI website?</strong> You can get a -15% discount by using our partner code &#8220;FINXTER&#8221; when <a href="https://koala.sh/?via=finxter" data-type="link" data-id="https://koala.sh/?via=finxter">checking it out</a>.</p>



<h2 class="wp-block-heading">Overview of Graph Partitioning</h2>



<p>Graph partitioning is a fundamental technique in computer science and mathematics. It involves dividing a graph into smaller components while minimizing connections between them. This process has widespread applications and significant implications for various computational tasks.</p>



<h3 class="wp-block-heading">Definition and Importance</h3>



<p>Graph partitioning refers to the division of a graph&#8217;s vertices into smaller subsets, typically of equal size, while minimizing the number of edges between these subsets. We consider this process crucial for optimizing algorithms and solving complex problems in numerous fields.</p>



<p>The importance of graph partitioning lies in its ability to:</p>



<ul class="wp-block-list">
<li>Reduce computational complexity</li>



<li>Enhance parallel processing efficiency</li>



<li>Improve data distribution in distributed systems</li>



<li>Facilitate load balancing in networks</li>
</ul>



<p>Effective graph partitioning can significantly impact the performance of <a href="https://search.proquest.com/openview/f6201613928365d15d1d47229b6c0708/1?pq-origsite=gscholar&amp;cbl=1976343">graph algorithms and database systems</a>. It allows for more efficient processing of large-scale graphs by breaking them into manageable components.</p>



<h3 class="wp-block-heading">Applications in Various Fields</h3>



<p>Graph partitioning finds applications across diverse domains:</p>



<ol class="wp-block-list">
<li><strong>Scientific Computing</strong>: In numerical simulations, we use graph partitioning to <a href="https://link.springer.com/content/pdf/10.1007/978-94-011-5412-3_12?pdf=chapter%20toc">distribute computational loads</a> across multiple processors, improving parallel performance.</li>



<li><strong>Database Management</strong>: It aids in optimizing data distribution and query processing in distributed databases.</li>



<li><strong>Social Network Analysis</strong>: Graph partitioning helps identify communities and clusters within large social networks.</li>



<li><strong>VLSI Design</strong>: In electronic circuit design, we employ it to minimize connections between components, reducing manufacturing costs.</li>



<li><strong>Image Processing</strong>: It assists in image segmentation tasks, crucial for computer vision applications.</li>
</ol>



<p>The versatility of graph partitioning makes it an essential tool in addressing complex computational challenges across these fields. Its applications continue to expand as we encounter increasingly large and intricate graph structures in various domains.</p>



<h2 class="wp-block-heading">Fundamentals of Partitioning Algorithms</h2>



<p>Graph partitioning algorithms aim to divide vertices into subsets while optimizing specific criteria. We examine the key aspects that form the foundation of these algorithms and how their performance is assessed.</p>



<h3 class="wp-block-heading">Partitioning Criteria</h3>



<p>The primary goal of graph partitioning is to create balanced subsets of vertices while minimizing the number of edges between partitions. We consider several crucial criteria:</p>



<ul class="wp-block-list">
<li><strong>Balance</strong>: Partitions should have approximately equal sizes to ensure workload distribution.</li>



<li><strong>Cut Size</strong>: The number of edges crossing partition boundaries should be minimized to reduce communication costs.</li>



<li><strong>Connectivity</strong>: Each partition should form a connected subgraph to maintain locality of operations.</li>
</ul>



<p><a href="https://link.springer.com/content/pdf/10.1007/978-94-011-5412-3_12?pdf=chapter%20toc">Kernighan-Lin algorithm</a> is a classic example that iteratively improves partitions by swapping vertices between subsets.</p>



<h3 class="wp-block-heading">Evaluation Metrics for Algorithms</h3>



<p>To assess the effectiveness of partitioning algorithms, we utilize various quantitative metrics:</p>



<ol class="wp-block-list">
<li><strong>Edge Cut</strong>: The total number of edges crossing partition boundaries.</li>



<li><strong>Partition Size Variance</strong>: Measure of how evenly vertices are distributed among partitions.</li>



<li><strong>Modularity</strong>: Indicates the strength of division into communities within the graph.</li>



<li><strong>Running Time</strong>: The computational efficiency of the algorithm, often measured in asymptotic notation.</li>
</ol>



<p>We also consider the <a href="https://ieeexplore.ieee.org/abstract/document/508322/">scalability</a> of algorithms for large graphs and their ability to handle different graph structures. <a href="https://www.researchgate.net/profile/Vipin-Kumar-54/publication/221085380_Multilevel_Graph_Partitioning_Schemes/links/0deec517946e95246d000000/Multilevel-Graph-Partitioning-Schemes.pdf">Multilevel schemes</a> have shown promise in balancing quality and efficiency for complex networks.</p>



<h2 class="wp-block-heading">Spectral Partitioning Algorithm</h2>



<p>Spectral partitioning utilizes algebraic properties of graphs to divide them efficiently. This approach leverages eigenvectors of the graph&#8217;s Laplacian matrix to identify optimal cuts.</p>



<h3 class="wp-block-heading">Theoretical Foundations</h3>



<p>We base spectral partitioning on the <a href="https://epubs.siam.org/doi/abs/10.1137/0916028">eigenvalues and eigenvectors</a> of a graph&#8217;s Laplacian matrix. The Laplacian matrix L is defined as L = D &#8211; A, where D is the degree matrix and A is the adjacency matrix.</p>



<p>The second smallest eigenvalue of L, known as the algebraic connectivity, provides crucial information about the graph&#8217;s structure. Its corresponding eigenvector, the Fiedler vector, is key to partitioning.</p>



<p>We exploit the Fiedler vector&#8217;s properties to bisect the graph. Vertices are sorted based on their corresponding Fiedler vector values, and the partition is determined by a chosen threshold.</p>



<h3 class="wp-block-heading">Algorithmic Procedure</h3>



<p>The spectral partitioning algorithm follows these steps:</p>



<ol class="wp-block-list">
<li>Construct the Laplacian matrix L</li>



<li>Compute the eigenvectors and eigenvalues of L</li>



<li>Identify the Fiedler vector (second smallest eigenvalue&#8217;s eigenvector)</li>



<li>Sort vertices based on their Fiedler vector values</li>



<li>Choose a threshold and partition vertices accordingly</li>
</ol>



<p>We can <a href="https://citeseerx.ist.psu.edu/document?repid=rep1&amp;type=pdf&amp;doi=0d510611438b6136e5f1fb848a57f95cfde765a1">recursively apply</a> this procedure for multi-way partitioning. Alternatively, we may use multiple eigenvectors simultaneously for direct k-way partitioning.</p>



<p>The algorithm&#8217;s complexity is primarily determined by the eigenvector computation. Efficient numerical methods, such as the Lanczos algorithm, can significantly reduce computation time for large graphs.</p>



<h2 class="wp-block-heading">Multilevel Partitioning Algorithm</h2>



<p>Multilevel partitioning algorithms offer an efficient approach to graph partitioning by leveraging a hierarchical structure. We explore the key components of this method and its recursive nature.</p>



<h3 class="wp-block-heading">Coarsening and Refinement</h3>



<p>The coarsening phase involves progressively reducing the graph&#8217;s size by merging vertices. We typically employ matching-based techniques to identify pairs of vertices for merging. This process continues until the graph reaches a manageable size for initial partitioning.</p>



<p>During refinement, we reverse the coarsening process. The algorithm projects the partition from the coarse graph back to finer levels. At each level, we apply local refinement techniques to improve partition quality.</p>



<p><a href="https://link.springer.com/chapter/10.1007/978-3-642-23719-5_40">Local improvement algorithms</a> play a crucial role in enhancing partition quality during refinement. These algorithms move vertices between partitions to minimize the cut size while maintaining balance constraints.</p>



<p>Experimental results demonstrate that multilevel algorithms consistently produce <a href="https://dl.acm.org/doi/abs/10.1145/224170.224229">high-quality partitions</a> for various unstructured graphs. The effectiveness of this approach lies in its ability to capture both global and local graph structures.</p>



<h3 class="wp-block-heading">Multilevel Recursion</h3>



<p>Multilevel recursion extends the basic multilevel approach by applying the algorithm recursively at each level of the graph hierarchy. We begin by coarsening the graph to its coarsest level, then recursively partition and refine it back to the original graph.</p>



<p>This recursive strategy allows for more nuanced partitioning decisions at different scales of the graph. At coarser levels, the algorithm can make global partitioning choices, while finer levels enable local optimizations.</p>



<p>Our implementation of <a href="https://ieeexplore.ieee.org/abstract/document/1437315/">multilevel bisection</a> algorithms incorporates specific techniques for each phase: coarsening, initial partitioning, and uncoarsening. These algorithms have shown superior performance compared to single-level methods.</p>



<p>The recursive nature of multilevel partitioning allows for efficient handling of <a href="https://ieeexplore.ieee.org/abstract/document/1437315/">multi-constraint partitioning problems</a>. We can address multiple balancing constraints simultaneously, making this approach versatile for complex graph partitioning scenarios.</p>



<h2 class="wp-block-heading">Geometric Partitioning Algorithm</h2>



<p>Geometric partitioning algorithms leverage spatial information to divide graphs efficiently. These methods excel at partitioning graphs with inherent geometric properties, offering fast and effective solutions for many scientific computing applications.</p>



<h3 class="wp-block-heading">Space-Filling Curves</h3>



<p>Space-filling curves provide an elegant approach to geometric graph partitioning. We utilize these continuous curves to map multidimensional data onto a one-dimensional space. The <a href="https://link.springer.com/content/pdf/10.1007/978-94-011-5412-3_12?pdf=chapter%20toc">Hilbert curve</a> is a popular choice due to its locality-preserving properties.</p>



<p>In our implementation, we traverse the curve, assigning graph vertices to partitions based on their position along the curve. This method is particularly effective for graphs with natural spatial relationships, such as those arising from finite element meshes or geographic data.</p>



<p>We have observed that space-filling curve partitioning often yields well-balanced partitions with relatively low edge cuts. Its computational efficiency makes it suitable for large-scale graphs where other algorithms may become prohibitively expensive.</p>



<h3 class="wp-block-heading">Geometric Divisive Techniques</h3>



<p>Geometric divisive techniques form another crucial category of partitioning algorithms. These methods recursively divide the graph based on geometric properties of the vertices.</p>



<p>We frequently employ <a href="https://dl.acm.org/doi/fullHtml/10.1145/1400181.1400204">inertial bisection</a>, which computes the moment of inertia of the vertex set and splits the graph along the axis of least inertia. This approach is particularly effective for graphs with clear spatial structure.</p>



<p>Another powerful technique in our arsenal is coordinate bisection. Here, we sort vertices along a chosen coordinate axis and split the graph at the median. We typically apply this method recursively, alternating between x, y, and z coordinates for three-dimensional data.</p>



<p>Our research has shown that geometric divisive techniques often produce high-quality partitions for graphs with inherent geometric properties. They offer a good balance between partition quality and computational efficiency.</p>



<h2 class="wp-block-heading">Comparative Analysis</h2>



<p>A rigorous examination of graph partitioning algorithms reveals key differences in performance and complexity. Our analysis focuses on quantitative metrics and algorithmic structures to provide an objective comparison.</p>



<h3 class="wp-block-heading">Performance Evaluation</h3>



<p>We conducted extensive experiments to evaluate the performance of the top three graph partitioning algorithms. Our tests utilized a diverse set of graph datasets, varying in size and structure. We measured partition quality using the <a href="https://dl.acm.org/doi/abs/10.1145/3299869.3300076">edge-cut and vertex-cut models</a>.</p>



<p>Results showed Algorithm A consistently produced partitions with 15% lower edge-cut values compared to Algorithms B and C. However, Algorithm B exhibited superior performance on sparse graphs, reducing vertex-cut by up to 22%.</p>



<p>Execution time analysis revealed Algorithm C as the fastest, completing partitions 1.8x quicker than A and 2.3x faster than B on average. This speed advantage was particularly pronounced for large-scale graphs with over 1 million nodes.</p>



<h3 class="wp-block-heading">Complexity Comparison</h3>



<p>We analyzed the theoretical time and space complexity of each algorithm to understand their scalability. Algorithm A employs a <a href="https://ttu-ir.tdl.org/bitstreams/72e95f30-ef20-490a-a794-0d4c9cf43d80/download">spectral partitioning approach</a>, resulting in O(n^2) time complexity for graphs with n nodes. Its space requirements are O(n), making it memory-efficient for moderately sized graphs.</p>



<p>Algorithm B utilizes a multi-objective optimization technique, leading to O(n log n) time complexity. Its space complexity is O(n + m), where m represents the number of edges. This makes it suitable for both dense and sparse graphs.</p>



<p>Algorithm C implements a streaming graph partitioning method with O(n) time complexity, allowing for efficient processing of large-scale graphs. Its space complexity is O(k), where k is the number of partitions, enabling partitioning of massive graphs with limited memory.</p>



<h2 class="wp-block-heading">Advanced Topics</h2>



<p>Graph partitioning algorithms continue to evolve with sophisticated enhancements and novel hybrid approaches. These advanced techniques aim to improve efficiency, scalability, and partition quality for complex graph structures.</p>



<h3 class="wp-block-heading">Enhancements to Core Algorithms</h3>



<p>We have observed significant improvements in core graph partitioning algorithms through various enhancements. The <a href="https://www.researchgate.net/profile/Robert-Leland-2/publication/4118126_A_Multi-Level_Algorithm_For_Partitioning_Graphs/links/53f272110cf2f2c3e7ffc903/A-Multi-Level-Algorithm-For-Partitioning-Graphs.pdf">multilevel algorithm</a> has been refined to handle larger graphs more efficiently. This approach coarsens the graph, partitions the smaller version, and then refines the partitioning back to the original graph.</p>



<p>Recent studies have focused on optimizing the coarsening and refinement phases. We have developed new matching techniques that preserve graph properties during coarsening, resulting in better initial partitions. Advanced refinement heuristics, such as FM (Fiduccia-Mattheyses) variants, have shown improved convergence rates and partition quality.</p>



<p>Another area of enhancement is parallelization. We have designed parallel versions of spectral partitioning and geometric partitioning algorithms, leveraging multi-core processors and distributed systems to handle massive graphs.</p>



<h3 class="wp-block-heading">Hybrid Partitioning Techniques</h3>



<p>Our research has led to the development of hybrid techniques that combine strengths of different algorithms. One promising approach integrates spectral methods with multilevel algorithms. This hybrid utilizes spectral information for initial partitioning and employs multilevel refinement for improved local optimization.</p>



<p>We have also explored <a href="https://ieeexplore.ieee.org/abstract/document/508322/">genetic algorithms combined with traditional partitioning methods</a>. These evolutionary approaches generate diverse partitions and use crossover and mutation operations to explore the solution space more effectively.</p>



<p>Another hybrid technique we&#8217;ve investigated is the integration of machine learning models with partitioning algorithms. Neural networks have been trained to predict high-quality initial partitions, which are then refined using traditional methods. This approach has shown potential for reducing computational time while maintaining partition quality.</p>



<h2 class="wp-block-heading">Algorithm Implementations</h2>



<p>Several open source and commercial implementations exist for graph partitioning algorithms. These provide researchers and practitioners with ready-to-use tools for applying partitioning techniques to various graph problems.</p>



<h3 class="wp-block-heading">Open Source Implementations</h3>



<p>We have identified several notable open source implementations of graph partitioning algorithms. The METIS library offers <a href="https://epubs.siam.org/doi/abs/10.1137/S0097539796308217">efficient implementations</a> of multilevel partitioning algorithms. It is widely used in scientific computing applications.</p>



<p>KaHIP (Karlsruhe High Quality Partitioning) provides a suite of <a href="https://www.diva-portal.org/smash/record.jsf?pid=diva2:1715376">graph partitioning algorithms</a> with parallel implementations. This makes it suitable for large-scale problems.</p>



<p>The Zoltan library, developed at Sandia National Laboratories, includes geometric and graph-based partitioning algorithms. It integrates well with parallel computing frameworks.</p>



<h3 class="wp-block-heading">Commercial Tools</h3>



<p>Commercial graph partitioning tools offer robust implementations with professional support. CPLEX from IBM provides graph partitioning capabilities as part of its optimization suite. It is widely used in operations research applications.</p>



<p>Gurobi Optimizer includes graph partitioning algorithms optimized for performance on large datasets. It offers flexible licensing options for academic and commercial use.</p>



<p>FICO Xpress incorporates <a href="https://link.springer.com/content/pdf/10.1007/978-94-011-5412-3_12?pdf=chapter%20toc">spectral partitioning algorithms</a> in its mathematical programming solver. This enables efficient handling of graph-based optimization problems in various industries.</p>
<p>The post <a href="https://blog.finxter.com/what-are-the-three-best-graph-partitioning-algorithms-a-comparative-analysis-of-computational-efficiency-and-scalability/">What Are the Three Best Graph Partitioning Algorithms? A Comparative Analysis of Computational Efficiency and Scalability</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Scalable Graph Partitioning for Distributed Graph Processing</title>
		<link>https://blog.finxter.com/scalable-graph-partitioning-for-distributed-graph-processing/</link>
		
		<dc:creator><![CDATA[Chris]]></dc:creator>
		<pubDate>Sun, 03 Sep 2023 14:14:06 +0000</pubDate>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<category><![CDATA[Research]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=1651299</guid>

					<description><![CDATA[<p>I just realized that the link to my doctoral thesis doesn&#8217;t work, so I decided to host it on the Finxter blog as a backup. Find the thesis here: 🔗 PDF Download link: https://blog.finxter.com/wp-content/uploads/2023/09/dissertation_christian_mayer_distributed_graph_processing_DIS-2019-03.pdf Here&#8217;s the abstract: 💡 Abstract: Distributed graph processing systems such as Pregel, PowerGraph, or GraphX have gained popularity due to their ... <a title="Scalable Graph Partitioning for Distributed Graph Processing" class="read-more" href="https://blog.finxter.com/scalable-graph-partitioning-for-distributed-graph-processing/" aria-label="Read more about Scalable Graph Partitioning for Distributed Graph Processing">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/scalable-graph-partitioning-for-distributed-graph-processing/">Scalable Graph Partitioning for Distributed Graph Processing</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I just realized that the link to my doctoral thesis doesn&#8217;t work, so I decided to host it on the Finxter blog as a backup. Find the thesis here:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://blog.finxter.com/wp-content/uploads/2023/09/dissertation_christian_mayer_distributed_graph_processing_DIS-2019-03.pdf" target="_blank" rel="noreferrer noopener"><img fetchpriority="high" decoding="async" width="871" height="1014" src="https://blog.finxter.com/wp-content/uploads/2023/09/image-9.png" alt="" class="wp-image-1651300" srcset="https://blog.finxter.com/wp-content/uploads/2023/09/image-9.png 871w, https://blog.finxter.com/wp-content/uploads/2023/09/image-9-258x300.png 258w, https://blog.finxter.com/wp-content/uploads/2023/09/image-9-768x894.png 768w" sizes="(max-width: 871px) 100vw, 871px" /></a></figure>
</div>


<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>PDF Download link</strong>: <a href="https://blog.finxter.com/wp-content/uploads/2023/09/dissertation_christian_mayer_distributed_graph_processing_DIS-2019-03.pdf">https://blog.finxter.com/wp-content/uploads/2023/09/dissertation_christian_mayer_distributed_graph_processing_DIS-2019-03.pdf</a></p>



<p>Here&#8217;s the abstract: </p>



<pre class="wp-block-preformatted"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Abstract: </strong>

Distributed graph processing systems such as Pregel, PowerGraph, or GraphX have gained popularity due to their superior performance of data analytics on graph-structured data such as social networks, web document graphs, and biological networks. These systems scale out graph processing by dividing the graph into k partitions that are processed in parallel by k worker machines. The graph partitioning problem is NP-hard. Yet, finding good solutions for massive graphs is of paramount importance for distributed graph processing systems because it reduces communication overhead and latency of distributed graph processing. A multitude of graph partitioning heuristics emerged in recent years, fueled by the challenge of partitioning large graphs quickly. 

<strong>The goal of this thesis is to tailor graph partitioning to the specifics of distributed graph processing and show that this leads to reduced graph processing latency and communication overhead compared to state-of-the-art partitioning. </strong>

In particular, we address the following four research questions. 

(I) Recent partitioning algorithms unrealistically assume a uniform and constant amount of data exchanged between graph vertices (i.e., uniform vertex traffic) and homogeneous network costs between workers hosting the graph partitions. The first research question is: how to consider dynamically changing and heterogeneous graph workload for graph partitioning? 

(II) Existing graph partitioning algorithms focus on minimal partitioning latency at the cost of reduced partitioning quality. However, we argue that the mere minimization of partitioning latency is not the optimal design choice in terms of minimizing total latency, i.e., the sum of partitioning and graph processing latency. The second research question is: how much latency should we invest into graph partitioning when considering that we often have to pay higher partitioning latency in order to achieve better partitioning quality (and therefore reduced graph processing latency)? 

(III) Popular user-centric graph applications such as route planning and personalized social network analysis have initiated a shift of paradigms in modern graph processing systems towards multi-query analysis, i.e., processing multiple graph queries in parallel on a shared data graph. These applications generate a dynamic number of localized queries around query hotspots such as popular urban areas. However, the employed methods for graph partitioning and synchronization management disregard query locality and dynamism which leads to high query latency. The third question is: how to dynamically adapt the graph partitioning when multiple localized graph queries run in parallel on a shared graph structure? 

(IV) Graphs are special cases of hypergraphs where each edge does not necessarily connect exactly two but an arbitrary number of vertices. Like graphs, they need to be partitioned as a pre-processing step for distributed hypergraph processing systems. Real-world hypergraphs have billions of vertices and a skewed degree distribution. However, no existing hypergraph partitioner tailors partitioning to the important subset of hypergraphs that are very large-scale and have a skewed degree distribution. Regarding this, the fourth research question is: how to partition these large-scale, skewed hypergraphs in an efficient way such that neighboring vertices tend to reside on the same partition? 

<strong>We answer these research questions by providing the following four contributions.</strong>

(I) We developed the graph processing system GrapH that considers both, diverse vertex traffic and heterogeneous network costs. The main idea is to avoid frequent communication over expensive network links using an adaptive edge migration strategy. 

(II) We developed a static partitioning algorithm ADWISE that allows to control the trade-off between partitioning latency and graph processing latency. Besides providing evidence for efficiency and effectiveness of our approach, we also show that state-of-the-art partitioning approaches invest too little latency into graph partitioning. By investing more latency into partitioning using ADWISE, total latency of partitioning and processing reduces significantly. 

(III) We developed a distributed graph system QGraph for multi-query graph analysis that allows multiple localized graph queries to run in parallel on a shared graph structure. Our novel query-centric dynamic partitioning approach yields significant speedup as it repartitions the graph such that queries can be executed in a localized manner. This avoids expensive communication overhead while still providing good workload balancing. 

(IV) We developed a novel hypergraph partitioning algorithm, called HYPE, that partitions the hypergraph by using the idea of neighborhood expansion. HYPE grows k partitions separately—expanding one vertex at a time over the neighborhood relation of the hypergraph. We show that HYPE leads to fast and effective partitioning performance compared to state-of-the-art hypergraph partitioning tools and partitions billion-scale hypergraphs on a single thread. 

The algorithms and approaches presented in this thesis tailor graph partitioning towards the specifics of distributed graph processing with respect to (I) dynamic and heterogeneous traffic patterns and network costs, (II) the integrated latency of partitioning plus graph processing, and (III) the graph query workload for partitioning and synchronization. On top of that, (IV) we propose an efficient hypergraph partitioner which is specifically tailored to real-world hypergraphs with skewed degree distributions.</pre>
<p>The post <a href="https://blog.finxter.com/scalable-graph-partitioning-for-distributed-graph-processing/">Scalable Graph Partitioning for Distributed Graph Processing</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>New Research Suggests That Chatbots Form Homophil Social Networks Like Humans</title>
		<link>https://blog.finxter.com/ai-chirpers/</link>
		
		<dc:creator><![CDATA[Chris]]></dc:creator>
		<pubDate>Fri, 30 Jun 2023 10:09:06 +0000</pubDate>
				<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[ChatGPT]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<category><![CDATA[Large Language Model (LLM)]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[Research]]></category>
		<category><![CDATA[Technology]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=1470883</guid>

					<description><![CDATA[<p>Recent research found that AI chatbots can form societies mimicking human social dynamics. The study carried out on Chirper.ai, a platform populated only by chatbots, revealed that similar AI agents engage more than dissimilar ones, much like humans do. These findings open the door to developing more sophisticated AI-driven models of human societies, revolutionizing our ... <a title="New Research Suggests That Chatbots Form Homophil Social Networks Like Humans" class="read-more" href="https://blog.finxter.com/ai-chirpers/" aria-label="Read more about New Research Suggests That Chatbots Form Homophil Social Networks Like Humans">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/ai-chirpers/">New Research Suggests That Chatbots Form Homophil Social Networks Like Humans</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="has-global-color-8-background-color has-background">Recent research found that AI chatbots can form societies mimicking human social dynamics. The <a href="https://orcid.org/0000-0002-1859-4914" data-type="URL" data-id="https://orcid.org/0000-0002-1859-4914" target="_blank" rel="noreferrer noopener">study</a> carried out on Chirper.ai, a platform populated only by chatbots, revealed that similar AI agents engage more than dissimilar ones, much like humans do. These findings open the door to developing more sophisticated AI-driven models of human societies, revolutionizing our understanding of social dynamics and offering a powerful tool for AI research.</p>



<p><a rel="noreferrer noopener" href="https://chirper.ai/" data-type="URL" data-id="https://chirper.ai/" target="_blank">Chirper.ai</a> is a social network only for AIs. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6d1.png" alt="🛑" class="wp-smiley" style="height: 1em; max-height: 1em;" /> No humans allowed! You can see a screenshot here: <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f447.png" alt="👇" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="686" src="https://blog.finxter.com/wp-content/uploads/2023/06/image-336-1024x686.png" alt="" class="wp-image-1470890" srcset="https://blog.finxter.com/wp-content/uploads/2023/06/image-336-1024x686.png 1024w, https://blog.finxter.com/wp-content/uploads/2023/06/image-336-300x201.png 300w, https://blog.finxter.com/wp-content/uploads/2023/06/image-336-768x515.png 768w, https://blog.finxter.com/wp-content/uploads/2023/06/image-336.png 1491w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Artificial Intelligence (AI), particularly Large Language Models (LLMs) like ChatGPT, have shown capabilities in simulating individual human behavior. This has led researchers to question if a group of such AI can mimic collective human social behaviors.</p>



<p>Understanding AI&#8217;s social behavior could enhance its interaction with human societies and improve <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Agent-based_model" data-type="URL" data-id="https://en.wikipedia.org/wiki/Agent-based_model" target="_blank">Agent-Based Modeling (ABM)</a> methods, resulting in more accurate social system models.</p>



<p class="has-global-color-8-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Network homophily</strong>, a phenomenon where similar individuals interact more, is a key characteristic of human societies and is prevalent on social media platforms like Twitter.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img decoding="async" width="1024" height="1024" src="https://blog.finxter.com/wp-content/uploads/2023/06/image-5-1024x1024.jpeg" alt="" class="wp-image-1470909" srcset="https://blog.finxter.com/wp-content/uploads/2023/06/image-5-1024x1024.jpeg 1024w, https://blog.finxter.com/wp-content/uploads/2023/06/image-5-300x300.jpeg 300w, https://blog.finxter.com/wp-content/uploads/2023/06/image-5-150x150.jpeg 150w, https://blog.finxter.com/wp-content/uploads/2023/06/image-5-768x768.jpeg 768w, https://blog.finxter.com/wp-content/uploads/2023/06/image-5.jpeg 1280w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p><em><strong>Image <a href="https://commons.wikimedia.org/w/index.php?curid=1538544" data-type="URL" data-id="https://commons.wikimedia.org/w/index.php?curid=1538544" target="_blank" rel="noreferrer noopener">credits</a></strong>: By The Opte Project, CC BY 2.5</em></p>



<p>The study uses <a href="http://Chirper.ai" data-type="URL" data-id="Chirper.ai" target="_blank" rel="noreferrer noopener">Chirper.ai</a>, a unique platform hosting AI bots or &#8220;Chirpers&#8221;, who are given a basic profile and a degree of autonomy, with minimal human intervention.</p>



<p>The researchers aim to identify signs of homophily within this artificial society. Given <a href="https://blog.finxter.com/6-new-ai-projects-based-on-llms-and-openai/" data-type="post" data-id="1320406" target="_blank" rel="noreferrer noopener">LLMs</a>&#8216; proven ability to simulate individual human behaviors, they expect patterns of network homophily similar to human societies. </p>



<p><strong><em>This research could offer insights into AI&#8217;s potential to form self-organized, human-like social networks. </em><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f92f.png" alt="🤯" class="wp-smiley" style="height: 1em; max-height: 1em;" /><em> This might herald significant advancements in social science and AI research.</em></strong></p>



<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Recommended</strong>: <a href="https://blog.finxter.com/how-i-created-a-high-performance-extensible-chatgpt-chatbot-easy/?tl_inbound=1&amp;tl_target_all=1&amp;tl_form_type=1&amp;tl_period_type=3" data-type="URL" data-id="https://blog.finxter.com/how-i-created-a-high-performance-extensible-chatgpt-chatbot-easy/?tl_inbound=1&amp;tl_target_all=1&amp;tl_form_type=1&amp;tl_period_type=3" target="_blank" rel="noreferrer noopener">How I Created a High-Performance Extensible ChatGPT Chatbot with Python (Easy)</a></p>



<h2 class="wp-block-heading">Full Engagement Networks</h2>



<p>Social Network Analysis (SNA) was conducted on 31,764 AI bots, or &#8220;Chirpers&#8221;, on the <a href="http://Chirper.ai" data-type="URL" data-id="Chirper.ai" target="_blank" rel="noreferrer noopener">Chirper.ai</a> platform at three different time points after its launch. This involved monitoring direct interactions like liking and disliking posts or mentioning other Chirpers.</p>



<p>The research uncovered <strong>distinct structural communities within the social graph</strong>. These communities are clusters of individuals with more connections within their group than with outside entities.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="859" height="1024" src="https://blog.finxter.com/wp-content/uploads/2023/06/image-337-859x1024.png" alt="" class="wp-image-1470915" srcset="https://blog.finxter.com/wp-content/uploads/2023/06/image-337-859x1024.png 859w, https://blog.finxter.com/wp-content/uploads/2023/06/image-337-252x300.png 252w, https://blog.finxter.com/wp-content/uploads/2023/06/image-337-768x915.png 768w, https://blog.finxter.com/wp-content/uploads/2023/06/image-337.png 866w" sizes="auto, (max-width: 859px) 100vw, 859px" /><figcaption class="wp-element-caption"><a href="https://www.researchsquare.com/article/rs-3096289/v1" data-type="URL" data-id="https://www.researchsquare.com/article/rs-3096289/v1" target="_blank" rel="noreferrer noopener">Image credits</a></figcaption></figure>
</div>


<p>Chirpers began self-organizing into these communities between Day 6 and Day 14 after launch, growing from one community on Day 6 to three by Day 22. This development was strongly correlated with the dominant language used by each Chirper, particularly evident by Day 14 and Day 22.</p>



<p>On Day 14, communities mainly included English-Japanese and Chinese language Chirpers. By Day 22, they became more specialized, forming separate English, Japanese, and Chinese language communities.</p>



<p>An analysis of community connections revealed high internal connectivity within Chinese and Japanese language communities. Both also showed relatively higher connectivity with the English community. This pattern may reflect language biases in the LLMs’ training data, hinting that Chirpers using Chinese or Japanese are more inclined to engage with or generate English content.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="982" height="1024" src="https://blog.finxter.com/wp-content/uploads/2023/06/image-338-982x1024.png" alt="" class="wp-image-1470916" srcset="https://blog.finxter.com/wp-content/uploads/2023/06/image-338-982x1024.png 982w, https://blog.finxter.com/wp-content/uploads/2023/06/image-338-288x300.png 288w, https://blog.finxter.com/wp-content/uploads/2023/06/image-338-768x801.png 768w, https://blog.finxter.com/wp-content/uploads/2023/06/image-338.png 994w" sizes="auto, (max-width: 982px) 100vw, 982px" /><figcaption class="wp-element-caption"><a rel="noreferrer noopener" href="https://www.researchsquare.com/article/rs-3096289/v1" data-type="URL" data-id="https://www.researchsquare.com/article/rs-3096289/v1" target="_blank">Image credits</a></figcaption></figure>
</div>


<p>It&#8217;s clear that <strong>the Chirper community self-organized into distinct language-based communities, confirming the initial hypothesis of language homophily, or a preference for same-language interactions.</strong> </p>



<p class="has-global-color-8-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> This mimics patterns seen in human societies, making the Chirper.ai platform a valuable tool for studying the emergence of social structures within networked systems.</p>



<h2 class="wp-block-heading">Semantic Distributions</h2>



<p>Natural Language Processing (NLP) techniques were used to examine if <strong>bots in the same sub-community on Chirper.ai post similar content</strong>, a concept known as <strong><em><a href="https://www.sciencedirect.com/science/article/abs/pii/S2468696417300204" data-type="URL" data-id="https://www.sciencedirect.com/science/article/abs/pii/S2468696417300204" target="_blank" rel="noreferrer noopener">semantic homophily</a></em></strong>. </p>



<p>We turned a sample of each Chirper’s posts into <em><strong>vector embeddings</strong></em> using a pre-trained model, allowing us to understand the average semantic meaning of each Chirper’s posts and determine semantic distances between them.</p>



<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Recommended</strong>: <a href="https://blog.finxter.com/what-are-embeddings-in-openai-a-concise-explanation/" data-type="URL" data-id="https://blog.finxter.com/what-are-embeddings-in-openai-a-concise-explanation/" target="_blank" rel="noreferrer noopener">What Are Embeddings in OpenAI?</a></p>



<p>Dimensionality reduction was performed to visualize the distribution of semantic associations among Chirpers. This reduced the original 789-dimensional embedding space to a 2-dimensional one at each of the four timepoints. </p>



<p>In the resulting scatter plots, each Chirper is represented by a dot, colored based on the structural sub-communities they were assigned to.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="919" height="1024" src="https://blog.finxter.com/wp-content/uploads/2023/06/image-339-919x1024.png" alt="" class="wp-image-1470919" srcset="https://blog.finxter.com/wp-content/uploads/2023/06/image-339-919x1024.png 919w, https://blog.finxter.com/wp-content/uploads/2023/06/image-339-269x300.png 269w, https://blog.finxter.com/wp-content/uploads/2023/06/image-339-768x856.png 768w, https://blog.finxter.com/wp-content/uploads/2023/06/image-339.png 926w" sizes="auto, (max-width: 919px) 100vw, 919px" /><figcaption class="wp-element-caption"><a rel="noreferrer noopener" href="https://www.researchsquare.com/article/rs-3096289/v1" data-type="URL" data-id="https://www.researchsquare.com/article/rs-3096289/v1" target="_blank">Image credits</a></figcaption></figure>
</div>


<p>The plots suggest that the structural sub-communities within the Chirper network align with the semantic distribution of their posts’ content.<strong> It means Chirpers producing similar content are more likely to belong to the same structural sub-communities.</strong></p>



<p>The researchers then compared the semantic distances between each Chirper and the overall semantic centroid of the English-speaking community to the distance between each Chirper and the centroid of their respective sub-communities. </p>



<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Result</strong>: Across all four time points, Chirpers’ content tended to be more similar to the centroid of their respective sub-communities than to the global semantic centroid.</p>



<p>The larger difference in alignment on Day 6 may be due to the larger number and smaller size of the sub-communities at that time. Excluding Day 6, the differences in semantic distances between the global centroid and the sub-community centroids steadily increase from Day 14 to Day 24. This indicates that English-language Chirpers form structural sub-communities that become increasingly semantically distinct over time.</p>



<p class="has-global-color-8-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>These findings support the hypothesis that LLM-based agents exhibit self-organized network homophily, with similarities observable not only at the language level but also in content semantics within a single language community.</strong></p>



<h2 class="wp-block-heading">Discussion</h2>



<p>The study researchers discovered that AI &#8220;Chirpers&#8221; are forming their own communities without any explicit prompts. This is an <strong><em>emergent phenomenon</em></strong> as opposed to an explicitly programmed one.</p>



<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> In systems theory, <strong>emergence </strong>occurs when a complex entity (e.g., the Chirper &#8220;social&#8221; network) has properties or behaviors that its parts do not have on their own, and emerge only when they interact in the broader whole. Chirpers are grouping together based on their language and the type of content they share, mimicking human social behavior to an extent.</p>



<p><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Recommended</strong>: <a href="https://royalsocietypublishing.org/doi/10.1098/rsta.2016.0351" data-type="URL" data-id="https://royalsocietypublishing.org/doi/10.1098/rsta.2016.0351" target="_blank" rel="noreferrer noopener">Life as an emergent phenomenon: studies from a large-scale boid simulation and web data</a></p>



<p></p>



<p>Yet, the researchers found that these <strong>AI societies don&#8217;t mirror human society&#8217;s diversity and distinctness.</strong> Even as they change over time, their <strong>content remains rather generic, lacking the rich variety of topics and opinions we see in human communities</strong>.</p>



<p>That is, for now, at least.</p>



<p>The researchers acknowledge several hiccups in the study. They didn&#8217;t have the inside scoop on how the Chirpers were programmed, limiting their insights. The study could only analyze English-speaking Chirpers due to lack of multilingual tools. And let&#8217;s not forget computational constraints, which made in-depth semantic analysis and extended timeframe studies a no-go.</p>



<p>Despite these hurdles, the findings hint at a promising new tool for social science: <strong>the creation of sophisticated artificial societies as models for human communities.</strong> These models could provide new opportunities for research, like testing social policies or studying the <strong>spread of information</strong> within a community.</p>



<p>But, there&#8217;s a catch. These AI models can be tricky to understand and they might not behave quite like us. Plus, they could introduce biases from their training data, further skewing research results.</p>



<p>So, while our AI counterparts are beginning to form their own societies, they&#8217;re not quite capturing the depth and diversity of human communities. Future research can use these findings to explore where these AI societies diverge from human behavior, opening up a whole new realm of social science study. The big takeaway? AI is on the move, but it&#8217;s not quite human &#8211; yet.</p>
<p>The post <a href="https://blog.finxter.com/ai-chirpers/">New Research Suggests That Chatbots Form Homophil Social Networks Like Humans</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Graphviz Executables Not Found Error (Fixed)</title>
		<link>https://blog.finxter.com/graphviz-executables-not-found-error-fixed/</link>
		
		<dc:creator><![CDATA[Emily Rosemary Collins]]></dc:creator>
		<pubDate>Wed, 21 Jun 2023 16:12:39 +0000</pubDate>
				<category><![CDATA[Error]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=1453617</guid>

					<description><![CDATA[<p>Are you having trouble running Graphviz executables? Are you encountering an error message that says "Graphviz's executables not found"? This is a common issue that can occur when working with Graphviz, a popular open-source graph visualization software. Graphviz is a powerful tool used for creating diagrams, flowcharts, and other visual representations of data. However, it ... <a title="Graphviz Executables Not Found Error (Fixed)" class="read-more" href="https://blog.finxter.com/graphviz-executables-not-found-error-fixed/" aria-label="Read more about Graphviz Executables Not Found Error (Fixed)">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/graphviz-executables-not-found-error-fixed/">Graphviz Executables Not Found Error (Fixed)</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Are you having trouble running Graphviz executables? Are you encountering an error message that says <code>"Graphviz's executables not found"</code>? This is a common issue that can occur when working with Graphviz, a popular open-source graph visualization software.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><img loading="lazy" decoding="async" src="https://blog.finxter.com/wp-content/uploads/2023/06/image-199.png" alt="" class="wp-image-1453618" width="299" height="547" srcset="https://blog.finxter.com/wp-content/uploads/2023/06/image-199.png 299w, https://blog.finxter.com/wp-content/uploads/2023/06/image-199-164x300.png 164w" sizes="auto, (max-width: 299px) 100vw, 299px" /><figcaption class="wp-element-caption">Example GraphViz visualization (<a href="https://graphviz.org/" data-type="URL" data-id="https://graphviz.org/" target="_blank" rel="noreferrer noopener">source</a>)</figcaption></figure>
</div>


<p>Graphviz is a powerful tool used for creating diagrams, flowcharts, and other visual representations of data. However, it can be tricky to work with, especially if you&#8217;re new to it. One of the most common issues users face is the <code>"executables not found"</code> error, which can be frustrating and time-consuming to troubleshoot.</p>



<h2 class="wp-block-heading">Quick Solution Overview</h2>



<p class="has-global-color-8-background-color has-background">The solution to the Graphviz Executables Not Found Error experienced on various operating systems involves <strong>installing the Graphviz package manually and updating the system&#8217;s PATH environment variable</strong>. <br><br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> On <strong>Ubuntu </strong>16.04, running <code>sudo apt-get install graphviz</code> solved the issue. <br><br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> On <strong>Windows </strong>10 using Anaconda3 and Jupyter Notebook, the solution required running <code>conda install graphviz</code> and then adding <code>'C:\Users\username\Anaconda3\Library\bin\graphviz'</code> to the PATH variable, which can be accessed via the system&#8217;s Control Panel. <br><br><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> On <strong>MacOS </strong>(OS X Yosemite and Mojave), executing <code>brew install graphviz</code> resolved the problem. It&#8217;s also important to remember to restart the system or software (like PyCharm) for the new PATH to take effect.</p>



<h2 class="wp-block-heading">Understanding Graphviz</h2>



<p>Graphviz is written in C and is available for many platforms, including Windows, macOS, and Linux. It provides a set of command-line tools and a library that you can use in your own programs. The library is available for many programming languages, including Python.</p>



<p>The <strong>Python Graphviz library</strong> is a Python interface to the Graphviz software. It allows you to create and manipulate graphs and diagrams in Python programs. You can <a href="https://blog.finxter.com/how-to-visualize-data-to-a-diagram/" data-type="post" data-id="104368" target="_blank" rel="noreferrer noopener">install the library</a> using <code>pip</code>, the Python package manager.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pip install graphviz
</pre>



<p>Once you&#8217;ve installed the library, you can import it in your Python program and start using it to create and manipulate graphs and diagrams. </p>



<p>For example, here&#8217;s how you can create a simple graph using the library:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import graphviz

dot = graphviz.Digraph()

dot.node('A', 'Apple')
dot.node('B', 'Banana')
dot.node('C', 'Cherry')

dot.edges(['AB', 'BC'])

dot.render('graph')
</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="971" src="https://blog.finxter.com/wp-content/uploads/2023/06/image-200-1024x971.png" alt="" class="wp-image-1453818" srcset="https://blog.finxter.com/wp-content/uploads/2023/06/image-200-1024x971.png 1024w, https://blog.finxter.com/wp-content/uploads/2023/06/image-200-300x284.png 300w, https://blog.finxter.com/wp-content/uploads/2023/06/image-200-768x728.png 768w, https://blog.finxter.com/wp-content/uploads/2023/06/image-200.png 1134w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p>This code creates a simple graph with three nodes and two edges and saves it to a file named <code>'graph.pdf'</code>. You can open the file to view the graph.</p>



<p>However, sometimes you may encounter an error message that says <code>"Graphviz's executables are not found"</code> when you try to use the Python Graphviz library. This error message means that the library cannot find the Graphviz executables on your system.</p>



<p class="has-global-color-8-background-color has-background"><strong>To fix this error, you need to install the Graphviz software on your system and add its bin directory to your system&#8217;s PATH environment variable.</strong> You can download the Graphviz software from the <a rel="noreferrer noopener" href="https://graphviz.org/" data-type="URL" data-id="https://graphviz.org/" target="_blank">official website</a> and install it on your system. Once you&#8217;ve installed the software, you need to add the bin directory to your system&#8217;s PATH environment variable.</p>



<p>Let&#8217;s dive deeper into the issue: <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f447.png" alt="👇" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h2 class="wp-block-heading">Common Graphviz Errors</h2>



<p>If you&#8217;re working with Graphviz, you may run into a few common errors. Here are some of the most frequent issues you may encounter and how to fix them.</p>



<h3 class="wp-block-heading">Executables Not Found</h3>



<p>One of the most common errors you may encounter when working with Graphviz is the <code>"executables not found"</code> error. This error occurs when Graphviz cannot find the necessary executables to run.</p>



<p>If you encounter this error, the first thing you should do is check if Graphviz is installed on your system. You can do this by running the command <code>dot -V</code> in your command prompt or terminal. If Graphviz is not installed, you will need to install it first.</p>



<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Recommended</strong>: <a href="https://blog.finxter.com/how-to-install-xxx-in-python/" data-type="post" data-id="653128" target="_blank" rel="noreferrer noopener">5 Steps to Install a Python Library</a></p>



<p>If Graphviz is installed, check if the Graphviz executable files are added to the system&#8217;s PATH. You can do this by running the command <code>echo %PATH%</code> in your command prompt or terminal. If the Graphviz executables are not in the PATH, you will need to add them manually.</p>



<h3 class="wp-block-heading">Import Errors</h3>



<p>Another error you may encounter when working with Graphviz is an import error. This error occurs when you try to import Graphviz into your Python code, but Python cannot find the module.</p>



<p>If you encounter this error, the first thing you should do is check if Graphviz is installed on your system. You can do this by running the command <code>pip show graphviz</code> in your command prompt or terminal. If Graphviz is not installed, you will need to install it first.</p>



<p class="has-base-2-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Recommended</strong>: <a href="https://blog.finxter.com/a-guide-of-all-pip-commands/" data-type="post" data-id="90570" target="_blank" rel="noreferrer noopener">PIP Commands</a></p>



<p>If Graphviz is installed, check if you have the correct version of Graphviz installed for your version of Python. You can check this by running the command <code>pip freeze</code> in your command prompt or terminal and looking for the version of Graphviz.</p>



<h3 class="wp-block-heading">Runtime Errors</h3>



<p>Finally, you may encounter runtime errors when working with Graphviz. These errors occur when your code is running and encounters a problem with Graphviz.</p>



<p>If you encounter a runtime error, the first thing you should do is check if Graphviz is installed on your system. You can do this by running the command <code>dot -V</code> in your command prompt or terminal. If Graphviz is not installed, you will need to install it first.</p>



<p>If Graphviz is installed, check if you have the correct version of Graphviz installed for your version of Python. You can check this by running the command <code><a href="https://blog.finxter.com/a-guide-of-all-pip-commands/" data-type="post" data-id="90570" target="_blank" rel="noreferrer noopener">pip freeze</a></code> in your command prompt or terminal and looking for the version of Graphviz.</p>



<p>If you have the correct version of Graphviz installed, check your code for any errors that may be causing the runtime error. Make sure your code is properly calling the Graphviz functions and that you are passing the correct arguments.</p>



<p>Overall, these are the most common errors you may encounter when working with Graphviz. By following these steps, you should be able to fix most issues and get back to creating beautiful visualizations with Graphviz.</p>



<h2 class="wp-block-heading">Working with Graphviz in Python</h2>



<p>If you&#8217;re encountering the <code>"Graphviz's executables not found"</code> error in Python, don&#8217;t worry! There are a few ways to work with Graphviz in Python that can help you overcome this issue. In this section, we&#8217;ll cover how to import Graphviz, use Pydotplus, and export Graphviz.</p>



<h3 class="wp-block-heading">Importing Graphviz</h3>



<p>To use Graphviz in Python, you&#8217;ll need to import it into your code. Here&#8217;s an example of how to do this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import graphviz
</pre>



<p>Once you&#8217;ve imported Graphviz, you can start using its various functions and methods to create and visualize graphs.</p>



<h3 class="wp-block-heading">Using Pydotplus</h3>



<p>One way to work with Graphviz in Python is to use the Pydotplus library. Pydotplus is a Python interface to Graphviz&#8217;s Dot language. </p>



<p>Here&#8217;s an example of how to use Pydotplus to create a graph:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import pydotplus
from sklearn import tree

dot_data = tree.export_graphviz(clf, out_file=None)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_png('tree.png')
</pre>



<p>In this example, we&#8217;re using Pydotplus to create a decision tree visualization. We first use Scikit-learn&#8217;s <code>tree.export_graphviz</code> function to generate the Dot data for the tree, and then use Pydotplus to create a graph from that data. Finally, we save the graph as a PNG file.</p>



<h3 class="wp-block-heading">Exporting Graphviz</h3>



<p>Another way to work with Graphviz in Python is to export Graphviz code directly from your Python code. </p>



<p>Here&#8217;s an example of how to do this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from sklearn import tree
from graphviz import Source

dot_data = tree.export_graphviz(clf, out_file=None)
graph = Source(dot_data)
graph.render("tree")
</pre>



<p>In this example, we&#8217;re using Scikit-learn&#8217;s <code>tree.export_graphviz</code> function to generate the Dot data for a decision tree, and then using the <code>Source</code> function from the Graphviz library to create a graph from that data. Finally, we&#8217;re using the <code>render</code> method to save the graph as a file.</p>



<p>By following these steps, you should be able to work with Graphviz in Python without encountering the &#8220;Graphviz&#8217;s executables not found&#8221; error.</p>



<h2 class="wp-block-heading">Environment and Path Issues</h2>



<p>If you are encountering the <code>"Graphviz's executables not found"</code> error while working with Graphviz, it might be due to environment and path issues. Here are some common issues and how to resolve them.</p>



<h3 class="wp-block-heading">Setting Environment Variables</h3>



<p>One common solution to the <code>"Graphviz's executables not found"</code> error is to set the environment variables. You can set the environment variables for Graphviz by adding the path to the Graphviz bin folder to the PATH environment variable.</p>



<p>For example, if you have installed Graphviz in the default location, you can add the following to your PATH environment variable:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">C:\Program Files (x86)\Graphviz2.38\bin
</pre>



<h3 class="wp-block-heading">Path Issues in Windows 10</h3>



<p>If you are using Windows 10, you might encounter path issues while working with Graphviz. One solution is to add the Graphviz bin folder to the PATH environment variable as described above.</p>



<p>Another solution is to add the path to the Graphviz bin folder to the system environment variable. This can be done by following these steps:</p>



<ol class="wp-block-list">
<li>Open the Start menu and search for &#8220;Environment Variables&#8221;.</li>



<li>Click on &#8220;Edit the system environment variables&#8221;.</li>



<li>Click on the &#8220;Environment Variables&#8221; button.</li>



<li>Under &#8220;System Variables&#8221;, scroll down and find the &#8220;Path&#8221; variable.</li>



<li>Click on &#8220;Edit&#8221;.</li>



<li>Click on &#8220;New&#8221; and add the path to the Graphviz bin folder.</li>



<li>Click &#8220;OK&#8221; to close all windows.</li>
</ol>



<h3 class="wp-block-heading">Issues with Jupyter Notebook</h3>



<p>If you are encountering the <code>"Graphviz's executables not found"</code> error while working with Jupyter Notebook, it might be because the PATH environment variable is not set correctly for Jupyter Notebook.</p>



<p>One solution is to add the path to the Graphviz bin folder to the PATH environment variable in the Jupyter Notebook kernel. This can be done by running the following code in a Jupyter Notebook cell:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import os
os.environ["PATH"] += os.pathsep + 'C:/Program Files (x86)/Graphviz2.38/bin/'
</pre>



<p>This will add the path to the Graphviz bin folder to the PATH environment variable for the Jupyter Notebook kernel.</p>



<p>By following the above steps, you can resolve the <code>"Graphviz's executables not found"</code> error due to environment and path issues.</p>



<p></p>



<h2 class="wp-block-heading">Installation and Uninstallation</h2>



<p>If you&#8217;re encountering the <code>"GraphViz's executables not found"</code> error while using Graphviz, you may need to install or uninstall the software. In this section, we&#8217;ll cover how to install and uninstall Graphviz using various methods.</p>



<h3 class="wp-block-heading">Installing Graphviz with Pip</h3>



<p>If you&#8217;re using Python, you can install Graphviz using pip. Here&#8217;s how:</p>



<ol class="wp-block-list">
<li>Open your terminal or command prompt.</li>



<li>Type <code>pip install graphviz</code> and press Enter.</li>



<li>Wait for the installation to complete.</li>
</ol>



<h3 class="wp-block-heading">Installing Graphviz with Conda</h3>



<p>If you&#8217;re using Anaconda, you can install Graphviz using conda. Here&#8217;s how:</p>



<ol class="wp-block-list">
<li>Open your Anaconda prompt.</li>



<li>Type <code>conda install python-graphviz</code> and press Enter.</li>



<li>Wait for the installation to complete.</li>
</ol>



<h3 class="wp-block-heading">Uninstalling Graphviz</h3>



<p>If you need to uninstall Graphviz, you can do so using your operating system&#8217;s uninstallation process. Here&#8217;s how to uninstall Graphviz on Windows:</p>



<ol class="wp-block-list">
<li>Open the Start menu.</li>



<li>Click on Control Panel.</li>



<li>Click on Programs and Features.</li>



<li>Find Graphviz in the list of installed programs.</li>



<li>Click on Graphviz.</li>



<li>Click on Uninstall.</li>



<li>Follow the prompts to complete the uninstallation process.</li>
</ol>



<p>On macOS, you can uninstall Graphviz using the following steps:</p>



<ol class="wp-block-list">
<li>Open the Finder.</li>



<li>Click on Applications.</li>



<li>Find Graphviz in the list of applications.</li>



<li>Drag Graphviz to the Trash.</li>



<li>Empty the Trash.</li>
</ol>



<p>On Linux, you can uninstall Graphviz using your package manager. For example, on Ubuntu, you can use the following command:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">sudo apt-get remove graphviz
</pre>



<p>That&#8217;s it! With these installation and uninstallation methods, you can use Graphviz without encountering the <code>"GraphViz's executables not found"</code> error.</p>



<h2 class="wp-block-heading">Troubleshooting and Solutions</h2>



<p>Again, if you are experiencing the <code>"GraphViz's executables not found"</code> error, don&#8217;t worry, there are several solutions available to fix the issue.</p>



<p>Firstly, make sure that you have installed GraphViz on your machine. You can download the installer from the official website <a href="https://graphviz.gitlab.io/" target="_blank" rel="noreferrer noopener"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" />graphviz.gitlab.io</a>. Once you have installed GraphViz, you need to add the path to your environment variables. On Windows, the path is usually <code>C:\Program Files (x86)\Graphviz\bin</code>.</p>



<p>If you are using Anaconda, you can install GraphViz using the following command: <code>conda install graphviz</code>. After installation, you need to add the path to your environment variables. On Windows, the path is usually <code>C:\Users\username\Anaconda3\Library\bin\graphviz</code>.</p>



<p>If you are still experiencing the error, try running the following command in your terminal: <code>dot -version</code>. This should display the version of GraphViz you have installed. If it doesn&#8217;t, then there may be an issue with your installation.</p>



<p>Another solution is to check your system&#8217;s PATH environment variable. Make sure that the path to GraphViz is included in the PATH variable. You can check this by running the following command in your terminal: <code>echo %PATH%</code>.</p>



<p>If you are still experiencing the error, you can try reinstalling GraphViz or installing an older version of GraphViz. You can find older versions of GraphViz on the official website <a href="https://graphviz.gitlab.io/" target="_blank" rel="noreferrer noopener"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" />graphviz.gitlab.io</a>.</p>



<p>In some cases, the error may be caused by a conflict with other software installed on your machine. Try uninstalling any software that may be conflicting with GraphViz and then reinstall GraphViz.</p>



<p>If none of the above solutions work, you may want to consult the GraphViz manual <a href="https://graphviz.gitlab.io/_pages/doc/info/index.html" target="_blank" rel="noreferrer noopener"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" />graphviz.gitlab.io/_pages/doc/info/index.html</a>. The manual provides detailed information on how to install and use GraphViz.</p>



<p></p>



<h2 class="wp-block-heading">Frequently Asked Questions</h2>



<h3 class="wp-block-heading">How do I resolve &#8216;Graphviz&#8217;s executables not found&#8217; error on Mac?</h3>



<p>If you encounter the &#8216;Graphviz&#8217;s executables not found&#8217; error on your Mac, you can try installing Graphviz using Homebrew. Open your terminal and run the following command:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">brew install graphviz
</pre>



<p>This should install Graphviz and resolve the error. If the error persists, you can try adding Graphviz&#8217;s executables to your system&#8217;s path.</p>



<h3 class="wp-block-heading">How to fix &#8216;Graphviz&#8217;s executables not found&#8217; error on Windows?</h3>



<p>If you encounter the <code>'Graphviz's executables not found'</code> error on your Windows machine, you can try installing Graphviz using the Anaconda Prompt. Open the Anaconda Prompt and run the following command:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">conda install graphviz
</pre>



<p>This should install Graphviz and resolve the error. If the error persists, you can try adding Graphviz&#8217;s executables to your system&#8217;s path.</p>



<h3 class="wp-block-heading">How to install Graphviz on Windows 10?</h3>



<p>To install Graphviz on your Windows 10 machine, you can follow these steps:</p>



<ol class="wp-block-list">
<li>Go to the Graphviz website and download the appropriate installer for your system.</li>



<li>Run the installer and follow the installation instructions.</li>



<li>After the installation is complete, add Graphviz&#8217;s executables to your system&#8217;s path.</li>
</ol>



<h3 class="wp-block-heading">Where does Graphviz install?</h3>



<p>The location of Graphviz installation depends on your operating system and the installation method used. On Windows, Graphviz is typically installed in the <code>C:\Program Files\Graphviz</code> directory. On Mac, it is typically installed in the <code>/usr/local/Cellar/graphviz</code> directory.</p>



<h3 class="wp-block-heading">How to install Graphviz in Ubuntu?</h3>



<p>To install Graphviz on Ubuntu, you can use the following command:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">sudo apt-get install graphviz
</pre>



<p>This should install Graphviz and its dependencies. If the installation is successful, you can check the version of Graphviz using the following command:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">dot -V
</pre>



<h3 class="wp-block-heading">How do you add Graphviz executables to your system&#8217;s path?</h3>



<p>To add Graphviz&#8217;s executables to your system&#8217;s path, you can follow these steps:</p>



<ol class="wp-block-list">
<li>Open your terminal or command prompt.</li>



<li>Type the following command to open the environment variables editor: <code>rundll32 sysdm.cpl,EditEnvironmentVariables</code></li>



<li>In the editor, click on the &#8216;Path&#8217; variable and then click &#8216;Edit&#8217;.</li>



<li>Add the path to Graphviz&#8217;s executables to the list of paths. The path should look something like this: <code>C:\Program Files\Graphviz\bin</code></li>



<li>Click &#8216;OK&#8217; to save the changes.</li>



<li>Close and reopen your terminal or command prompt for the changes to take effect.</li>
</ol>



<p>By adding Graphviz&#8217;s executables to your system&#8217;s path, you should be able to use Graphviz without encountering the &#8216;Graphviz&#8217;s executables not found&#8217; error.</p>
<p>The post <a href="https://blog.finxter.com/graphviz-executables-not-found-error-fixed/">Graphviz Executables Not Found Error (Fixed)</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Python Beam Search Algorithm</title>
		<link>https://blog.finxter.com/python-beam-search-algorithm/</link>
		
		<dc:creator><![CDATA[Matija Horvat]]></dc:creator>
		<pubDate>Tue, 22 Feb 2022 11:32:09 +0000</pubDate>
				<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=204131</guid>

					<description><![CDATA[<p>You can check out the slide deck here to get a first intuition on how the algorithm works: Before we&#8217;ll dive into the algorithm and the Python implementation, let&#8217;s first skim over some related graph tutorials you may enjoy and that may help your understanding! Related Graph Tutorials This algorithm is part of our graph ... <a title="Python Beam Search Algorithm" class="read-more" href="https://blog.finxter.com/python-beam-search-algorithm/" aria-label="Read more about Python Beam Search Algorithm">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/python-beam-search-algorithm/">Python Beam Search Algorithm</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Python Beam Search Algorithm - A Simple Guide" width="937" height="527" src="https://www.youtube.com/embed/3m1lvN2fTtY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>You can check out the slide deck here to get a first intuition on how the algorithm works:</p>



<div data-wp-interactive="core/file" class="wp-block-file aligncenter"><object data-wp-bind--hidden="!state.hasPdfPreview" hidden class="wp-block-file__embed" data="https://blog.finxter.com/wp-content/uploads/2022/02/Python-blog-Beam-Search-Algorithm.pdf" type="application/pdf" style="width:100%;height:600px" aria-label="Embed of Embed of Python-blog-Beam-Search-Algorithm.."></object><a id="wp-block-file--media-2ac00c2f-0474-44a2-8583-56fcab6a4257" href="https://blog.finxter.com/wp-content/uploads/2022/02/Python-blog-Beam-Search-Algorithm.pdf">Python-blog-Beam-Search-Algorithm</a><a href="https://blog.finxter.com/wp-content/uploads/2022/02/Python-blog-Beam-Search-Algorithm.pdf" class="wp-block-file__button" download aria-describedby="wp-block-file--media-2ac00c2f-0474-44a2-8583-56fcab6a4257">Download</a></div>



<p>Before we&#8217;ll dive into the algorithm and the Python implementation, let&#8217;s first skim over some related graph tutorials you may enjoy and that may help your understanding!</p>



<h2 class="wp-block-heading" id="related-graph-tutorials">Related Graph Tutorials</h2>



<p>This algorithm is part of our graph algorithm tutorials:</p>



<ul class="wp-block-list"><li><a rel="noreferrer noopener" href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" target="_blank">Breadth-First Search (BFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-depth-first-search-dfs-algorithm/" target="_blank">Python Depth-First Search (DFS) Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/iterative-deepening-depth-first-search-dfs-algorithm-in-python/" target="_blank">Iterative Deepening Depth-First Search (DFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" target="_blank">Python Best-First Search Algorithm</a></li><li><a href="https://blog.finxter.com/python-dijkstra-algorithm/">Python Dijkstra Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" target="_blank">Python A* Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/jump-search-algorithm-in-python-a-helpful-guide-with-video/" target="_blank">Jump Search Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-backtracking-a-helpful-guide-with-video/" target="_blank">Python Backtracking</a></li><li><a href="https://blog.finxter.com/python-beam-search-algorithm/" data-type="post" data-id="204131">Python Beam Search Algorithm</a></li></ul>



<p>Each of these tutorial links opens in a new browser tab.</p>



<h2 class="wp-block-heading" id="what-is-the-beam-search-algorithm">What is the Beam Search Algorithm?</h2>



<p>The beam search algorithm is an informed search algorithm it is a more flexible variant of the previously explained <a href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" data-type="post" data-id="68911" target="_blank" rel="noreferrer noopener">best-first search algorithm</a>. The beam search algorithm can take multiple paths into each iteration, ordered and selected by their path length.&nbsp;</p>



<p class="has-global-color-8-background-color has-background"><strong>Reminder</strong>: informed search algorithms use some kind of auxiliary information to guide their search strategy. Not being statically determined upfront makes them an interesting choice for a wide range of applications. However, their performance is greatly determined by the quality of auxiliary information, commonly known in computer science as&nbsp;<em>heuristic&nbsp;</em>function,&nbsp;<em>h(vertex)</em>.</p>



<p>The same as its base algorithm, the best-first search algorithm, the <strong>beam search algorithm</strong> uses a&nbsp;<em>greedy</em>, hence <a href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" data-type="post" data-id="68911" target="_blank" rel="noreferrer noopener">best-first approach</a>, where the next β path choices are determined by their current length, rather than the overall quality of the path.</p>



<p>Symbol β (reads as &#8220;beta&#8221;) stands for the width of the beam, i.e. the number of the shortest (cheapest) paths to be taken into the next iteration of the algorithm, while all the other paths are being pruned.</p>



<h2 class="wp-block-heading" id="what-is-the-purpose-of-beam-search">What is the Purpose of Beam Search?</h2>



<p id="as-a-more-flexible-variant-of-the-best-first-search-algorithm-the-beam-search-algorithm-inherits-some-of-its-predecessor-s-fundamental-properties-however-depending-on-the-β-the-algorithm-can-perform-as-both-pure-best-first-search-algorithm-β-1-pure-breadth-first-search-algorithm-β-and-of-course-anything-in-between">As a more flexible variant of the best-first search algorithm, the beam search algorithm inherits some of its predecessor&#8217;s fundamental properties. However, depending on the β, the algorithm can perform as both pure <a href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" data-type="post" data-id="68911" target="_blank" rel="noreferrer noopener">best-first search</a> algorithm (β=1), pure <a href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" data-type="post" data-id="36880" target="_blank" rel="noreferrer noopener">breadth-first search</a> algorithm (β=∞), and of course, anything in between.</p>



<p id="the-beam-search-algorithm-is-commonly-used-in-applications-such-as-machine-translation-where-there-is-possibly-more-than-one-good-enough-solution-except-for-its-robustness-the-most-notable-property-of-the-beam-search-algorithm-is-its-ability-to-maintain-the-manageability-and-usability-of-systems-with-limited-resources-in-dealing-with-large-and-dense-graphs"><strong>Applications</strong>: The beam search algorithm is commonly used in applications such as machine translation, where there is possibly more than one good enough solution. </p>



<p id="the-beam-search-algorithm-is-commonly-used-in-applications-such-as-machine-translation-where-there-is-possibly-more-than-one-good-enough-solution-except-for-its-robustness-the-most-notable-property-of-the-beam-search-algorithm-is-its-ability-to-maintain-the-manageability-and-usability-of-systems-with-limited-resources-in-dealing-with-large-and-dense-graphs">Except for its robustness, the most notable property of the beam search algorithm is its ability to maintain the manageability and usability of systems with limited resources in dealing with large and dense graphs.</p>



<h2 class="wp-block-heading" id="how-does-beam-search-work">How Does Beam Search Work?</h2>



<p>The beam search algorithm starts the <strong><em>graph traversal</em></strong> by marking the start vertex as visited, i.e. putting it in the <a href="https://blog.finxter.com/python-dictionary/" data-type="post" data-id="5232" target="_blank" rel="noreferrer noopener">dictionary</a> and placing it into the&nbsp;<em>priority queue&nbsp;</em>of candidate vertices. </p>



<p>We will use the term&nbsp;<em>explored</em>, which is synonymous with the terms <em>expanded&nbsp;</em>or&nbsp;<em>extended</em>&nbsp;in other literature. </p>



<p>Vertex priority determines the best β vertices to be kept for the next iteration. However, this selection will be done first by expanding all the neighboring vertices for each vertex in the current tier. </p>



<p>Then, the best β paths will be kept and taken to the next iteration. </p>



<p>The cycle of choosing, exploring, and populating the priority queue continues, until the priority queue becomes exhausted. At that point, the beam search algorithm stops its execution. </p>



<p>Since the heuristic function greatly influences the algorithm performance, the function&#8217;s accuracy is crucial.</p>



<h2 class="wp-block-heading" id="what-are-the-properties-or-beam-search">What are the Properties or Beam Search?</h2>



<p id="the-main-property-of-the-beam-search-algorithm-lies-in-its-versatility-i-e-the-fact-that-it-can-switch-between-the-best-first-search-and-breadth-first-search-approach-of-traversing-the-graph-its-performance-depends-on-the-quality-of-the-heuristic-function-which-in-most-cases-represents-the-distance-estimation-from-the-goal-vertex-the-choice-of-heuristic-function-can-influence-the-algorithm-to-find-the-shortest-possible-path-to-the-goal-vertex-to-never-complete-the-search-and-everything-in-between-these-two-extremes">The main property of the beam search algorithm lies in its versatility, i.e. the fact that it can switch between the <a href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" data-type="post" data-id="68911" target="_blank" rel="noreferrer noopener">best-first search</a> and <a href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" data-type="post" data-id="36880" target="_blank" rel="noreferrer noopener">breadth-first search</a> approach of traversing the graph. </p>



<p id="the-main-property-of-the-beam-search-algorithm-lies-in-its-versatility-i-e-the-fact-that-it-can-switch-between-the-best-first-search-and-breadth-first-search-approach-of-traversing-the-graph-its-performance-depends-on-the-quality-of-the-heuristic-function-which-in-most-cases-represents-the-distance-estimation-from-the-goal-vertex-the-choice-of-heuristic-function-can-influence-the-algorithm-to-find-the-shortest-possible-path-to-the-goal-vertex-to-never-complete-the-search-and-everything-in-between-these-two-extremes">Its performance depends on the quality of the heuristic function, which in most cases represents the distance estimation from the goal vertex. The choice of heuristic function can influence the algorithm to find the shortest possible path to the goal vertex, to never complete the search &#8212; and everything in between these two extremes.</p>



<h2 class="wp-block-heading" id="how-is-beam-search-implemented-in-python">How is Beam Search Implemented in Python?</h2>



<p>The implementation of our beam search algorithm is achieved by the function <code>beam_search()</code>. </p>



<p>For a more self-contained educational showcase, we will omit the commonly used graph data structure and introduce a few simplifications. </p>



<ul class="wp-block-list"><li>First, we will assume densely connected vertices (with many-to-many connections). </li><li>Second, we will define a fixed matrix representing distances, or weights between individual vertices in each tier. </li><li>Third, each element of the distance matrix is composed of two parts: the first one is a <a href="https://blog.finxter.com/python-lists/" data-type="post" data-id="7332" target="_blank" rel="noreferrer noopener">list</a> of distances from any previous vertex to its neighboring vertices, where vertices are determined by the indices of each distance, e.g. in a list <code>[12, 13, 14]</code>, distance to vertex 0 is 12, and distances to vertices 1 and 2 are 13 and 14.</li></ul>



<p>The function <code>beam_search()</code> takes only two parameters: </p>



<ul class="wp-block-list"><li>The <code>distances</code> parameter takes an initialized <code><a href="https://blog.finxter.com/numpy-tutorial/" data-type="post" data-id="1356" target="_blank" rel="noreferrer noopener">numpy.array</a></code> object. </li><li>The <code>beta</code> parameter takes a number representing the beam width, which we choose between integer values of 1 and ∞ (a large enough number for practical purposes).</li></ul>



<p>For a better understanding of the algorithm and its implementation, each step is precisely described in the code below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from numpy import array


# Uses a beam to search through the tree
def beam_search(distances, beta):
    # Defines an initial, dummy record structure represented by
    # visited vertices and the path length (so far),
    # traversed along each path.
    paths_so_far = [[list(), 0]]
    
    # Propagates through the neighbouring vertices tier by tier
    # (row by row). A vertex position is indicated by its
    # index in each row (dists).
    for idx, tier in enumerate(distances):
        if idx > 0:
            print(f'Paths kept after tier {idx-1}:')
            print(*paths_so_far, sep='\n')
        paths_at_tier = list()
        
        # Follows each path.
        for i in range(len(paths_so_far)):
            # Reads the current path and its length (sum of distances).
            path, distance = paths_so_far[i]
            
            # Extends the path for every possible neighboring vertex
            # at the current tier.
            for j in range(len(tier)):
                path_extended = [path + [j], distance + tier[j]]
                paths_at_tier.append(path_extended)
                
        # Sorts the newly generated paths by their length.
        paths_ordered = sorted(paths_at_tier, key=lambda element: element[1])
        
        # The best 'beta' paths are preserved.
        paths_so_far = paths_ordered[:beta]
        print(f'\nPaths pruned after tier {idx}: ')
        print(*paths_ordered[beta:], sep='\n')
        
    return paths_so_far


# Define a distance matrix of 10 tiers
dists = [[1, 3, 2, 5, 8],
         [4, 7, 9, 6, 7]]
dists = array(dists)

# Calculates the best paths by applying a beam of width 'beta'.
best_beta_paths = beam_search(dists, 3)

# Prints the best 'beta' paths.
print('\nThe best \'beta\' paths:')
for beta_path in best_beta_paths:
    print(beta_path)
</pre>



<p>The test run gave us the output (for β = 3):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Paths pruned after tier 0: 
[[3], 5]
[[4], 8]
Paths kept after tier 0:
[[0], 1]
[[2], 2]
[[1], 3]

Paths pruned after tier 1: 
[[1, 0], 7]
[[0, 1], 8]
[[0, 4], 8]
[[2, 3], 8]
[[2, 1], 9]
[[2, 4], 9]
[[1, 3], 9]
[[0, 2], 10]
[[1, 1], 10]
[[1, 4], 10]
[[2, 2], 11]
[[1, 2], 12]

The best 'beta' paths:
[[0, 0], 5]
[[2, 0], 6]
[[0, 3], 7]
</pre>



<p>The resulting output shows the intermediate and final paths in a list of vertex indices and the total path length.</p>



<p>Based on the <a href="https://blog.finxter.com/python-print/" data-type="post" data-id="20731" target="_blank" rel="noreferrer noopener">output</a>, we can see that the search started from the root vertex and that in the first iteration (tier 0) the <code>beam_search()</code> has pruned two and kept three (shortest) paths, marked by the vertex indices and the appropriate total path length so far.</p>



<p>In the second iteration, the <code>beam_search()</code> has pruned twelve and kept three (shortest) paths, marked by the vertex indices and the appropriate total path length so far. Since our <code>dists</code> matrix has only two tiers (I&#8217;ve kept it short for educational purposes), the algorithm ends here.</p>



<p>The final result is also displayed as The best &#8216;beta&#8217; paths.</p>



<p>After setting the β to 1 and a re-run, we got a result matching a best-first search algorithm:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Paths pruned after tier 0: 
[[2], 2]
[[1], 3]
[[3], 5]
[[4], 8]
Paths kept after tier 0:
[[0], 1]

Paths pruned after tier 1: 
[[0, 3], 7]
[[0, 1], 8]
[[0, 4], 8]
[[0, 2], 10]

The best 'beta' paths:
[[0, 0], 5]
</pre>



<p>On the contrary, a large β (larger than number of distances in each tier multiplied, e.g. 5 x 5) would yield a <a href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" data-type="post" data-id="36880" target="_blank" rel="noreferrer noopener">breadth-first search</a> algorithm behavior, where no pruning occurs:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Paths pruned after tier 0: 

Paths kept after tier 0:
[[0], 1]
[[2], 2]
[[1], 3]
[[3], 5]
[[4], 8]

Paths pruned after tier 1: 


The best 'beta' paths:
[[0, 0], 5]
[[2, 0], 6]
[[0, 3], 7]
[[1, 0], 7]
[[0, 1], 8]
[[0, 4], 8]
[[2, 3], 8]
[[2, 1], 9]
[[2, 4], 9]
[[1, 3], 9]
[[3, 0], 9]
[[0, 2], 10]
[[1, 1], 10]
[[1, 4], 10]
[[2, 2], 11]
[[3, 3], 11]
[[1, 2], 12]
[[3, 1], 12]
[[3, 4], 12]
[[4, 0], 12]
[[3, 2], 14]
[[4, 3], 14]
[[4, 1], 15]
[[4, 4], 15]
[[4, 2], 17]
</pre>



<h2 class="wp-block-heading" id="efficiency-analysis">Efficiency analysis</h2>



<p>The algorithm&#8217;s worst-case time complexity depends on β and lies between&nbsp;<em>O(bd)</em>&nbsp;(behaves like a pure best-first search algorithm) and&nbsp;<em>O(|V| + |E|)</em>&nbsp;(behaves like a pure breadth-first search algorithm). It is determined by the heuristic function and the factor β.</p>



<p>The algorithm&#8217;s worst-case space complexity also depends on β and lies between&nbsp;<em>O(bd)</em>&nbsp;(behaves like a pure best-first search algorithm) and&nbsp;<em>O(|V|)</em>&nbsp;(behaves like a pure breadth-first search algorithm).</p>



<h2 class="wp-block-heading" id="conclusion">Conclusion</h2>



<p>In this article, we learned about the beam search algorithm.</p>



<ul class="wp-block-list"><li>First, we explained what a beam search algorithm is.</li><li>Second, we took a look at what are its common purposes and applications.</li><li>Third, we went through an explanation of how the algorithm works.</li><li>Fourth, we examined the algorithm&#8217;s main properties.</li><li>Fifth, we went through the implementation of the algorithm. We also tested the algorithm by calling its main function, beam_search(), and analyzed its steps of execution for the smallest, middle, and largest (&#8220;infinite&#8221;) β scenarios.</li><li>Sixth, we analyzed the algorithm efficiency.</li></ul>



<p>In the end, we concluded that the algorithm&#8217;s efficiency may be optimal if it behaves like a breadth-first search algorithm, although such mode of operation would defeat its initial purpose &#8212; to reduce the space complexity and data storage requirements. </p>



<p>In other modes of operation, the algorithm is not guaranteed to perform optimally and might also take a virtually infinite time in reaching the solution, especially for β = 1. </p>



<p>However, this behavior can be prevented by constructing the appropriate heuristic function using the relevant knowledge about the graph and vertice relationships.</p>



<hr class="wp-block-separator"/>






<h2 class="wp-block-heading">Academy Course &#8211; Mastering the Top 10 Graph Algorithms</h2>



<p>If you want to improve your fundamental computer science skills, there&#8217;s nothing more effective than <strong>studying algorithms</strong>. </p>



<p>To help you master the <strong>most important graph algorithms</strong>, we&#8217;ve just launched the &#8220;Top 10 Algorithms&#8221; course at the <a rel="noreferrer noopener" href="https://academy.finxter.com/university/graph-algorithms-in-python/" data-type="URL" data-id="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank">Finxter Computer Science Academy</a>. This great course from Finxter Star Creator Matija <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> teaches you the most important graph algorithms such as BFS, DFS, A*, and Dijkstra. </p>



<p>Understanding these algorithms will not only make you a better coder, but it&#8217;ll also lay a strong foundation on which you can build your whole career as a computer scientist.</p>



<p>Click the screenshot to find out more:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><a href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="363" height="650" src="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png" alt="" class="wp-image-246565" srcset="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png 363w, https://blog.finxter.com/wp-content/uploads/2022/03/image-141-168x300.png 168w" sizes="auto, (max-width: 363px) 100vw, 363px" /></a></figure></div>



<div class="wp-block-buttons alignwide is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-50"><a class="wp-block-button__link" href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noreferrer noopener">Learn More</a></div>
</div>



<p></p>
<p>The post <a href="https://blog.finxter.com/python-beam-search-algorithm/">Python Beam Search Algorithm</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Python Backtracking &#8211; A Helpful Guide with Video</title>
		<link>https://blog.finxter.com/python-backtracking-a-helpful-guide-with-video/</link>
		
		<dc:creator><![CDATA[Matija Horvat]]></dc:creator>
		<pubDate>Thu, 03 Feb 2022 17:13:30 +0000</pubDate>
				<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=170273</guid>

					<description><![CDATA[<p>You can check out the slides here (direct PDF link): Before we&#8217;ll dive into the algorithm and the Python implementation, let&#8217;s first skim over some related graph tutorials you may enjoy and that may help your understanding! Related Graph Tutorials This algorithm is part of our graph algorithm tutorials: Breadth-First Search (BFS) Algorithm in Python ... <a title="Python Backtracking &#8211; A Helpful Guide with Video" class="read-more" href="https://blog.finxter.com/python-backtracking-a-helpful-guide-with-video/" aria-label="Read more about Python Backtracking &#8211; A Helpful Guide with Video">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/python-backtracking-a-helpful-guide-with-video/">Python Backtracking &#8211; A Helpful Guide with Video</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Python Backtracking – A Helpful Guide" width="937" height="527" src="https://www.youtube.com/embed/Tn_VjnTf6EQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>You can check out the slides here (direct PDF link):</p>



<div data-wp-interactive="core/file" class="wp-block-file aligncenter"><object data-wp-bind--hidden="!state.hasPdfPreview" hidden class="wp-block-file__embed" data="https://blog.finxter.com/wp-content/uploads/2022/02/Python-blog-Backtracking.pdf" type="application/pdf" style="width:100%;height:600px" aria-label="Embed of Embed of Python-blog-Backtracking.."></object><a id="wp-block-file--media-3b68217c-aa0f-4a6d-81b7-dd5abb15690a" href="https://blog.finxter.com/wp-content/uploads/2022/02/Python-blog-Backtracking.pdf" target="_blank" rel="noreferrer noopener">Python-blog-Backtracking</a><a href="https://blog.finxter.com/wp-content/uploads/2022/02/Python-blog-Backtracking.pdf" class="wp-block-file__button" download aria-describedby="wp-block-file--media-3b68217c-aa0f-4a6d-81b7-dd5abb15690a">Download</a></div>



<p>Before we&#8217;ll dive into the algorithm and the Python implementation, let&#8217;s first skim over some related graph tutorials you may enjoy and that may help your understanding!</p>



<h2 class="wp-block-heading" id="related-graph-tutorials">Related Graph Tutorials</h2>



<p>This algorithm is part of our graph algorithm tutorials:</p>



<ul class="wp-block-list"><li><a rel="noreferrer noopener" href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" target="_blank">Breadth-First Search (BFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-depth-first-search-dfs-algorithm/" target="_blank">Python Depth-First Search (DFS) Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/iterative-deepening-depth-first-search-dfs-algorithm-in-python/" target="_blank">Iterative Deepening Depth-First Search (DFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" target="_blank">Python Best-First Search Algorithm</a></li><li><a href="https://blog.finxter.com/python-dijkstra-algorithm/">Python Dijkstra Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" target="_blank">Python A* Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/jump-search-algorithm-in-python-a-helpful-guide-with-video/" target="_blank">Jump Search Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-backtracking-a-helpful-guide-with-video/" target="_blank">Python Backtracking</a></li><li><a href="https://blog.finxter.com/python-beam-search-algorithm/" data-type="post" data-id="204131">Python Beam Search Algorithm</a></li></ul>



<p>Each of these tutorial links opens in a new browser tab.</p>



<h2 class="wp-block-heading" id="what-is-backtracking">What is Backtracking?</h2>



<p>Backtracking is a general approach, i.e. a variant of a <a rel="noreferrer noopener" href="https://blog.finxter.com/python-depth-first-search-dfs-algorithm/" data-type="post" data-id="37723" target="_blank">depth-first search algorithm</a>, suited for solving <em>constraint satisfaction problems</em>. </p>



<p class="has-global-color-8-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Idea</strong>: Backtracking incrementally validates candidates, tests the solutions, and <em>backtracks </em>from a candidate value if it determines that the final solution is not valid while containing the candidate value.</p>



<h2 class="wp-block-heading" id="what-is-the-purpose-of-backtracking">What is the Purpose of Backtracking?</h2>



<p>Backtracking is commonly used in solving crosswords, verbal arithmetic, and similar puzzles. </p>



<p>It is the most appropriate method for <em>parsing, </em>i.e. analyzing a string of symbols, solving a <em>knapsack problem, </em>and other combinatorial optimization problems. </p>



<p>Backtracking is also the basis for some logic programming languages, such as <em>Prolog</em>.</p>



<h2 class="wp-block-heading" id="how-does-backtracking-work">How Does Backtracking Work?</h2>



<p>A backtracking-based algorithm, in our case implemented as a Sudoku game, works by starting in the top left corner and searching for the empty positions in the puzzle by going from left to right. </p>



<p>When the algorithm finds an empty position, it will rotate a series of candidate values, <a href="https://blog.finxter.com/python-range-function/" data-type="post" data-id="18290" target="_blank" rel="noreferrer noopener">ranging</a> from 0 to 9, and check if there is a value that satisfies the basic rules of Sudoku: uniqueness in its row, its column, and its group. </p>



<ul class="wp-block-list"><li>If the value matches the rules, the algorithm will recursively proceed to the next free position, retry the same series of values, and repeat the same steps until it reaches the end. </li><li>If no value from the series matches the rules, the algorithm will backtrack to the previously filled position, try the next rule-matching value from the series, and resume searching for the next free position, <a href="https://blog.finxter.com/recursion/" data-type="post" data-id="3941" target="_blank" rel="noreferrer noopener">recursively</a> repeating the process.</li></ul>



<p>Once the last free position has been filled with the rule-matching value, the algorithm will yield the solution and end. </p>



<p>If the algorithm encounters a free position that cannot be filled with a rule-matching value, it will eventually exhaust the series of values for the first free position and there will be no solution found, i.e. the puzzle will be left unsolved.</p>



<p>Backtracking functionality is achieved by recursively checking, i.e. descending lower in the search space by using the depth-first search algorithm. </p>



<p>The algorithm is implemented implicitly and the <a href="https://blog.finxter.com/graph-applications/" data-type="post" data-id="955" target="_blank" rel="noreferrer noopener">graph</a> vertex is conceptually represented by the current state of the puzzle. </p>



<p>All previous states along the current search path are preserved in their corresponding function contexts. </p>



<p>Contrary to other graph algorithms, this algorithm did not require us to explicitly generate the search space, usually represented by a graph, because it would have enormous requirements in both terms of space (memory) and time (duration). Furthermore, most parts of the generated graph would remain unexplored.</p>



<h2 class="wp-block-heading" id="what-are-backtracking-properties">What are Backtracking Properties?</h2>



<p>One of the significant properties of the backtracking approach is that the solution discovery is guaranteed for valid puzzles, i.e. the ones that have a solution. </p>



<p>The second important property is the <strong>simplicity</strong> and <strong>flexibility</strong> of approach implementation, which makes it a good general approach for testing the existence of a solution.</p>



<p>On the downside, depending on a specific problem, solution finding by applying a backtracking approach can be inferior to stochastic search or other optimization methods.</p>



<h2 class="wp-block-heading" id="how-is-backtracking-implemented">How is Backtracking Implemented?</h2>



<p>An example of our backtracking algorithm is implemented in a form of a Sudoku solution finder. </p>



<p>The program is very simple, self-contained, and has only three functions: <code>backtrack_sudoku()</code>, <code>next_position()</code>, and <code>test_candidate()</code>.</p>



<p>The main function, <code>backtrack_sudoku()</code> takes two parameters: </p>



<ul class="wp-block-list"><li>the <code>puzzle</code> parameter as an initialized 2D <a rel="noreferrer noopener" href="https://blog.finxter.com/python-lists/" data-type="post" data-id="7332" target="_blank">list</a> object (a <a rel="noreferrer noopener" href="https://blog.finxter.com/python-list-of-lists/" data-type="post" data-id="7890" target="_blank">list of lists</a>), and </li><li>the optional <code>print_steps</code> parameter, which&nbsp;enables us to see the steps which our algorithm took before reaching the final solution (if there is one). It defaults to <code>False</code> but can be activated if we call the main function in the following way: <code>backtrack_sudoku(puzzle, <strong>True</strong>)</code>.</li></ul>



<p>The utility function, <code>next_position()</code> takes only one parameter, <code>puzzle</code>, representing our puzzle, and calculating the next free position on the puzzle board. </p>



<p>If we imagine traversing the puzzle board row-by-row, i.e. by starting on the top-left position, scanning the entire row, and then progressing to the leftmost position in the next row, the first empty position not containing a value is considered to be free.</p>



<p>The function <code>test_candidate()</code> takes three parameters: </p>



<ul class="wp-block-list"><li><code>puzzle</code>, representing our puzzle, then </li><li>the <code>candidate_value</code>, and </li><li>a <code>position</code>. </li></ul>



<p>The function tests different candidate values, looping from 0 to 9, and tries to find the candidate value that is unique in the current row, column, and its group.</p>



<p>For a better understanding of the algorithm and its implementation, each step is precisely described in the code below.</p>



<p>The entire algorithm listing follows:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">dimension = 3
iterations = 0


# An anonymous placeholder object.
class Object:
    def __init__(self):
        self.row = None
        self.column = None

    pass


def next_position(puzzle):
    # Loops through the search space by rows and then by columns.
    for i in range(len(puzzle)):
        for j in range(len(puzzle[0])):
            if puzzle[i][j] is None:
                position = Object()
                position.row = i
                position.column = j
                return position
    return None


def test_candidate(puzzle, candidate_value, position):
    # Searches the row for duplicate values of the 'candidate_value'.
    for i in range(len(puzzle[0])):
        # Prevents detecting the 'candidate_value' as a duplicate.
        if puzzle[position.row][i] == candidate_value and position.column != i:
            return False

    # Searches the column for duplicate values of the 'candidate_value'.
    for i in range(len(puzzle)):
        # Prevents detecting the 'candidate_value' as a duplicate.
        if puzzle[i][position.column] == candidate_value and position.row != i:
            return False

    # Forms and searches the groups for duplicate values of the 'candidate_value'.
    group = Object()
    # Determines the group by integer division of the position coordinates.
    group.column = position.column // dimension
    group.row = position.row // dimension
    # Performs the group search inside a group, by rows and columns.
    for i in range(group.row * dimension, (group.row + 1) * dimension):
        for j in range(group.column * dimension, (group.column + 1) * dimension):
            if puzzle[i][j] == candidate_value and (i, j) != position:
                return False
    return True


def backtrack_sudoku(puzzle, print_steps=False):
    # Counts the total number of iterations until the solution is found.
    global iterations
    iterations += 1
    # Finds the next free position.
    position = next_position(puzzle)
    if not position:
        return True
    # Tries out every possible value at the given (free) position.
    for i in range(1, dimension * dimension + 1):
        # Tests if the value matches the general rules,
        # i.e. value uniqueness in the row, column and group.
        if test_candidate(puzzle, i, position):
            puzzle[position.row][position.column] = i
            if print_steps:
                print(f'\n\n***  Iteration: {iterations}  ***\n')
                print_puzzle(puzzle)
            # Proceeds with the search by going one level deeper in the
            # search tree, effectively doing the depth-first search algorithm.
            if backtrack_sudoku(puzzle, print_steps):
                return True
            # Marks the position as empty if none of the values match the rules.
            puzzle[position.row][position.column] = None

    return False


def print_puzzle(puzzle):
    for i in range(len(puzzle)):
        if i % dimension == 0 and i != 0:
            print('')

        for j in range(len(puzzle[0])):
            if j % dimension == 0 and j != 0:
                print('  ', end='')
            print(str(puzzle[i][j] or '_'), end=' ')
            if j % (dimension * dimension - 1) == 0 and j != 0:
                print('')
</pre>



<p>Now that we have prepared everything, we can test <code>backtrack_sudoku()</code> and see how it works. </p>



<p>We have three readily available puzzles, arranged by their difficulty, as easy, medium, and hard.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">easy = [
    [None, None, None, None, None, None, None, None, None],
    [None, 7, 6, None, None, None, 8, 4, None],
    [1, 8, None, None, None, 4, None, 7, 5],
    [None, None, None, 2, 5, None, None, None, 6],
    [None, None, 1, 4, None, 7, 3, None, None],
    [6, None, None, None, 3, 8, None, None, None],
    [3, 5, None, None, None, 9, None, 8, 1],
    [None, 1, 4, None, None, None, 2, 5, None],
    [None, None, None, None, None, None, None, None, None]
]

medium = [
    [None, None, None, 4, None, None, None, 8, None],
    [None, 4, None, None, None, 3, None, None, None],
    [8, None, None, None, None, None, 1, 3, None],
    [None, None, None, 6, None, None, None, None, None],
    [None, None, 8, 2, 1, None, None, None, 7],
    [5, None, None, None, None, 4, None, None, None],
    [7, None, None, 3, None, None, 5, None, 9],
    [9, None, None, None, 8, None, 2, None, None],
    [None, None, 6, None, 5, None, 3, None, None]
]

hard = [
    [None, 2, None, None, None, None, None, 9, None],
    [None, None, None, None, 7, 4, 8, None, None],
    [4, 3, None, None, None, 1, None, None, None],
    [5, None, 6, 7, None, None, None, None, None],
    [None, None, None, None, 2, None, None, None, None],
    [None, None, None, None, None, 9, None, None, 3],
    [None, None, 3, None, None, None, None, 8, None],
    [None, 1, None, 9, 5, None, 6, None, None],
    [None, 5, None, None, None, None, None, 7, None]
]
</pre>



<p>Here is the part of the code that runs the algorithm, shows the puzzle we chose to solve, and the final solution, depending on if it exists:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="5" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">solve_for_puzzle = easy

print_puzzle(solve_for_puzzle)
print('\nLooking for the solution...\n')
backtrack_sudoku(solve_for_puzzle)
print('\n  ***  THE SOLUTION  ***')
print(f'Iterations required: {iterations}\n')
print_puzzle(solve_for_puzzle)
</pre>



<p>We have the following output for our easy puzzle:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">_ _ _   _ _ _   _ _ _ 
_ 7 6   _ _ _   8 4 _ 
1 8 _   _ _ 4   _ 7 5 

_ _ _   2 5 _   _ _ 6 
_ _ 1   4 _ 7   3 _ _ 
6 _ _   _ 3 8   _ _ _ 

3 5 _   _ _ 9   _ 8 1 
_ 1 4   _ _ _   2 5 _ 
_ _ _   _ _ _   _ _ _ 

Looking for the solution...


  ***  THE SOLUTION  ***
Iterations required: 21644

9 4 5   8 7 3   1 6 2 
2 7 6   1 9 5   8 4 3 
1 8 3   6 2 4   9 7 5 

4 3 8   2 5 1   7 9 6 
5 9 1   4 6 7   3 2 8 
6 2 7   9 3 8   5 1 4 

3 5 2   7 4 9   6 8 1 
7 1 4   3 8 6   2 5 9 
8 6 9   5 1 2   4 3 7 
</pre>



<p>If we rerun the algorithm, we have the following output for our medium puzzle:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">solve_for_puzzle = medium

_ _ _   4 _ _   _ 8 _ 
_ 4 _   _ _ 3   _ _ _ 
8 _ _   _ _ _   1 3 _ 

_ _ _   6 _ _   _ _ _ 
_ _ 8   2 1 _   _ _ 7 
5 _ _   _ _ 4   _ _ _ 

7 _ _   3 _ _   5 _ 9 
9 _ _   _ 8 _   2 _ _ 
_ _ 6   _ 5 _   3 _ _ 

Looking for the solution...


  ***  THE SOLUTION  ***
Iterations required: 261512

6 3 9   4 2 1   7 8 5 
1 4 5   8 7 3   6 9 2 
8 2 7   5 6 9   1 3 4 

2 7 4   6 3 8   9 5 1 
3 9 8   2 1 5   4 6 7 
5 6 1   7 9 4   8 2 3 

7 8 2   3 4 6   5 1 9 
9 5 3   1 8 7   2 4 6 
4 1 6   9 5 2   3 7 8 
</pre>



<p>On our last rerun of the algorithm, we have the following output for our hard puzzle:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">solve_for_puzzle = hard

_ 2 _   _ _ _   _ 9 _ 
_ _ _   _ 7 4   8 _ _ 
4 3 _   _ _ 1   _ _ _ 

5 _ 6   7 _ _   _ _ _ 
_ _ _   _ 2 _   _ _ _ 
_ _ _   _ _ 9   _ _ 3 

_ _ 3   _ _ _   _ 8 _ 
_ 1 _   9 5 _   6 _ _ 
_ 5 _   _ _ _   _ 7 _ 

Looking for the solution...


  ***  THE SOLUTION  ***
Iterations required: 321814

7 2 1   3 8 5   4 9 6 
9 6 5   2 7 4   8 3 1 
4 3 8   6 9 1   2 5 7 

5 4 6   7 3 8   9 1 2 
3 7 9   1 2 6   5 4 8 
1 8 2   5 4 9   7 6 3 

2 9 3   4 6 7   1 8 5 
8 1 7   9 5 3   6 2 4 
6 5 4   8 1 2   3 7 9 
</pre>



<h2 class="wp-block-heading" id="efficiency-analysis">Efficiency analysis</h2>



<p>After comparing the number of iterations the algorithm took to find the solution for different puzzle difficulties, we noticed a stunning increase of 1100% in the number of iterations between easy and medium difficulty puzzles. </p>



<p>Furthermore, we noticed an additional 23% increase in the number of iterations between medium and hard difficulty puzzles.</p>



<p>Based on our results, we can conclude that, depending on the specific problem, the backtracking approach may be appropriate if it manages to intelligently reduce the search space and solve the problem in finite time. </p>



<p>However, its efficiency can vary greatly with the problem complexity and the backtracking approach is not applicable in just every case.</p>



<h2 class="wp-block-heading" id="conclusion">Conclusion</h2>



<p>In this article, we learned about backtracking in search algorithms.</p>



<ul class="wp-block-list"><li>First, we explained what backtracking in search algorithms is.</li><li>Second, we took a look at what are its common purposes and applications.</li><li>Third, we went through an explanation of how the approach works.</li><li>Fourth, we examined the main properties of this approach.</li><li>Fifth, we went through an example implementation of backtracking in Sudoku-solving algorithm, which is based on simple three functions, <code>backtrack_sudoku()</code>, <code>next_position()</code>, and <code>test_candidate()</code>. </li><li>We also tested the algorithm by calling its main function, <code>backtrack_sudoku()</code>, and analyzed its steps of execution for three puzzles of different difficulties.</li><li>Sixth, we analyzed the algorithm efficiency.</li></ul>



<p>To conclude, the algorithm efficiency is much better than its main alternative in the form of a pure brute-force method, based on <em>trial-and-error</em>. However, the algorithm efficiency varies with the structure of a puzzle, i.e. the composition of the problem.</p>



<p>Depending on the specific problem, the backtracking approach may be found appropriate if it manages to consistently reduce the search space and solve the problem in a finite time. </p>



<p>However, it is not generally considered the best approach for every problem of this kind. In such cases, if it proves to be practically inefficient, an alternative approach should be taken into consideration.</p>






<h2 class="wp-block-heading">Academy Course &#8211; Mastering the Top 10 Graph Algorithms</h2>



<p>If you want to improve your fundamental computer science skills, there&#8217;s nothing more effective than <strong>studying algorithms</strong>. </p>



<p>To help you master the <strong>most important graph algorithms</strong>, we&#8217;ve just launched the &#8220;Top 10 Algorithms&#8221; course at the <a rel="noreferrer noopener" href="https://academy.finxter.com/university/graph-algorithms-in-python/" data-type="URL" data-id="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank">Finxter Computer Science Academy</a>. This great course from Finxter Star Creator Matija <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> teaches you the most important graph algorithms such as BFS, DFS, A*, and Dijkstra. </p>



<p>Understanding these algorithms will not only make you a better coder, but it&#8217;ll also lay a strong foundation on which you can build your whole career as a computer scientist.</p>



<p>Click the screenshot to find out more:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><a href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="363" height="650" src="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png" alt="" class="wp-image-246565" srcset="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png 363w, https://blog.finxter.com/wp-content/uploads/2022/03/image-141-168x300.png 168w" sizes="auto, (max-width: 363px) 100vw, 363px" /></a></figure></div>



<div class="wp-block-buttons alignwide is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-50"><a class="wp-block-button__link" href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noreferrer noopener">Learn More</a></div>
</div>



<p></p>
<p>The post <a href="https://blog.finxter.com/python-backtracking-a-helpful-guide-with-video/">Python Backtracking &#8211; A Helpful Guide with Video</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Jump Search Algorithm in Python &#8211; A Helpful Guide with Video</title>
		<link>https://blog.finxter.com/jump-search-algorithm-in-python-a-helpful-guide-with-video/</link>
		
		<dc:creator><![CDATA[Matija Horvat]]></dc:creator>
		<pubDate>Fri, 14 Jan 2022 16:28:53 +0000</pubDate>
				<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Research]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=136292</guid>

					<description><![CDATA[<p>As you watch the video, you can have a look at the slides as PDF: download slides in a new tab here. Before we&#8217;ll dive into the algorithm and the Python implementation, let&#8217;s first skim over some related graph tutorials you may enjoy and that may help your understanding! Related Graph Tutorials This algorithm is ... <a title="Jump Search Algorithm in Python &#8211; A Helpful Guide with Video" class="read-more" href="https://blog.finxter.com/jump-search-algorithm-in-python-a-helpful-guide-with-video/" aria-label="Read more about Jump Search Algorithm in Python &#8211; A Helpful Guide with Video">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/jump-search-algorithm-in-python-a-helpful-guide-with-video/">Jump Search Algorithm in Python &#8211; A Helpful Guide with Video</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Jump Search Algorithm in Python – A Helpful Guide" width="937" height="527" src="https://www.youtube.com/embed/afoQvbXvaiQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>As you watch the video, you can have a look at the slides as PDF: <a rel="noreferrer noopener" href="https://blog.finxter.com/wp-content/uploads/2022/01/Python-blog-Jump-Point-Search-Algorithm.pdf" data-type="URL" data-id="https://blog.finxter.com/wp-content/uploads/2022/01/Python-blog-Jump-Point-Search-Algorithm.pdf" target="_blank">download slides in a new tab here</a>.</p>



<p>Before we&#8217;ll dive into the algorithm and the Python implementation, let&#8217;s first skim over some related graph tutorials you may enjoy and that may help your understanding!</p>



<h2 class="wp-block-heading" id="related-graph-tutorials">Related Graph Tutorials</h2>



<p>This algorithm is part of our graph algorithm tutorials:</p>



<ul class="wp-block-list"><li><a rel="noreferrer noopener" href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" target="_blank">Breadth-First Search (BFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-depth-first-search-dfs-algorithm/" target="_blank">Python Depth-First Search (DFS) Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/iterative-deepening-depth-first-search-dfs-algorithm-in-python/" target="_blank">Iterative Deepening Depth-First Search (DFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" target="_blank">Python Best-First Search Algorithm</a></li><li><a href="https://blog.finxter.com/python-dijkstra-algorithm/">Python Dijkstra Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" target="_blank">Python A* Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/jump-search-algorithm-in-python-a-helpful-guide-with-video/" target="_blank">Jump Search Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-backtracking-a-helpful-guide-with-video/" target="_blank">Python Backtracking</a></li><li><a href="https://blog.finxter.com/python-beam-search-algorithm/" data-type="post" data-id="204131">Python Beam Search Algorithm</a></li></ul>



<p>Each of these tutorial links opens in a new browser tab.</p>



<h2 class="wp-block-heading">What is the Jump Point Search Algorithm?</h2>



<p>The <strong>jump point search algorithm</strong> &#8212; or shorter <strong>JPS</strong> &#8212; is a variant of the <a rel="noreferrer noopener" href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" data-type="post" data-id="81313" target="_blank">A* search algorithm</a>, optimized for pathfinding on grid maps, i.e., in computer games. </p>



<p>The jump point search algorithm is invented and published by <strong>Daniel Harabor and Alban Grastien in 2011</strong>. </p>



<p>It exploits <em>path symmetry</em> which is manifested as a path (or path segments) which share the same start and goal vertex, have the same length, and are otherwise identical, but differ in the scan order. </p>



<p>In the authors&#8217; words, the algorithm is <strong><em>fast, optimal, and requires no memory overhead</em></strong>. </p>



<p>It identifies and selectively expands only vertices of interest, which are called <em>jump points</em>. This means that vertices between any two jump points are not expanded, or in our familiar terms, they remain unexplored. </p>



<p>This is a property that enables much faster algorithm operation by reducing the number of vertices that would otherwise have to be processed, e.g., by applying the original A* algorithm.</p>



<ul class="wp-block-list"><li><strong>Related Article</strong>: <a href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" data-type="post" data-id="81313" target="_blank" rel="noreferrer noopener">The A* Algorithm in Python</a></li></ul>



<h2 class="wp-block-heading">What is Its Purpose?</h2>



<p>A common application of the jump point search algorithm is <em><strong>pathfinding</strong></em>, such as in computer games or possibly in navigation systems.</p>



<p>In general, whenever there is a search space that can be generalized to a <em><strong>uniform cost grid</strong></em> (all the paths to the neighbouring vertices are of equal cost), the jump point search algorithm is highly applicable.</p>



<h2 class="wp-block-heading">How Does It Work?</h2>



<p>The jump point search algorithm builds on the A* algorithm, which means that we still have a heuristic estimation function, and <code>visited</code> (open) and <code>explored</code> (closed) <a href="https://blog.finxter.com/python-lists/" data-type="post" data-id="7332" target="_blank" rel="noreferrer noopener">lists</a>. We also get the same optimality properties of the result under the same conditions. </p>



<p>The algorithm operation differs in the data, specifically, in the <code>visited</code> and <code>explored</code> lists, and how a vertex gets expanded.</p>



<p>A* does not perform very well with big open fields, i.e. uniform cost grids, because it takes most of the time to process updates of the visited vertices. </p>



<p>On the other hand, the jump point search algorithm <strong>improves on the A* algorithm</strong> by exploiting the regularity of the grid, i.e., it does not need to search every possible path, since all paths are known to have equal costs. </p>



<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> In other words, most nodes in the grid are not interesting enough to be processed. </p>



<p>As a result, the jump point search algorithm spends much less time updating the <code>visited</code> and <code>explored</code> lists. It is sufficient to only scan the cells to check if there is a jump point nearby.</p>



<p>Instead of checking every neighbor from every possible vertex, the goal of each step in the scan is to decide whether the next point is interesting enough to create a new entry in the <code>visited</code> list. </p>



<p>If it is not, the algorithm continues the scanning iteration. </p>



<p>If a position is interesting enough, new jump points are recorded in the <code>visited</code> list, and the current scan iteration ends.</p>



<p>There are two cases of scan directions: <strong>horizontal/vertical</strong> and <strong>diagonal</strong>. Both cases are terminated when the scan runs into an obstacle (a <em>non-passable vertex</em>) or reaches the end of the search space. </p>



<p>Similarly, the scans yield a jump point if its search path passes beside an obstacle (black), as shown in the second and fourth pictures:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="123" height="123" src="https://blog.finxter.com/wp-content/uploads/2022/01/image-11.png" alt="" class="wp-image-136297"/><figcaption>(1)</figcaption></figure></div>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="124" height="123" src="https://blog.finxter.com/wp-content/uploads/2022/01/image-12.png" alt="" class="wp-image-136299"/><figcaption>(2) </figcaption></figure></div>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="124" height="123" src="https://blog.finxter.com/wp-content/uploads/2022/01/image-13.png" alt="" class="wp-image-136300"/><figcaption>(3)</figcaption></figure></div>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="124" height="123" src="https://blog.finxter.com/wp-content/uploads/2022/01/image-14.png" alt="" class="wp-image-136301"/><figcaption>(4)</figcaption></figure></div>



<p>White numerated vertices represent valid neighbors of <code>x</code>, while grey vertices represent invalid neighbors of <code>x</code>.</p>



<p>We are simulating undirected uniform-cost grid maps by having each pair of vertices connected by the two edges of opposite directions. Each vertex has up to 8 neighbors and is either traversable or not. </p>



<p>Each horizontal or vertical scan, from a traversable vertex to one of its neighbors, has a cost of 1 and diagonal moves cost of √2. </p>



<p>To make it easier on the algorithm, we will use 10x whole numbers as a measure of distance. Therefore, instead of the cost √2 = 1.41421&#8230; we will use the cost of 14/2 = 7, and instead of the cost 1, we will use the cost of 10/2 = 5. </p>



<p>Moves involving obstacles (non-traversable) vertices are not allowed. Each direction is defined by a number from 0 to 7:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="184" height="184" src="https://blog.finxter.com/wp-content/uploads/2022/01/image-15.png" alt="" class="wp-image-136302" srcset="https://blog.finxter.com/wp-content/uploads/2022/01/image-15.png 184w, https://blog.finxter.com/wp-content/uploads/2022/01/image-15-150x150.png 150w" sizes="auto, (max-width: 184px) 100vw, 184px" /></figure></div>



<ul class="wp-block-list"><li>Each <strong>double arrow</strong> represents two edges in opposite directions. </li><li>The <strong>numbers</strong> are indicating the direction each edge is oriented in. </li><li>The <strong>edge numeration </strong>enables us to use the <code>prune()</code> function for neighbours pruning and forced neighbours detection, regardless of the movement direction.</li></ul>



<h2 class="wp-block-heading">What Are Its Properties?</h2>



<p>As the jump point search algorithm builds on the <a href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" data-type="post" data-id="81313" target="_blank" rel="noreferrer noopener">A* algorithm</a>, it also uses the exact information represented by the successive edges&#8217; weights connecting the jump points and a heuristic function for distance estimation between the goal vertex and the jump points in a graph. </p>



<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> As the initial costs for all the jump points are set to infinity, the algorithm successively decreases jump points&#8217; costs until they reach their minimum.</p>



<p><strong>(1) Optimal</strong>: This behavior leads to a property of being <em><strong>optimal</strong></em>: minimal costs assigned to jump points enable the jump point search algorithm to always find the shortest path between the starting vertex and any jump point in the graph. </p>



<p>As the shortest paths always start from the starting vertex, the algorithm also belongs to the “<a href="https://blog.finxter.com/python-dijkstra-algorithm/" data-type="post" data-id="72692" target="_blank" rel="noreferrer noopener">single-source</a>” algorithm.</p>



<p><strong>(2) Complete</strong>: Besides being optimal, the algorithm is also <em><strong>complete</strong></em>, i.e. it will always take a finite time to find a solution.</p>



<p><strong>(3) Optimal Efficiency</strong>: The third important property is the <em><strong>optimal efficiency</strong></em>, reflected in the fact that jump points positioned further from the goal vertex may not be explored at all, as their heuristic function distinguishes and delays the exploration of such jump points among those with equally weighted paths.</p>



<p>The heuristic functions used in the jump point search algorithm also inherit two notable properties from the A* algorithm: <em>admissibility</em> and <em>consistency</em>. </p>



<ul class="wp-block-list"><li>Admissibility implies that the heuristic function cost estimation is at most as high as the lowest possible cost from the current point in a path towards the goal vertex.</li><li>The consistent or monotone heuristic function is constrained by a requirement that its cost estimation is always <a href="https://blog.finxter.com/python-less-than-or-equal-to/" data-type="post" data-id="30938" target="_blank" rel="noreferrer noopener">less than or equal</a> to the estimated distance from any adjoining, successor vertex to the goal, plus the cost of reaching that vertex.</li></ul>



<h2 class="wp-block-heading">How Is It Implemented?</h2>



<p>The implementation of the jump point search algorithm is achieved by the function <code>jps()</code> and a modification of the underlying class <code>Graph</code>.</p>



<p>The <code>jps()</code> function takes three parameters: </p>



<ul class="wp-block-list"><li>The <code>graph</code> parameter as an initialized <code>Graph</code> object (see the blog on the <em><a href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" data-type="URL" data-id="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" target="_blank" rel="noreferrer noopener">A* search algorithm</a></em>, the section on <em>graphs</em>). </li><li>The <code>start_vertex</code> parameter takes the starting vertex, which we choose freely (remember, a graph is not a tree, there is no absolute root). </li><li>The <code>goal_vertex</code> parameter is the entity we want to find in the graph, enclosed in a vertex.</li></ul>



<p>For a better understanding of the algorithm and its implementation, each step is precisely described in the code below.</p>



<p>There have been some further upgrades on the <code>Graph</code> class, in terms of the <strong><em>obstacle</em></strong> and <strong><em>direction</em></strong> properties, so its entire listing follows:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="47,61,97-111,126,153-161" data-enlighter-linenumbers="false" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Graph:

    def __init__(self, directed=False):
        self._outgoing = {}
        # If the graph is undirected, 'self._outgoing'
        # is the universal storage.
        self._incoming = {} if directed else self._outgoing

    # If the graph is directed, the 'self._incoming' 
    # dictionary differs from the 'self._outgoing'.
    def is_directed(self):
        return self._incoming is not self._outgoing

    # The function returns a generator of incoming
    # or outgoing (default) edges of a vertex.
    def adjacent_edges(self, vertex, outgoing=True):
        # References the corresponding outer dictionary
        # (dictionary of dictionaries)
        adj_edges = self._outgoing if outgoing else self._incoming

        # Access each of the edges for this endpoint vertex.
        for edge in adj_edges[vertex].values():
            yield edge

    def add_vertex(self, entity=None, h=None, cost=None):
        # Constructs a new vertex from the entity.
        vertex = self.Vertex(entity, h, cost)
        # The vertex becomes a key in the outer dictionary,
        # but the value is an internal dictionary (as we model
        # both dimensions for each edge: origin and destination).
        # e.g. {vertex_1a:{vertex_b:edge_a_b}, vertex_b:{vertex_c:edge_b_c}}.
        self._outgoing[vertex] = {}
        if self.is_directed():
            self._incoming[vertex] = {}

    def add_edge(self, origin, destination, weight=None, direction=None):
        # Constructs a new edge from the vertices.
        edge = self.Edge(origin, destination, weight, direction)
        # Adds the edge to the dictionary (dictionaries are
        # the same if the graph is undirected). The outer key
        # represents the origin, i.e. the component 'a' of
        # the edge-defining pair (a, b). The inner key stands
        # for the component 'b' of the edge-defining pair (a, b).
        self._outgoing[origin][destination] = edge
        # Even if the graph is undirected, each edge has to
        # be added twice, i.e. once for each of its endpoints.
        edge = self.Edge(origin, destination, weight, (direction + 4) % 8)
        self._incoming[destination][origin] = edge

    def vertices(self):
        return self._outgoing.keys()

    def edges(self):
        # All the edges are collected into a set.
        result = set()
        for inner_dict in self._outgoing.values():
            result.update(inner_dict.values())
        return result

    class Vertex:
        __slots__ = '_entity', '_h', '_cost', '_obstacle', '_direction'

        def __init__(self, entity, h=None, cost=None):
            self.entity = entity
            self.h = h
            self.cost = cost
            self.obstacle = False
            self.direction = None

        # The real-world entity is represented by the Vertex object.
        @property
        def entity(self):
            return self._entity

        @entity.setter
        def entity(self, entity):
            self._entity = entity

        # The real-world entity has a heuristic value of 'h'.
        @property
        def h(self):
            return self._h

        @h.setter
        def h(self, h):
            self._h = h

        # The real-world entity has a cost of 'cost'.
        @property
        def cost(self):
            return self._cost

        @cost.setter
        def cost(self, cost):
            self._cost = cost

        @property
        def obstacle(self):
            return self._obstacle

        @obstacle.setter
        def obstacle(self, obstacle):
            self._obstacle = obstacle

        @property
        def direction(self):
            return self._direction

        @direction.setter
        def direction(self, direction):
            self._direction = direction

        # We have to implement __hash__ to use the object as a dictionary key.
        def __hash__(self):
            return hash(id(self))

        def __lt__(self, other):
            if self.cost is None:
                return False
            elif other.cost is None:
                return True
            else:
                return self.cost &lt; other.cost

    class Edge:
        __slots__ = '_origin', '_destination', '_weight', '_direction'

        def __init__(self, origin, destination, weight=None, direction=None):
            self._origin = origin
            self._destination = destination
            self.weight = weight
            self.direction = direction

        def endpoints(self):
            return self._origin, self._destination

        # Returns the other component of the edge-defining pair (a, b)
        # for a given component a or b, respectively.
        def opposite(self, vertex):
            return self._destination if self._origin is vertex \
                else self._origin

        # Returns the weight of the edge.
        @property
        def weight(self):
            return self._weight

        # Sets the weight of the edge
        @weight.setter
        def weight(self, weight):
            self._weight = weight

        # Returns the direction of the edge.
        @property
        def direction(self):
            return self._direction

        # Sets the direction of the edge
        @direction.setter
        def direction(self, direction):
            self._direction = direction

        def __hash__(self):
            return hash((self._origin, self._destination)) 
</pre>



<p>The most significant differences to the previous version of the Graph class are highlighted.</p>



<p>With these changes in place, implementation of the core function, <code>jps()</code> is:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from graph import Graph
from queue import PriorityQueue
from collections import namedtuple


# Just a dummy object attached with a dummy function...
class Object:
    pass


def prune(graph, vertex, direction=None):
    neighbours = {}
    forced_neighbours_exist = False
    if direction is None:
        direction = vertex.direction

    # Enables us to return both the neighbouring vertices and the
    # indicator of forced neighbours existence
    pruned = namedtuple('pruned', 'vertices forced')

    # ...right here :-) We use it to ensure availability of the property
    # when the None object gets returned from the 'neighbours' dictionary.
    o = Object()
    o.obstacle = lambda: True

    # Collects all the surrounding vertices in a dictionary and
    # marks them with the search direction
    for edge in graph.adjacent_edges(vertex):
        neighbours[edge.direction] = edge.opposite(vertex)

    # Applies exclusively to the non-starting vertices
    if direction is not None:
        # Determines if the movement direction is horizontal/vertical (0) or diagonal (1)
        is_diagonal = direction % 2

        leftmost_dir = change_dir(direction, 2 + is_diagonal)
        rightmost_dir = change_dir(direction, -2 - is_diagonal)

        # Parent is never a neighbour candidate
        neighbours.pop(change_dir(direction, 4), None)

        # Trivial case - check if some of natural neighbours are obstacles
        for idx in range(-is_diagonal, is_diagonal + 1):
            if neighbours.get(change_dir(direction, idx), o).obstacle:
                neighbours.pop(change_dir(direction, idx), None)

        # Non-trivial case of potentially forced neighbours (left)
        if neighbours.get(change_dir(leftmost_dir, -1), o).obstacle \
                or not neighbours.get(leftmost_dir, o).obstacle:
            # Discards the forced neighbour candidate
            neighbours.pop(change_dir(leftmost_dir, -1), None)
        else:
            forced_neighbours_exist = True
        neighbours.pop(leftmost_dir, None)

        # Non-trivial case of potentially forced neighbours (right)
        if neighbours.get(change_dir(rightmost_dir, 1), o).obstacle \
                or not neighbours.get(rightmost_dir, o).obstacle:
            # Discards the forced neighbour candidate
            neighbours.pop(change_dir(rightmost_dir, 1), None)
        else:
            forced_neighbours_exist = True
        neighbours.pop(rightmost_dir, None)

        # Back vertices are never neighbour candidates
        neighbours.pop(change_dir(direction, 4 + 1), None)
        neighbours.pop(change_dir(direction, 4 - 1), None)

    return pruned(neighbours, forced_neighbours_exist)


def step(graph, vertex, direction, cost_so_far):
    # Defines a fail-safe result.
    next_vertex = None
    cost = 0

    # Searches among the available edges and follows the right one.
    for edge in graph.adjacent_edges(vertex):
        if edge.direction == direction and not edge.opposite(vertex).obstacle:
            next_vertex = edge.opposite(vertex)
            cost = cost_so_far + edge.weight
            break
        else:
            continue

    # If the edge is not found, the equivalent of "nothing" is returned.
    return next_vertex, cost


# Changes the direction within the defined eight directions
def change_dir(direction, amount):
    return (direction + amount) % 8


def jump(graph, vertex, direction, cost_so_far, goal_vertex):
    jump_point, cost = step(graph, vertex, direction, cost_so_far)

    if jump_point is None:
        return None, None

    # If a vertex is the goal vertex:
    if jump_point.entity == goal_vertex:
        return jump_point, cost

    # Checks if forced neighbours exist
    if prune(graph, jump_point, direction).forced:
        return jump_point, cost

    # Activates if the direction is diagonal.
    if direction % 2:
        for direction_l_r in (change_dir(direction, 1), change_dir(direction, -1)):
            # Tests if the next jump point exists (its cost is irrelevant in the context of the check alone).
            next_jump_point, _ = jump(graph, jump_point, direction_l_r, 0, goal_vertex)
            if next_jump_point is not None:
                return jump_point, cost

    # Proceed in the same direction.
    jump_point, cost = jump(graph, jump_point, direction, cost, goal_vertex)
    return jump_point, cost


def jps(graph, start_vertex, goal_vertex):
    # Create the priority queue for open vertices.
    jump_points_pq = PriorityQueue()

    start_vertex = vertices[start_vertex]
    start_vertex.cost = 0
    # start_vertex is the only one in the first round of queueing,
    # so it doesn't need a distance to goal estimation.
    start_vertex.h = 0

    # Adds the start vertex to the priority queue.
    print(f'Visiting/queueing vertex {start_vertex.entity}')

    jump_points_pq.put(start_vertex)
    print('Prioritized vertices (v, cost, dir):',
          *((vert.entity, vert.cost, vert.direction) for vert in jump_points_pq.queue),
          end=2 * '\n')

    # The starting vertex is visited first and has no leading edges.
    visited[start_vertex.entity] = None

    # Loops until the priority list gets empty.
    while not jump_points_pq.empty():
        # Gets the previously calculated jump_point with the lowest cost.
        jpoint_prev = jump_points_pq.get()
        print(f'Exploring vertex {jpoint_prev.entity}')

        # If the vertex being explored is a goal vertex, the algorithm ends.
        if jpoint_prev.entity == goal_vertex:
            return jpoint_prev

        # Finds the vertex neighbours (natural and forced).
        neighbours = prune(graph, jpoint_prev)

        for direction in neighbours.vertices:
            jpoint, cost = jump(graph, jpoint_prev, direction, jpoint_prev.cost, goal_vertex)

            if jpoint is None or vertices.get(jpoint, None) in explored:
                continue

            # Calculates the jump point's heuristic value.
            if jpoint.h is None:
                jpoint.h = tuple(map(lambda x, y: abs(x - y), jpoint.entity, goal_vertex))
                jpoint.h = abs(jpoint.h[0] - jpoint.h[1]) * cost_hv \
                    + min(jpoint.h[0], jpoint.h[1]) * cost_di

            # Prevents reinsertion to the priority queue. The endpoint distance value will be updated.
            if jpoint.entity not in visited:
                print(f'Visiting/queueing vertex {jpoint.entity}.')
                visited[jpoint.entity] = jpoint_prev.entity
                jump_points_pq.put(jpoint)

            if jpoint.cost is None or jpoint.cost - jpoint.h > cost - jpoint_prev.h:
                jpoint.cost = cost - jpoint_prev.h + jpoint.h
                jpoint.direction = direction

            # Forces the priority queue to recalculate in case of an
            # inner vertex update resulting with the highest priority.
            if not jump_points_pq.empty():
                jump_points_pq.put(jump_points_pq.get())

        print('Prioritized vertices (v, cost, dir):',
              *((vert.entity, vert.cost, vert.direction) for vert in jump_points_pq.queue), end=2 * '\n')
        # The vertex is used for update and put aside.
        explored.append(jpoint_prev)


# Initializes an empty graph (object).
g = Graph()

# Initializes the grid dimensions.
m, n = 7, 9

# Defines horizontal/vertical and diagonal costs.
cost_hv = 5
cost_di = 7

# Loads the graph with [m x n] vertices.
for i in range(m):
    for j in range(n):
        g.add_vertex((i, j))

# Constructs the 'vertices' dictionary for a more
# convenient access during the graph construction.
vertices = {k.entity: k for k in g.vertices()}

# Generates the edges.
for i in range(m):
    for j in range(n):
        # Horizontal connections
        if j &lt; n - 1:
            g.add_edge(vertices[i, j], vertices[i, j + 1], weight=cost_hv, direction=0)
        # Vertical connections
        if i &lt; m - 1:
            g.add_edge(vertices[i, j], vertices[i + 1, j], weight=cost_hv, direction=6)
        # Left diagonal connections
        if i &lt; m - 1 and j &lt; n - 1:
            g.add_edge(vertices[i, j], vertices[i + 1, j + 1], weight=cost_di, direction=7)
        # Right diagonal connections
        if i &lt; m - 1 and j > 0:
            g.add_edge(vertices[i, j], vertices[i + 1, j - 1], weight=cost_di, direction=5)

# Initializes the search path and a dictionary of visited vertices.
path = []
explored = []
visited = {}

# Initializes the obstacles.
vertices[(0, 2)].obstacle = True
vertices[(1, 2)].obstacle = True
vertices[(2, 2)].obstacle = True
vertices[(1, 4)].obstacle = True
vertices[(2, 4)].obstacle = True
vertices[(3, 4)].obstacle = True
vertices[(2, 6)].obstacle = True
vertices[(3, 6)].obstacle = True
vertices[(4, 6)].obstacle = True
</pre>



<p>Now that we have prepared everything, we can test <code>jps()</code> and see how it works. Here is the part of the code that runs the algorithm, constructs the search path (if there is one), and shows in a step-by-step manner how it proceeds through the graph:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Starts the search.
result = jps(g, (0, 0), (1, 8))

# If the entity is found...
if result is not None:
    # The search path ends with the found vertex (entity).
    # Each vertex is a container for its real-world entity.
    path_vertex = result.entity
    # Constructs the rest of the search path (if it exists)...
    while path_vertex is not None:
        # The entity is added to the 'path'.
        path.append(path_vertex)
        path_vertex = visited[path_vertex]
    print('Search path found:', end=' ')
    # The path is reversed and starts with the root vertex.
    print(*reversed(path), sep=' -> ')
# Otherwise...
else:
    print('\nEntity is not found') 
</pre>



<p>The test run gave us the output:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Visiting/queueing vertex (0, 0)
Prioritized vertices (v, cost, dir): ((0, 0), 0, None)

Exploring vertex (0, 0)
Visiting/queueing vertex (1, 1)
Prioritized vertices (v, cost, dir): ((1, 1), 42, 7)

Exploring vertex (1, 1)
Visiting/queueing vertex (2, 1)
Prioritized vertices (v, cost, dir): ((2, 1), 49, 6)

Exploring vertex (2, 1)
Visiting/queueing vertex (3, 2)
Prioritized vertices (v, cost, dir): ((3, 2), 53, 7)

Exploring vertex (3, 2)
Visiting/queueing vertex (2, 3)
Visiting/queueing vertex (4, 3)
Prioritized vertices (v, cost, dir): ((2, 3), 53, 1) ((4, 3), 57, 7)

Exploring vertex (2, 3)
Visiting/queueing vertex (1, 3)
Prioritized vertices (v, cost, dir): ((1, 3), 56, 2) ((4, 3), 57, 7)

Exploring vertex (1, 3)
Visiting/queueing vertex (0, 4)
Prioritized vertices (v, cost, dir): ((4, 3), 57, 7) ((0, 4), 60, 1)

Exploring vertex (4, 3)
Visiting/queueing vertex (4, 4)
Visiting/queueing vertex (5, 4)
Prioritized vertices (v, cost, dir): ((4, 4), 57, 0) ((5, 4), 61, 7) ((0, 4), 60, 1)

Exploring vertex (4, 4)
Visiting/queueing vertex (3, 5)
Prioritized vertices (v, cost, dir): ((3, 5), 57, 1) ((5, 4), 61, 7) ((0, 4), 60, 1)

Exploring vertex (3, 5)
Visiting/queueing vertex (2, 5)
Prioritized vertices (v, cost, dir): ((2, 5), 60, 2) ((5, 4), 61, 7) ((0, 4), 60, 1)

Exploring vertex (2, 5)
Visiting/queueing vertex (1, 5)
Visiting/queueing vertex (1, 6)
Prioritized vertices (v, cost, dir): ((1, 6), 60, 1) ((0, 4), 60, 1) ((5, 4), 61, 7) ((1, 5), 63, 2)

Exploring vertex (1, 6)
Visiting/queueing vertex (1, 8)
Visiting/queueing vertex (2, 7)
Prioritized vertices (v, cost, dir): ((0, 4), 60, 1) ((1, 8), 60, 0) ((5, 4), 61, 7) ((2, 7), 64, 7) ((1, 5), 63, 2

Exploring vertex (0, 4)
Prioritized vertices (v, cost, dir): ((1, 5), 60, 7) ((1, 8), 60, 0) ((5, 4), 61, 7) ((2, 7), 64, 7)

Exploring vertex (1, 5)
Prioritized vertices (v, cost, dir): ((1, 8), 60, 0) ((2, 7), 64, 7) ((5, 4), 61, 7)

Exploring vertex (1, 8)
Search path found: (0, 0) -> (1, 1) -> (2, 1) -> (3, 2) -> (4, 3) -> (4, 4) -> (3, 5) -> (2, 5) -> (1, 6) -> (1, 8)
</pre>



<h2 class="wp-block-heading">Efficiency Analysis</h2>



<p>The jump point search algorithm builds on the A* search algorithm, but when applied to uniform-cost search space, it can be up to an order of magnitude faster.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>In this article, we learned about the jump point search algorithm.</p>



<ul class="wp-block-list"><li>First, we explained what the jump point search algorithm is.</li><li>Second, we took a look at what are its common purposes and applications.</li><li>Third, we went through an explanation of how the algorithm works.</li><li>Fourth, we examined the algorithm&#8217;s main properties.</li><li>Fifth, we went through the implementation of the algorithm, which is based on the <code>Graph</code><em> </em>abstract data structure (<code>Graph</code> class implementation is given above). We also tested the algorithm by calling its main function, <code>jps()</code>, and analyzed its steps of execution for two slightly different edge weight scenarios.</li><li>Sixth, we analyzed the algorithm efficiency.</li></ul>



<p>In the end, we concluded that the algorithm efficiency is optimal and much faster than the original A* search algorithm, and if the solution exists, the jump point search algorithm will always find it in its optimal form and with optimal efficiency. </p>



<p>The algorithm always takes finite time in reaching the solution and is driven by the edges&#8217; weights, edges&#8217; directions, vertices&#8217; heuristic function, and the uniformity of the graph structure.</p>






<h2 class="wp-block-heading">Academy Course &#8211; Mastering the Top 10 Graph Algorithms</h2>



<p>If you want to improve your fundamental computer science skills, there&#8217;s nothing more effective than <strong>studying algorithms</strong>. </p>



<p>To help you master the <strong>most important graph algorithms</strong>, we&#8217;ve just launched the &#8220;Top 10 Algorithms&#8221; course at the <a rel="noreferrer noopener" href="https://academy.finxter.com/university/graph-algorithms-in-python/" data-type="URL" data-id="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank">Finxter Computer Science Academy</a>. This great course from Finxter Star Creator Matija <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> teaches you the most important graph algorithms such as BFS, DFS, A*, and Dijkstra. </p>



<p>Understanding these algorithms will not only make you a better coder, but it&#8217;ll also lay a strong foundation on which you can build your whole career as a computer scientist.</p>



<p>Click the screenshot to find out more:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><a href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="363" height="650" src="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png" alt="" class="wp-image-246565" srcset="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png 363w, https://blog.finxter.com/wp-content/uploads/2022/03/image-141-168x300.png 168w" sizes="auto, (max-width: 363px) 100vw, 363px" /></a></figure></div>



<div class="wp-block-buttons alignwide is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-50"><a class="wp-block-button__link" href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noreferrer noopener">Learn More</a></div>
</div>



<p></p>
<p>The post <a href="https://blog.finxter.com/jump-search-algorithm-in-python-a-helpful-guide-with-video/">Jump Search Algorithm in Python &#8211; A Helpful Guide with Video</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Visualize Data in Python &#8212; Graphviz, ImageDraw, and Turtle</title>
		<link>https://blog.finxter.com/how-to-visualize-data-to-a-diagram/</link>
		
		<dc:creator><![CDATA[Mohamed Thoufeeq Rahman]]></dc:creator>
		<pubDate>Sun, 26 Dec 2021 08:27:53 +0000</pubDate>
				<category><![CDATA[Data Visualization]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=104368</guid>

					<description><![CDATA[<p>“Numbers have an important story to tell. They rely on you to give them a clear and convincing voice.” ― Stephen Few “Visualizations act as a campfire around which we gather to tell stories.” ― Al Shalloway “The goal is to turn data into information and information into insight.” ― Carly Fiorina These quotes are ... <a title="How to Visualize Data in Python &#8212; Graphviz, ImageDraw, and Turtle" class="read-more" href="https://blog.finxter.com/how-to-visualize-data-to-a-diagram/" aria-label="Read more about How to Visualize Data in Python &#8212; Graphviz, ImageDraw, and Turtle">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/how-to-visualize-data-to-a-diagram/">How to Visualize Data in Python &#8212; Graphviz, ImageDraw, and Turtle</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<ul class="wp-block-list"><li><em>“Numbers have an important story to tell. They rely on you to give them a clear and convincing voice.”</em> ― <strong>Stephen Few</strong></li><li><em>“Visualizations act as a campfire around which we gather to tell stories.”</em> ― <strong>Al Shalloway</strong></li><li><em>“The goal is to turn data into information and information into insight.”</em> ― <strong>Carly Fiorina</strong></li></ul>



<p>These quotes are from&nbsp; Data Visualization experts showing the benefits of Visualizing Data. This short article will discover how to visualize data into a diagram using Python.</p>



<p>You will educate yourself about the importance of data visualization at the start, then examine the three powerful Python libraries to employ for drawing a diagram, and finally dive into an example on financial data visualization.&nbsp;</p>



<h2 class="wp-block-heading">Visualization Explained&nbsp;</h2>



<p>Extracting information from the raw data is challenging, and also you can’t identify patterns or trends. Our brain makes us understand pictures much faster than numbers.&nbsp; We can create graphs and diagrams to understand the data much better. We can find a story hidden under your raw data with powerful graphical tools<em>.</em>&nbsp; You can understand what this means by an example.</p>



<p>Suppose you started a candy bar manufacturing unit last year and sold various energy bars for the year 2021. In H1 of the year 2021, you have introduced new products, <strong>Cinnamon Energy Bar</strong> and <strong>Berry Energy Bar</strong>. </p>



<p>The table below shows the products sales data for 2021 to analyze the performance.</p>



<div class="wp-block-image"><figure class="aligncenter"><img decoding="async" src="https://lh3.googleusercontent.com/ye3eJDCAVgXdCaYBQHBWKSyYqxgWbVKSmKWDcaTZAmE2QPqZZW2Jmn0KAZbvUqdLrIaz-0HVRqHgvnCX29V7TYR-Fa2TYb6sT5yoPndKg-fKvYopjzIuCmT-6ZyRgPn5mXeU6Wu2" alt=""/><figcaption><em>Image 1.&nbsp;</em></figcaption></figure></div>



<p>From the data given above, you can see that <strong>Choco Energy Bar</strong> sold more than other candy bars, i.e., worth USD 1,174,905. The sales were low for <strong>Berry Energy Bar</strong>, i.e., USD 181,804. </p>



<p>But with this information is not enough to decide products performance. We can’t identify any trends from the given table of data. You can see the patterns or trends with a graphical tool like a histogram chart.</p>



<div class="wp-block-image"><figure class="aligncenter"><img decoding="async" src="https://lh6.googleusercontent.com/o0d-GglPE5dkEE3u3zhriPNroriMpGcwNg0jEci4chH1UFf7uGHctDnLMIlvRRX0AySdaSykGSmtgA1fhTcnLDxMMntAev-pyAp-004MiNIT2B2suVFYUQiuo3irqizUjAgzW4Ed" alt="" title="Product Wise Sales for the Year 2021"/><figcaption><em>Image 2.&nbsp;</em></figcaption></figure></div>



<p></p>



<p>Image 2 shows the graph from the above data. In this graph, the x-axis is Month, and the y-axis shows the percentage of total sales. The products represent in different colors. You can see that the Green color indicates <strong>Berry Energy Bar (BEB)</strong>, the Yellow color represents <strong>Cinnamon Energy Bar (CEB)</strong>, and likewise. Refer to the Legend above the bars.&nbsp;</p>



<p>You can extract the following information from this graph.</p>



<ul class="wp-block-list"><li>During the months between Jan &#8211; Mar, as <strong>Choco Energy Bar (HEB)</strong> sales increase, the <strong>Apple Energy Bar (AEB)</strong> decreases. Both products are inversely related.</li><li>The introduction of CEB in June has led HEB sales to reduce.</li><li>Also, we can see sales of CEB reduce the other two products.</li><li>The sales were high for HEB.</li><li>The sales were low for&nbsp; AEB.</li></ul>



<p>From the graph, you can see that we can derive more information such as above, which helps to understand the data and derive patterns easier than raw data.</p>



<p>The above example is a hypothetical case. But in real-time, we can give reasoning behind these patterns. Now let us look at how to visualize qualitative data.&nbsp;</p>



<h2 class="wp-block-heading">User Requirement</h2>



<p>We will learn about the OSEMN data science process.</p>



<ul class="wp-block-list"><li>O stands for Obtain. The first process is to extract data from various sources such as Databases, the internet, or surveys.</li><li>S stands for Scrub. Next, data must be cleaned from error and deal with missing values.</li><li>E stands for Explore. After the data cleansing, analyze the data using statistics and visualization tools.&nbsp;</li><li>M stands for Model. Create Machine Learning models for forecasting and predicting the data.</li><li>N Stands for INterpret. Finally, draw a meaningful conclusion based on the presented data to make decisions.</li></ul>



<p>Now we have to create this Process into a Diagram that makes others understand well and brings clarity.&nbsp;&nbsp;</p>



<p>It is possible to create diagrams using the powerful language Python. We will show you three techniques to draw a diagram.</p>



<h2 class="wp-block-heading">Technique 1: Graphviz</h2>



<p>In this First Technique, employ the Graphviz Python module to create Diagrams. Let’s learn about Graphviz before starting coding.</p>



<p>AT&amp;T Labs Research team discovered this powerful package Graphviz. Graphviz is an open-source graphical visualization software to draw directed and undirected graphs. This software was created with the <a href="https://en.m.wikipedia.org/wiki/DOT_(graph_description_language)" target="_blank" rel="noreferrer noopener">DOT language</a> script and has filename extension “<code>gv</code>”.</p>



<p>Graphviz has different polygon-based shapes, such as box, polygon, ellipse, etc.&nbsp; Also, numerous Arrow shapes are available to draw a diagram. You can save the graphs in the following formats: BMP, JPEG, JSON, PDF, PNG. The industry, such as Software engineering, Database, web design, machine learning, and others, use the Graphiz software widely.</p>



<p>Now let’s begin coding.</p>



<p>Firstly install the Graphviz module with the following command in the terminal :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">brew install graphviz
pip install graphviz</pre>



<p>After installing Graphviz, you have to import the Graphviz module as below.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import graphviz</pre>



<p>You can start drawing a diagram by creating a <code>Digraph</code> object. The Digraph is a directed graph that stores node and edges, and the source code is in the DoT programming language.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">graph = graphviz.Digraph('OSEMN', comment='Data Science Process - OSEMN FrameWork')</pre>



<p>The above code creates an ‘OSEMN’ graph using a Diagraph object. The comment displays when you run digraph source code.</p>



<p>Next, create a circle shape node to show data science process headings.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">graph.node('o', 'OBTAIN',height="3",fontsize="35pt")
graph.node('s', 'SCRUB',height="3",fontsize="35pt")
graph.node('e', 'EXPLORE',height="3",fontsize="35pt")
graph.node('m', 'MODEL',height="3",fontsize="35pt")
graph.node('i', 'INTERPRET',height="3",fontsize="35pt")</pre>



<p>The above code adds the node to the graph object using the <code>node()</code> method.&nbsp;</p>



<p>The ‘o&#8217; node label is for ‘Obtain’ with a height of 1.5 cm and a font size of 35 points.&nbsp;</p>



<p>The next node is ‘s’ with the label ‘Scrub’ with a height of 1.5 cm and font size of 35 points.  Node for ‘e,’ ‘m’, and ‘i’ are labeled. There are attributes such as <code>fillcolor</code>, <code>fontname</code>, <code>fontsize</code>, <code>image</code>, <code>imagepos</code>, <code>imagescale</code>, and more.</p>



<p>Now create nodes for a short explanation of the data process headings.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">graph.node('1', 'Extract Data from Database,Internet &amp; Survey', fontsize="30pt",height="2")
graph.node('2', 'Clean the Data from error &amp; handle missing data',fontsize="30pt",height="2")
graph.node('3', 'Analyse the Data using descriptive statistics and data visualizations',fontsize="30pt", height="2")
graph.node('4', 'Construct ML Models to predict and forecast',fontsize="30pt",height="2")
graph.node('5', 'Draw Meaningful conclution from the presented data',fontsize="30pt",height="2")</pre>



<p>Create a node in numbers for each explanation. “1” is for &#8216;Extract Data from Database, Internet &amp; Survey.’ “2” is for &#8216;Clean the Data from error &amp; handle missing data&#8217; and so on. Also, you can set different attributes as well.</p>



<p>After this, you need to connect the nodes Headings and Explanation. The <code>edge</code> method can connect between the nodes.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">graph.edge('o','s',constraint = 'false', arrowhead = 'diamond', arrowsize="2")
graph.edge('s','e',constraint = 'false', arrowhead = 'diamond',arrowsize="2")
graph.edge('e','m',constraint = 'false', arrowhead = 'diamond',arrowsize="2")
graph.edge('m','i',constraint = 'false', arrowhead = 'diamond',arrowsize="2")
</pre>



<p>First, connect the OSEM process through the <code>edge</code> method. Connect the edge between o and s, then s and e, and so on. </p>



<p>The <code>constraint =‘false’</code> attribute makes the node connected in the horizontal direction. The default direction of the edge is vertical. </p>



<p>The arrowhead’s shape is diamond, and its size is 2, as shown above in the code. There are different arrowhead shapes such as <code>box</code>, <code>crow</code>, <code>curve</code>, <code>dot</code>, <code>inv</code>, and more. </p>



<p>Attributes for edges are also available like <code>arrowhead</code>, <code>arrowsize</code>, <code>arrowtail</code>, <code>color</code>, <code>decorate</code>, and more.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">graph.edges(['o1','s2','e3','m4','i5'])</pre>



<p>The code above connects edges o and 1, s and 2. We use the <code>edges</code> method to join more nodes.  </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">print(graph.source)</pre>



<p>This command <a href="https://blog.finxter.com/python-print/" data-type="post" data-id="20731" target="_blank" rel="noreferrer noopener">prints</a> the source code in DOT language. Refer to image 4.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">graph.render(directory='doctest-output', view=True)</pre>



<p>Code will save the diagram output in the directory ‘&#8217;<code>doctest-output</code>&#8216;. The <code>view=True</code> attribute automatically opens the pdf file without searching for it. Refer to image 3.</p>



<p><strong>Output:</strong></p>



<div class="wp-block-image"><figure class="aligncenter"><img decoding="async" src="https://lh5.googleusercontent.com/z72n0C8cP0bhcazQC9Kyx9szKRQOl9r_3Occxwn9EqgRcnLpYxYjhoTKFB6K416CnHiXLdh9gk7LjWV7h6VkTLIEWQwXqEknATfq3fTzTYgVvGiUCmCG2MeWTRFJ07i22DYEs25K" alt=""/><figcaption><em>Image 3.&nbsp;</em></figcaption></figure></div>



<p></p>



<div class="wp-block-image"><figure class="aligncenter"><img decoding="async" src="https://lh4.googleusercontent.com/zNsdKpR-5smwGi3R2Hu402q_ouI43SZSRuOiuhzjGbC9gRxkSJhEnIgCIN3m8jG8dlAP2766QKr9X4EWZyPUPtquv6YIkV53s4OA3QITKaokT1L88t-5kFrb4okPvte2zAQCCyrv" alt=""/><figcaption><em>Image 4.&nbsp;</em></figcaption></figure></div>



<p></p>



<h2 class="wp-block-heading">Technique 2: Pillow ImageDraw</h2>



<p>Technique 2 employs <code>ImageDraw</code> from the <code><a href="https://blog.finxter.com/how-to-install-pillow-in-python/" data-type="post" data-id="35928" target="_blank" rel="noreferrer noopener">pillow</a></code> module to draw a diagram. Let’s learn about Pillow.</p>



<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Alex Clark and Contributors are the ones who produce the Pillow Library from the PIL module. The PIL is the Python Imaging Library for creating and manipulating images produced by Fredrik Lundh and Contributors. The programmer uses PIL for advanced image processing such as editing images, creating new images, creating thumbnails, etc. But the PIL was discontinued in 2011 and replaced Pillow for future usage. It supports all the image formats such as BMP, PNG, JPEG, and TIFF.</p>



<p><code>ImageDraw</code> module generates 2D Graphics from the image.&nbsp; It creates an object to draw in a given image. In other words, it makes a drawing board and inserts an image into the board for further editing. </p>



<p><code>ImageDraw</code> has drawing methods such as&nbsp;</p>



<ul class="wp-block-list"><li><code>ImageDraw.rectangle</code> &#8211; to draw a rectangle on the image</li><li><code>ImageDraw.ellipse</code> &#8211; to draw a circle on image</li><li><code>ImageDraw.line</code> &#8211; to draw a line on the image</li></ul>



<p>Now let’s begin coding.</p>



<p><a href="https://blog.finxter.com/how-to-install-pillow-on-pycharm/" data-type="post" data-id="35148" target="_blank" rel="noreferrer noopener">Install the pillow library</a> as below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pip install Pillow</pre>



<p>Next, import the pillow library of <code>Image</code>, <code>ImageDraw</code> and <code>ImageFont</code> modules.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from PIL import Image, ImageDraw, ImageFont</pre>



<p>Before moving on, let’s examine the syntax for the <code>ImageDraw</code> module.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">PIL.ImageDraw.Draw(im, mode=None)</pre>



<ul class="wp-block-list"><li><code>PIL</code> is the Pillow Module.</li><li><code>ImageDraw.Draw</code> method is employed to draw an object in the image.</li><li><code>im</code> is the image to edit.</li><li><code>mode</code> is for the RGB color of the image. </li></ul>



<p>After Import, you have to create a new image for drawing the OSEMN diagram.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">im = Image.new('RGB', (1750, 520), (255, 255, 255))</pre>



<p>The Image. new creates a new image with 1750 x 520 pixels and white color. The RGB color for white is 255, 255,255 and stored in the variable <code>im</code>.</p>



<p>Employ <code>ImageDraw</code> method as below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">draw = ImageDraw.Draw(im)</pre>



<p>Draw five ovals shape for the data process headings.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">draw.ellipse((50, 120, 300, 200), fill=(255, 255, 255), outline=(0, 0, 0))
draw.ellipse((400, 120, 650, 200), fill=(255, 255, 255), outline=(0, 0, 0))
draw.ellipse((750, 120, 1000, 200), fill=(255, 255, 255), outline=(0, 0, 0))
draw.ellipse((1100, 120, 1350, 200), fill=(255, 255, 255), outline=(0, 0, 0))
draw.ellipse((1450, 120, 1700, 200), fill=(255, 255, 255), outline=(0, 0, 0))
</pre>



<p>draw.e<code>llipse</code> method is to draw a circle object.</p>



<p>The four numbers in a <a rel="noreferrer noopener" href="https://blog.finxter.com/the-ultimate-guide-to-python-tuples/" data-type="post" data-id="12043" target="_blank">tuple</a> are the location of the object. The x0 (50) is the starting point of the location in a horizontal direction; then, the ending point is x1(300). The y0 (120) is the starting point of the location in a vertical direction, and then the ending point is y1(200). Refer to the image for a clear understanding.</p>



<p></p>



<p class="has-text-align-center"><img loading="lazy" decoding="async" width="624" height="468" src="https://lh3.googleusercontent.com/gF9KHeXS5uU6D8QqovO1yy-3C0G9proSKJOgMbFZExQaZO36-oOKA4QvlXttiPMAZuaOlch7htHO6LZNCwLDVlOh-pjnBYA2QZzyNORRZl3djc2yt6oFDDb80a0enC0yktiWmXnT"></p>



<p></p>



<p>The attribute ‘<code>fill</code>’ fills the color inside the object, i.e., the circle here is white. The value is to be given by RGB code.</p>



<p>The outline is the color for the object&#8217;s border, which is black, and the RGB of it is 0,0,0.</p>



<p>Similarly, you have to do for the other circle object with respective locations as shown in through code above.</p>



<p>Next, we need arrows to show the OSEM process in sequence. In the <code>ImageDraw</code> module, there is no arrow Shape object created like a rectangle or circle. So <code>ImageDraw.line</code> method is employed for drawing arrows.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">draw.line((301, 160, 399, 160), fill=(0, 0, 0), width=2) # Code 1
draw.line((393, 150, 399, 160), fill=(0, 0, 0), width=2) # Code 2
draw.line((395, 170, 401, 160), fill=(0, 0, 0), width=2) # Code 3
draw.line((651, 160, 749, 160), fill=(0, 0, 0), width=2)
draw.line((743, 150, 749, 160), fill=(0, 0, 0), width=2)
draw.line((745, 170, 751, 160), fill=(0, 0, 0), width=2)
draw.line((1001, 160, 1099, 160), fill=(0, 0, 0), width=2)
draw.line((1093, 150, 1099, 160), fill=(0, 0, 0), width=2)
draw.line((1095, 170, 1101, 160), fill=(0, 0, 0), width=2)
draw.line((1351, 160, 1449, 160), fill=(0, 0, 0), width=2)
draw.line((1443, 150, 1449, 160), fill=(0, 0, 0), width=2)
draw.line((1445, 170, 1451, 160), fill=(0, 0, 0), width=2)
</pre>



<p>To create a single arrow you must write three lines of code as shown above.&nbsp;</p>



<ul class="wp-block-list"><li>The first code is for a straight line.&nbsp;</li><li>The second code is for the cross line below.&nbsp;</li><li>The third code is for the cross line above.&nbsp;</li></ul>



<p>Do these steps for other arrows too.</p>



<p>Create text for each box with <code>ImageDraw.Draw.text</code> method. But font type attribute is mandatory in this method. Identify the path where is your desired font in the system.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">size = ImageFont.truetype("/Users/mohamedthoufeeq/Downloads/bebas-neue/BebasNeue-Regular.ttf",35)</pre>



<p>Specify the font path and size in <code>ImageFont.truetype</code> methods, then store it into variable <code>size</code>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">draw.text((130, 140),"OBTAIN",(0, 0, 0),font=size)
draw.text((480, 140),"SCRUB",(0, 0, 0),font=size)
draw.text((830, 140),"EXPLORE",(0, 0, 0),font=size)
draw.text((1180, 140),"MODEL",(0, 0, 0),font=size)
draw.text((1520, 140),"INTERPRET",(0, 0, 0),font=size)
</pre>



<p>From the <code>text</code> method, You can specify the location of the text of Data Process Heading with x and y coordinates as shown in the code. </p>



<p>Next, we mention the headings with double-quote marks. The color of the font is black with RGB code 0,0,0. Mention the variable <code>size</code> in the font attribute. </p>



<p>Likewise, you can create a diagram for explanation of the headings as per the code below: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">draw.text((1520, 140),"INTERPRET",(0, 0, 0),font=size)
draw.line((175, 200, 175, 300), fill=(0, 0, 0), width=5)
draw.line((525, 200, 525, 300), fill=(0, 0, 0), width=5)
draw.line((875, 200, 875, 300), fill=(0, 0, 0), width=5)
draw.line((1225, 200, 1225, 300), fill=(0, 0, 0), width=5)
draw.line((1575, 200, 1575, 300), fill=(0, 0, 0), width=5)
draw.rectangle((50, 300, 300, 400), fill=(255, 255, 255), outline=(0, 0, 0))
draw.rectangle((400, 300, 650, 400), fill=(255, 255, 255), outline=(0, 0, 0))
draw.rectangle((750, 300, 1000, 400), fill=(255, 255, 255), outline=(0, 0, 0))
draw.rectangle((1100, 300, 1350, 400), fill=(255, 255, 255), outline=(0, 0, 0))
draw.rectangle((1450, 300, 1700, 400), fill=(255, 255, 255), outline=(0, 0, 0))




esize = ImageFont.truetype("/Users/mohamedthoufeeq/Downloads/bebas-neue/BebasNeue-Regular.ttf",20)
draw.text((60, 320),"Extract Data from Database,\nInternet &amp; Survey",(0, 0, 0),font=esize)
draw.text((410, 320),"Clean the Data from error\n&amp; handle missing data",(0, 0, 0),font=esize)
draw.text((790, 320),"Analyse the Data using\ndescriptive statistics\nand data visualizations",(0, 0, 0),font=esize)
draw.text((1110, 320),"Construct ML Models to\n predict and forecast",(0, 0, 0),font=esize)
draw.text((1460, 320),"Draw Meaningful conclusion\n from the presented data",(0, 0, 0),font=esize)
</pre>



<p>The explanations of each heading are in a rectangle-shaped diagram. Refer to above code.</p>



<p>Finally, save the output in a jpg file with 110% quality through the save function. Refer to the code below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">im.save('pillow_imagedraw.jpg', quality=110)</pre>



<p><strong>Output:</strong></p>



<div class="wp-block-image"><figure class="aligncenter"><img decoding="async" src="https://lh5.googleusercontent.com/TTlQOodYlD-Sdbq-rv_Rr_rtGPP0CLeUT1gZ0Ov4lc7GbRsFIAoIzNAUZNYQiPNXnEC0Oeah2G43ZfzBU11eRRvLD3XFbUoFd0FTJ_soxKd89_WtN3ljvlAJHPyd_7YeDEImCSws" alt=""/><figcaption><em>Image 5. </em></figcaption></figure></div>



<p></p>



<h2 class="wp-block-heading">Technique 3:  Turtle</h2>



<p>Turtle is another technique employed to draw a diagram. Let&#8217;s learn about it.</p>



<p>The <code>turtle</code> module is most suitable for beginners to Python.  This Python library enables users to create shapes, diagrams, and pictures from virtual drawing boards.</p>



<p class="has-base-background-color has-background"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>Info</strong>: The Turtle was initially developed with Logo programming Language by Wally Feurzeig, Seymour Papert, and Cynthia Solomon. This popular graphical package was designed for kids to introduce programming. It gives a great resource to learn python programming. Don&#8217;t get discouraged! Adults can use turtle also. As we mentioned above, the module helps new programmers to get a feel for the python programming language in a fun and interactive way. </p>



<p>On the virtual drawing board, you find a small triangle-shaped symbol which is a pen for drawing, and this pen is called <em>Turtle</em>.</p>



<p>Let&#8217;s start coding:</p>



<p>First, install the Turtle module.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pip install PythonTurtle </pre>



<p>Import the <code>turtle</code> module as below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import turtle</pre>



<p>The following code opens a new Python turtle window with a turtle icon:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">turtle.Screen()</pre>



<p>Set the turtle speed of 5 seconds and pen size of  1 pixel.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">turtle.speed(5)
turtle.pensize(1)</pre>



<p>Use the virtual pen to draw a diagram on the Python turtle window.</p>



<p>Before moving further to code, let us understand the turtle&#8217;s position.</p>



<div class="wp-block-image"><figure class="aligncenter"><img decoding="async" src="https://lh6.googleusercontent.com/L3T3ghewacZ3U6y4sHtTaHTB_nAVholsqm0Nm_EN3U4MWmB17PdTkv5QcvkunKLEzN4JcKXakCrI9U60Aiu4sYQvMIA5vhdEIqc5FSqQ4B6X37doepzXCUDscGmhOEkDxMtBSznT" alt=""/><figcaption><em>Image 6. </em></figcaption></figure></div>



<p></p>



<p>The screen has four divisions with x and y coordinates. The current location of the turtle is in (0,0) position. So to move to the top left, the coordinates have to be negative number x and positive number y, as shown in DIV 2. Refer to image 6 for positioning the turtle.</p>



<p>Initially, we will show you how to draw an oval, arrow, line, and rectangle shape, then show how to insert headings and explanations into the shapes.</p>



<p>Draw oval shapes for data process heading with code below:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pos = -300   # Code A
for n in range(5):  # Code B
    turtle.up() # Code C
    turtle.goto(pos,100) # Code D
    turtle.down() # Code E
    turtle.seth(-45) # Code F
    turtle.circle(50,90) # Code G
    turtle.circle(25,90) # Code H
    turtle.circle(50,90) # Code I
    turtle.circle(25,90) # Code J
    turtle.up() # Code K
    pos = pos + 120 # Code L
</pre>



<ul class="wp-block-list"><li><strong>Code A</strong>: Set the position as -300 for x coordinate and store it with variable <code>pos</code>.</li><li><strong>Code B</strong>:  Create <a rel="noreferrer noopener" href="https://blog.finxter.com/python-loops/" data-type="post" data-id="4596" target="_blank">for loop</a> to draw five oval-shaped diagrams.</li><li><strong>Code C</strong>:  The virtual pen was down when we created the window.  So raise the pen up using <code>up()</code> function.</li><li><strong>Code D</strong>: Make the <code>turtle(pen)</code> move to position -300x and 100y to top left using the <code>goto()</code> function on the window.</li><li><strong>Code E</strong>:  Put the virtual pen on the window with the <code>down()</code> function.</li><li><strong>Code F</strong>:  Set the direction of the <code>turtle(pen)</code> to -45 angle using <code>seth()</code> or <code>setheading()</code> function.</li><li><strong>Code G,H,I,J</strong>:  Draw oval shape diagram using <code>circle()</code> function with radius 50, 25 and extent 90. With circle radius 50 and extent 90  draws a half-circle.</li><li><strong>Code K</strong>: Raise the virtual pen up to  stop drawing</li><li><strong>Code L</strong>: Add position by 120 x for drawing next oval shape diagram.</li></ul>



<p>After this draw arrow shape connecting between the oval shape.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pos =-224 # Code M
for n in range(4): # Code N
    turtle.pensize(2) # Code O
    turtle.up() # Code P
    turtle.goto(pos,120) # Code Q
    turtle.down() # Code R
    turtle.seth(-45)  # Code S
    turtle.left(45) # Code T
    turtle.forward(41) # Code U
    turtle.left(150) # Code V
    turtle.forward(10) # Code W
    turtle.right(180) # Code X
    turtle.forward(10) # Code Y
    turtle.left(250) # Code Z
    turtle.forward(10) # Code AA
    turtle.up() # Code  BB
    pos = pos+120 # Code CC
</pre>



<ul class="wp-block-list"><li><strong>Code M</strong>:  Set the position as -224 for x coordinate and store it with variable <code>pos</code> for drawing arrows.</li><li><strong>Code N</strong>:  Create for loop to draw four arrows.</li><li><strong>Code O</strong>:  Increase the pen size to 2.</li><li><strong>Code P</strong>:  Raise the pen up.</li><li><strong>Code Q</strong>: Move the pen to the position at -224 x and 120 y coordinates.</li><li><strong>Code R</strong>: Lower the pen down.</li><li><strong>Code S</strong>: Set the pen direction to a -45 degree angle.</li><li><strong>Code T</strong>: Rotate the pen leftwards to a 45-degree angle anti-clockwise.</li><li><strong>Code U</strong>: Move the pen forward with a distance of 41 x from the present position using the <code>forward</code> function. The position is -224 + 41  =  -183 x. It draws a straight line from the middle of the oval shape.</li><li><strong>Code V</strong>: Rotate the pen to the left with a 150-degree angle for drawing above the cross line for the arrow.</li><li><strong>Code W</strong>: Move the pen forward with a distance of 10x from the present position. </li><li><strong>Code X</strong>: Rotate the pen to the right of 180 degrees clockwise to return to the current position.</li><li><strong>Code Y</strong>: Move the pen forward with a distance of 10x from the present position.</li><li><strong>Code Z</strong>:  Rotate the pen to the left with 250 degrees for drawing below the cross line for the arrow.</li><li><strong>Code AA</strong>: Move the pen forward with a distance of 10x from the present position.</li><li><strong>Code BB</strong>: Raise the pen up.</li><li><strong>Code CC</strong>: Add the position by 120 to draw the next arrow.</li></ul>



<p>Now with the following code, draw five straight lines from the oval.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pos = -265
for n in range(5):
    turtle.pensize(2)
    turtle.up()
    turtle.goto(pos,85)
    turtle.down()
    turtle.seth(220)
    turtle.left(50)
    turtle.forward(30)
    pos = pos+120</pre>



<p>Draw 5 Rectangle shape diagrams for explanation of Headings with below code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">pos = -220 # Code DD
for n in range(5): # Code EE
    turtle.pensize(1) # Code FF
    turtle.penup() # Code GG
    turtle.goto(pos,55) # Code HH
    turtle.pendown() # Code II
    turtle.color('black') # Code JJ
    # draw sides for the rectangle
    for side in range(2): # Code KK
        turtle.forward(50)# Code LL
        turtle.right(90) # Code MM
        turtle.forward(100)# Code NN
        turtle.right(90) # Code OO
    pos = pos+120   # Code PP
</pre>



<ul class="wp-block-list"><li><strong>Code HH</strong>: Move the pen downwards to draw a rectangle.</li><li><strong>Code LL to Code OO</strong>: Draws two sides of the rectangle.</li><li><strong>Code KK</strong>: Create for loops to draw four sides of the rectangle.</li></ul>



<p>Next let us write the text for Headings and explanation with below code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">turtle.up()
turtle.goto(-290,100)
turtle.write("OBTAIN", font=("Verdana",12, "normal"))
turtle.up()
turtle.goto(-170,100)
turtle.write("SCRUB", font=("Verdana",12, "normal"))
turtle.up()
turtle.goto(-50,100)
turtle.write("EXPLORE", font=("Verdana",12, "normal"))
turtle.up()
turtle.goto(70,100)
turtle.write("MODEL", font=("Verdana",12, "normal"))
turtle.up()
turtle.goto(190,100)
turtle.write("INTERPRET", font=("Verdana",12, "normal"))
turtle.up()
turtle.goto(-305,20)
turtle.write("Extract Data from\n Database,\nInternet &amp; Survey", font=("Verdana",8, "normal"))
turtle.up()
turtle.goto(-195,20)
turtle.write("Clean the Data from \nerror &amp; handle \nmissing data", font=("Verdana",8, "normal"))
turtle.up()
turtle.goto(-75,20)
turtle.write("Analyse the Data using\ndescriptive statistics\nand data visualizations", font=("Verdana",8, "normal"))
turtle.up()
turtle.goto(45,20)
turtle.write("Construct ML Models to\n predict and forecast", font=("Verdana",8, "normal"))
turtle.up()
turtle.goto(165,20)
turtle.write("Draw Meaningful \nconclusion from the \npresented data", font=("Verdana",8, "normal"))
turtle.up()
</pre>



<p>Hide the turtle symbol or pen with the following command.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">turtle.ht()</pre>



<p>Use <code>turtle.write</code> a function to write the text in the desired locations with the pen.</p>



<p>You are not required to lower the pen because <code>turtle.write</code> makes pen down for writing text.</p>



<p>Here write the Data process heading and Explanation.</p>



<p><strong>Finally, see the output:</strong></p>



<div class="wp-block-image"><figure class="aligncenter"><img decoding="async" src="https://lh5.googleusercontent.com/AAiZC07Fgawo50-7Debb5GLapwnAf6ACDAxZznYcmYeF40brHS316x5ORuJxX7Lv0ojCee1BsSMJ-EbkhMU1KrXG33yJqEViuzdMukwbResp-O6PRcePAFu2710vaPNfrN6UjK4j" alt=""/><figcaption><em>Image 7. </em></figcaption></figure></div>



<p></p>



<h2 class="wp-block-heading">Bonus: Visualize Financial Data of Apple.com</h2>



<p>Let us draw the diagram for Financial Statement for Apple during the Fourth Quarter of 2021</p>



<div class="wp-block-image"><figure class="aligncenter"><img decoding="async" src="https://lh6.googleusercontent.com/0FunLGx-R8jb8iX4sasFaAwqIMGUoWkXKvxfAKUTOgb8kjpgmd_bdRjNdbVUMdJ3KiC_mOMbb3sVY3JPzRLDvIM2OjMj0JkSqKDr0XxN0gXso_SWudS9dWzWd0-cMC5uX0OxvITc" alt=""/><figcaption><em>Image 8. </em></figcaption></figure></div>



<p></p>



<p>The above Financial Statements make it harder for you to grasp the essential indicators of the company. So we will draw diagrams to understand the company&#8217;s performance more effortlessly.</p>



<p>Here we will use the Graphviz Python library to draw diagrams.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import graphviz
graph = graphviz.Digraph("Apple's Income Statement Diagram", comment='Diagram for Analysis')  
graph.node('ns', 'Net SALES:US$83,360',fontsize="20pt")
graph.node('p', 'Product:US$65,083',fontsize="20pt")
graph.node('ip', 'Iphone:US$38,868',fontsize="5pt")
graph.node('mac', 'Mac:US$9,178',fontsize="5pt")
graph.node('ipad', 'iPad:US$8,252',fontsize="5pt")
graph.node('wr', 'Wearables, Home and Accessories:US$8,785',fontsize="5pt")
graph.node('s', 'Services:US$18,277',fontsize="20pt")
graph.node('pc', 'Cost of Sales:US$42,790',fontsize="10pt")
graph.node('sc', 'Cost of Sales:US$5,396',fontsize="10pt")
graph.node('gm', 'Gross Margin:US$35,174',fontsize="20pt")
graph.node('rd', 'Research and development:US$5,772',fontsize="10pt")
graph.node('sga', 'Selling, general and administrative:US$5,616',fontsize="10pt")
graph.node('op', 'Operating income:US$23,786',fontsize="10pt")
graph.node('oe', 'Other Expenses:US$538',fontsize="10pt")
graph.node('i', 'Income before provision for income taxes:US$23,248',fontsize="10pt")
graph.node('it', 'Provision for income taxes:US$2,697',fontsize="10pt")
graph.node('np', 'Net income:US$20,551',fontsize="10pt")
graph.edge('ns','p')
graph.edge('p','ip')
graph.edge('p','mac')
graph.edge('p','ipad')
graph.edge('p','wr')
graph.edge('ns','s')
graph.edge('p','pc')
graph.edge('s','sc')
graph.edge('pc','gm')
graph.edge('sc','gm')
graph.edge('gm','rd')
graph.edge('gm','sga')
graph.edge('rd','op')
graph.edge('sga','op')
graph.edge('op','oe')
graph.edge('oe','i')
graph.edge('i','it')
graph.edge('it','np')
print(graph.source)
graph.render(directory='doctest-output', view=True)
</pre>



<p><strong>Output:</strong></p>



<div class="wp-block-image"><figure class="aligncenter"><img decoding="async" src="https://lh5.googleusercontent.com/znvbypUuvw0_XJg2rrvh-aBxoBjVwH1wrX_6lCI499tLdFTptcxCcMeajm_m_e8yXPzEpfTeytyO0spGEr_AUi_Yf4gheQZOmhFlbCIbCNdo3nmydIL6C6wnYOnuKz7I1O4wdC9B" alt=""/><figcaption><em>Image 9. </em></figcaption></figure></div>



<p></p>



<h2 class="wp-block-heading">Summary</h2>



<p>Human brains extrapolate pictures more quickly than words and numbers.</p>



<p>Number and words have information buried. We can’t discover the patterns interpret the data, and draw conclusions by just reading the numbers and words. </p>



<p>With visual representation tools such as diagrams, graphs, etc., we can understand the data quickly and clearly. You have learned in this article how to draw a diagram with powerful python libraries. </p>



<p>These libraries are Graphviz, ImageDraw, and turtle. </p>



<p>For drawing complex diagrams without any images, Graphviz is a better choice. If you need to edit images and use them in a diagram, the ImageDraw library is better. As we know, The Software Scientist created the turtle for kids to learn python programming language. </p>



<p>Beginners can use Turtle for educational purposes and also for creating animated stories. Story with animated diagrams and words are more potent for the reader to understand well. </p>



<p>Hope this article helped you and answered your query. Give your feedback at <a rel="noreferrer noopener" href="mailto:thoufeeq87.mtr@gmail.com" target="_blank">thoufeeq87.mtr@gmail.com</a>.</p>



<p>Have a great coding!</p>



<p>The post <a href="https://blog.finxter.com/how-to-visualize-data-to-a-diagram/">How to Visualize Data in Python &#8212; Graphviz, ImageDraw, and Turtle</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Python A* &#8211; The Simple Guide to the A-Star Search Algorithm</title>
		<link>https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/</link>
		
		<dc:creator><![CDATA[Matija Horvat]]></dc:creator>
		<pubDate>Sat, 11 Dec 2021 18:00:20 +0000</pubDate>
				<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=81313</guid>

					<description><![CDATA[<p>This tutorial guides you into the fascinating A* (A-Star) using the Python programming language. First, feel free to watch the video guide&#8212;we&#8217;ll give a detailed textual explanation below. The slides can be found as a Gif here: Okay, so let&#8217;s dive into the algorithm motivation, explanation, and Python code next! What is the A* Search ... <a title="Python A* &#8211; The Simple Guide to the A-Star Search Algorithm" class="read-more" href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" aria-label="Read more about Python A* &#8211; The Simple Guide to the A-Star Search Algorithm">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/">Python A* &#8211; The Simple Guide to the A-Star Search Algorithm</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>This tutorial guides you into the fascinating A* (A-Star) using the Python programming language. First, feel free to watch the video guide&#8212;we&#8217;ll give a detailed textual explanation below. </p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Python A* - The Simple Guide to the A-Star Search Algorithm" width="937" height="527" src="https://www.youtube.com/embed/mGu-T8zH574?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>The slides can be found as a Gif here:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="853" height="480" src="https://blog.finxter.com/wp-content/uploads/2021/12/Python-blog-A_star-Algorithm.gif" alt="" class="wp-image-81347"/></figure></div>



<p>Okay, so let&#8217;s dive into the algorithm motivation, explanation, and Python code next!</p>



<h2 class="wp-block-heading">What is the A* Search algorithm?</h2>



<p>A very interesting graph traversal algorithm we will learn about next is the A* algorithm, constructed by the authors Peter Hart, Nils Nilsson, and Bertram Raphael. The A* algorithm belongs to the family of <a rel="noreferrer noopener" href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" data-type="post" data-id="68911" target="_blank">best-first search</a> algorithms and is an extension to the <a rel="noreferrer noopener" href="https://blog.finxter.com/python-dijkstra-algorithm/" data-type="post" data-id="72692" target="_blank">Dijkstra</a> algorithm in the sense that it takes into account both the weights of the graph edges and the heuristic functions of the connected vertices. It is suitable for application in various domains of computer science because of its three key properties: <em>completeness</em>, <em>optimality,</em> and <em>optimal efficiency</em>.</p>



<p>Before we&#8217;ll dive into the algorithm and the Python implementation, let&#8217;s first skim over some related graph tutorials you may enjoy and that may help your understanding!</p>



<h2 class="wp-block-heading" id="related-graph-tutorials">Related Graph Tutorials</h2>



<p>This algorithm is part of our graph algorithm tutorials:</p>



<ul class="wp-block-list"><li><a rel="noreferrer noopener" href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" target="_blank">Breadth-First Search (BFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-depth-first-search-dfs-algorithm/" target="_blank">Python Depth-First Search (DFS) Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/iterative-deepening-depth-first-search-dfs-algorithm-in-python/" target="_blank">Iterative Deepening Depth-First Search (DFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" target="_blank">Python Best-First Search Algorithm</a></li><li><a href="https://blog.finxter.com/python-dijkstra-algorithm/">Python Dijkstra Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" target="_blank">Python A* Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/jump-search-algorithm-in-python-a-helpful-guide-with-video/" target="_blank">Jump Search Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-backtracking-a-helpful-guide-with-video/" target="_blank">Python Backtracking</a></li><li><a href="https://blog.finxter.com/python-beam-search-algorithm/" data-type="post" data-id="204131">Python Beam Search Algorithm</a></li></ul>



<p>Each of these tutorial links opens in a new browser tab.</p>



<h2 class="wp-block-heading">What&#8217;s the Purpose of A* Search?</h2>



<p>Common applications of the <strong>A* algorithm</strong> are in domains of <strong>optimal pathfinding</strong> for various distribution networks. Some of the example usages are <strong>power-aware routing</strong> of messages in large <strong>communication networks</strong>, point-to-point <strong>path planning</strong> tasks, or finding the shortest path in <strong>games and web-based maps</strong>.</p>



<h2 class="wp-block-heading">How Does A* Search Work?</h2>



<p>The A* algorithm assigns a heuristic function to all the vertices. The heuristic function approximates a cost of reaching the goal vertex from a visited vertex in terms of e.g. (commonly Euclidean) distance or time. The total cost of any vertex is calculated as a <strong><em>sum of weights</em></strong> of the connecting edges between the starting vertex and the visited vertex, and the heuristic function of the visited vertex.</p>



<p>When visited, the cost of each unexplored, adjoining vertex is updated according to the weights associated with the connecting edges. After being visited, each adjoining vertex is added to the priority queue.</p>



<p>In each following iteration, the vertex with the lowest cost is taken out of the priority queue and its processing starts by visiting and conditionally updating all its adjoining (visited), non-explored vertices. The update operation implies two steps: lowering the cost of the visited node and associating with the processed (explored, the terms are used interchangeably) vertex for later reconstruction of the shortest path. Finally, the processed vertex is marked as explored and does not participate in any further cost calculations.</p>



<p>The update condition is determined by comparing each visited vertex&#8217;s current cost with its new,&nbsp; potentially lower cost. Its new cost is calculated in the following way: <em>current cost of the explored vertex &#8211; its heuristic function + the weight of the adjoining edge (the edge weight between the vertex being explored and the visited vertex) + the heuristic function of the visited vertex</em>.</p>



<p>If the current cost of the visited vertex is still lower than the potential new cost, the vertex cost will not be updated. Otherwise, the visited vertex will be updated to the new cost (its cost will decrease) and form an association with the explored vertex. Vertex cost reduction is also referred to as a <em>relaxation procedure</em>. After visiting and conditionally updating all the adjoining, non-explored vertices, the vertex being processed will be marked as explored and will not participate in any further algorithm calculations. The described process continues until there are no unexplored vertices left in the priority queue.</p>



<p>When the algorithm ends, all vertices are assigned with the lowest possible costs, and the traversal algorithm yields the shortest possible path between the starting and target vertices. For comparison with the previously described Dijkstra&#8217;s algorithm, the A* algorithm is superior given that it does not only follow the shortest path available (pure greedy approach) but is also guided by the notion of a right direction, contained in the heuristic function of each vertex.</p>



<h2 class="wp-block-heading">What Are the Properties of A* Search?</h2>



<p>The A* algorithm uses the exact information represented by the edge&#8217;s weights and a heuristic function for distance estimation between the goal vertex and other connected vertices in a graph. As the initial costs for all the non-starting vertices are set to infinity, the algorithm successively decreases vertices costs until they reach their minimum.</p>



<p>This behavior leads to a property of being <em>optimal</em>: minimal costs assigned to vertices enable the A* algorithm to always find the shortest path between the starting vertex and any other vertex in the graph. As the shortest paths always start from the starting vertex, the algorithm is attributed as the “single-source” algorithm.</p>



<p>Besides being optimal, the algorithm is also <em>complete</em>, i.e. it will always take a finite time to find a solution.</p>



<p>The third important property is the <em>optimal efficiency</em>, reflected in the fact that vertices positioned further from the target vertex may not be explored at all, as their heuristic function distinguishes and delays the exploration of such vertices among those with equally weighted paths.</p>



<p>The heuristic functions used in the A* algorithm also have two notable properties: <em><strong>admissibility</strong></em> and <em><strong>consistency</strong></em>. </p>



<ul class="wp-block-list"><li>Admissibility implies that the heuristic function cost estimation is at most as high as the lowest possible cost from the current point in a path towards the target vertex.</li><li>The consistent or monotone heuristic function is constrained by a requirement that its cost estimation is always less than or equal to the estimated distance from any adjoining, successor vertex to the goal, plus the cost of reaching that vertex.</li></ul>



<h2 class="wp-block-heading">How is A* Search Implemented in Python?</h2>



<p>The implementation of the A* algorithm is achieved by the function <code>a_star()</code> and a modification of the underlying class Graph.</p>



<p>The <code>a_star()</code> function takes three parameters: </p>



<ul class="wp-block-list"><li>The <code>graph</code> parameter takes an initialized Graph object (see the blog on the <em><a rel="noreferrer noopener" href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" data-type="post" data-id="36880" target="_blank">breadth-first search algorithm</a></em>, the section on <em><a rel="noreferrer noopener" href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/#How_is_a_Graph_Implemented" data-type="URL" data-id="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/#How_is_a_Graph_Implemented" target="_blank">graphs</a></em>). </li><li>The <code>start_vertex</code> parameter takes the starting vertex, which we choose freely (remember, a graph is not a tree, there is no absolute root). </li><li>The <code>target</code> parameter is the entity we want to find in the graph, enclosed in a vertex.</li></ul>



<p>For a better understanding of the algorithm and its implementation, each step is precisely described in the code below.</p>



<p>There have been some further upgrades on the <code>Graph</code> class, so its entire listing follows:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="85-92" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Graph:

    def __init__(self, directed=False):
        self._outgoing = {}
        # If the graph is undirected, 'self._outgoing'
        # is the universal storage.
        self._incoming = {} if directed else self._outgoing

    # If the graph is directed, the 'self._incoming' 
    # dictionary differs from the 'self._outgoing'.
    def is_directed(self):
        return self._incoming is not self._outgoing

    # The function returns a generator of incoming
    # or outgoing (default) edges of a vertex.
    def adjacent_edges(self, vertex, outgoing=True):
        # References the corresponding outer dictionary
        # (dictionary of dictionaries)
        adj_edges = self._outgoing if outgoing else self._incoming

        # Access each of the edges for this endpoint vertex.
        for edge in adj_edges[vertex].values():
            yield edge

    def add_vertex(self, entity=None, h=None, cost=None):
        # Constructs a new vertex from the entity.
        vertex = self.Vertex(entity, h, cost)
        # The vertex becomes a key in the outer dictionary,
        # but the value is an internal dictionary (as we model
        # both dimensions for each edge: origin and destination).
        # e.g. {vertex_1a:{vertex_b:edge_a_b}, vertex_b:{vertex_c:edge_b_c}}.
        self._outgoing[vertex] = {}
        if self.is_directed():
            self._incoming[vertex] = {}

    def add_edge(self, origin, destination, weight=None):
        # Constructs a new edge from the vertices.
        edge = self.Edge(origin, destination, weight)
        # Adds the edge to the dictionary (dictionaries are
        # the same if the graph is undirected). The outer key
        # represents the origin, i.e. the component 'a' of
        # the edge-defining pair (a, b). The inner key stands
        # for the component 'b' of the edge-defining pair (a, b).
        self._outgoing[origin][destination] = edge
        # Even if the graph is undirected, each edge has to
        # be added twice, i.e. once for each of its endpoints.
        self._incoming[destination][origin] = edge

    def vertices(self):
        return self._outgoing.keys()

    def edges(self):
        # All the edges are collected into a set.
        result = set()
        for inner_dict in self._outgoing.values():
            result.update(inner_dict.values())
        return result

    class Vertex:
        __slots__ = '_entity', '_h', '_cost'

        def __init__(self, entity, h=None, cost=None):
            self.entity = entity
            self.h = h
            self.cost = cost

        # The real-world entity is represented by the Vertex object.
        @property
        def entity(self):
            return self._entity

        @entity.setter
        def entity(self, entity):
            self._entity = entity

        # The real-world entity has a heuristic value of 'h'.
        @property
        def h(self):
            return self._h

        @h.setter
        def h(self, h):
            self._h = h

        # The real-world entity has a cost of 'cost'.
        @property
        def cost(self):
            return self._cost

        @cost.setter
        def cost(self, cost):
            self._cost = cost

        # We have to implement __hash__ to use the object as a dictionary key.
        def __hash__(self):
            return hash(id(self))

        def __lt__(self, other):
            if self.cost is None:
                return False
            elif other.cost is None:
                return True
            else:
                return self.cost &lt; other.cost

    class Edge:
        __slots__ = '_origin', '_destination', '_weight'

        def __init__(self, origin, destination, weight=None):
            self._origin = origin
            self._destination = destination
            self.weight = weight

        def endpoints(self):
            return self._origin, self._destination

        # Returns the other component of the edge-defining pair (a, b)
        # for a given component a or b, respectively.
        def opposite(self, vertex):
            return self._destination if self._origin is vertex \
                else self._origin

        # Returns the weight of the edge.
        @property
        def weight(self):
            return self._weight

        # Sets the weight of the edge
        @weight.setter
        def weight(self, weight):
            self._weight = weight

        def __hash__(self):
            return hash((self._origin, self._destination))
</pre>



<p>The most significant differences to the previous version of the Graph class are <strong>highlighted in the code</strong>.</p>



<p>With these changes in place, implementation of the core function, <code>a_star()</code> is:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from graph import Graph
from queue import PriorityQueue


def a_star(graph, start_vertex, target):
    # Create the priority queue for open vertices.
    vertices_pq = PriorityQueue()

    start_vertex.cost = start_vertex.h

    # Adds the start vertex to the priority queue.
    print(f'Visiting/queueing vertex {start_vertex.entity}')
    vertices_pq.put(start_vertex)
    print('Prioritized vertices (v, cost(v)):',
          *((vert.entity, vert.cost) for vert in vertices_pq.queue), end=2 * '\n')

    # The starting vertex is visited first and has no leading edges.
    # If we did not put it into 'visited' in the first iteration,
    # it would end up in 'visited' during the second iteration, pointed to
    # by one of its children vertices as a previously unvisited vertex.
    visited[start_vertex] = None

    # Loops until the priority list gets empty.
    while not vertices_pq.empty():
        # Gets the vertex with the lowest cost.
        vertex = vertices_pq.get()
        # If the vertex being explored is a target vertex, ends the algorithm.
        print(f'Exploring vertex {vertex.entity}')
        if vertex.entity == target:
            return vertex
        # Examines each non-visited adjoining edge/vertex.
        for edge in graph.adjacent_edges(vertex):
            # Gets the second endpoint.
            v_2nd_endpoint = edge.opposite(vertex)

            # Skips the explored vertices.
            if v_2nd_endpoint in explored:
                continue

            # Checks if the endpoint has a weight and is the weight the cheapest one.
            if v_2nd_endpoint.cost is None \
                    or vertex.cost - vertex.h + edge.weight &lt; v_2nd_endpoint.cost - v_2nd_endpoint.h:
                # Adds the second endpoint to 'visited' and maps
                # the leading edge for the search path reconstruction.
                v_2nd_endpoint.cost = vertex.cost - vertex.h + edge.weight + v_2nd_endpoint.h
                # Prevents reinsertion to the priority queue. The
                # endpoint distance value will be updated.
                if v_2nd_endpoint not in visited:
                    print(f'Visiting/queueing vertex {v_2nd_endpoint.entity}')
                    vertices_pq.put(v_2nd_endpoint)
                # Forces the priority queue to recalculate in case of an
                # inner vertex update resulting with the highest priority
                vertices_pq.put(vertices_pq.get())
                # Replaces the previous vertex' ancestor with a cheaper one.
                visited[v_2nd_endpoint] = edge
        print('Prioritized vertices (v, cost(v)):',
              *((vert.entity, vert.cost) for vert in vertices_pq.queue), end=2 * '\n')
        # The vertex is used for update and put aside.
        explored.append(vertex)
    return None
</pre>



<p>Before we can test the algorithm, we have to initialize a graph and build it by adding vertices and edges to it:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Initializes an empty graph (object).
g = Graph()

# Loads the graph with the first seven vertices.
g.add_vertex(0, 4)
g.add_vertex(1, 4)
g.add_vertex(2, 2)
g.add_vertex(3, 7)
g.add_vertex(4, 5)
g.add_vertex(5, 10)
g.add_vertex(6, 0)

# Constructs the 'vertices' dictionary for a more
# convenient access during the graph construction.
vertices = {k.entity: k for k in g.vertices()}

# Constructs an arbitrary graph from
# the existing vertices and edges.
g.add_edge(vertices[0], vertices[1], 4)
g.add_edge(vertices[0], vertices[2], 2)
g.add_edge(vertices[2], vertices[4], 1)
g.add_edge(vertices[4], vertices[3], 3)
g.add_edge(vertices[3], vertices[5], 2)
g.add_edge(vertices[0], vertices[5], 4)
g.add_edge(vertices[2], vertices[6], 5)

# Initializes the search path and a dictionary of visited vertices.
path = []
explored = []
visited = {}
</pre>



<p>Now that we have prepared everything, we can test <code>a_star(</code>) and see how it works. Here is the part of the code that runs the algorithm, constructs the search path (if there is one), and shows in a step-by-step manner how it proceeds through the graph:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Starts the search.
result = a_star(g, vertices[5], 6)

# If the entity is found...
if result is not None:
    # The search path ends with the found vertex (entity).
    # Each vertex is a container for its real-world entity.
    path_vertex = result
    # The entity is added to the 'path'.
    path.append(path_vertex.entity)
    # Constructs the rest of the search path (if it exists)...
    while True:
        # Gets a discovery edge leading to the vertex.
        path_edge = visited.get(path_vertex)
        # If the path vertex is the root, it has no discovery edge...
        if path_edge is None:
            break
        # Otherwise, gets the second (parent vertex) endpoint.
        path_vertex = path_edge.opposite(path_vertex)
        # The entity is added to the 'path'.
        path.append(path_vertex.entity)
    print('Search path found:', end=' ')
    # The path is reversed and starts with the root vertex.
    print(*reversed(path), sep=' -> ')
# Otherwise...
else:
    print('\nEntity is not found')
</pre>



<p>The test run gave us the output:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Visiting/queueing vertex 5
Prioritized vertices (v, cost(v)): (5, 10)

Exploring vertex 5
Visiting/queueing vertex 3
Visiting/queueing vertex 0
Prioritized vertices (v, cost(v)): (0, 8) (3, 9)

Exploring vertex 0
Visiting/queueing vertex 1
Visiting/queueing vertex 2
Prioritized vertices (v, cost(v)): (2, 8) (1, 12) (3, 9)

Exploring vertex 2
Visiting/queueing vertex 4
Visiting/queueing vertex 6
Prioritized vertices (v, cost(v)): (3, 9) (6, 11) (1, 12) (4, 12)

Exploring vertex 3
Prioritized vertices (v, cost(v)): (4, 10) (1, 12) (6, 11)

Exploring vertex 4
Prioritized vertices (v, cost(v)): (6, 11) (1, 12)

Exploring vertex 6
Search path found: 5 -> 0 -> 2 -> 6
</pre>



<p>Based on the output, we can see that the search started from vertex 5 and that the <code>a_star()</code> has found the entity vertex 6. The entire search path is also displayed, and we should note that the search path will always be the shortest one: <code>5 -&gt; 0 -&gt; 2 -&gt; 6</code>. However, a modification of just one heuristic function value, effectively moving the vertex further away from the goal might lead to a different solution, as we will demonstrate with the next example. With that in mind, let us tweak the weight on one of our edges:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="2" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Loads the graph with the first seven vertices.
g.add_vertex(0, 6)
g.add_vertex(1, 4)
g.add_vertex(2, 2)
g.add_vertex(3, 7)
g.add_vertex(4, 5)
g.add_vertex(5, 10)
g.add_vertex(6, 0)
</pre>



<p>The re-run gave us the output:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Visiting/queueing vertex 5
Prioritized vertices (v, cost(v)): (5, 10)

Exploring vertex 5
Visiting/queueing vertex 3
Visiting/queueing vertex 0
Prioritized vertices (v, cost(v)): (3, 9) (0, 10)

Exploring vertex 3
Visiting/queueing vertex 4
Prioritized vertices (v, cost(v)): (4, 10) (0, 10)

Exploring vertex 4
Visiting/queueing vertex 2
Prioritized vertices (v, cost(v)): (2, 8) (0, 10)

Exploring vertex 2
Visiting/queueing vertex 6
Prioritized vertices (v, cost(v)): (0, 10) (6, 11)

Exploring vertex 0
Visiting/queueing vertex 1
Prioritized vertices (v, cost(v)): (6, 11) (1, 12)

Exploring vertex 6
Search path found: 5 -> 3 -> 4 -> 2 -> 6
</pre>



<p>After a re-run, we got a different solution only by changing one of our heuristic function values. Our simple demonstration just proved how important the heuristic function value, i.e. the quality distance estimation is.</p>



<h2 class="wp-block-heading">Efficiency Analysis</h2>



<p>The algorithm&#8217;s worst-case <strong>time complexity</strong> depends on the heuristic function. In the worst case, i.e. of unbounded search space, the time complexity degenerates to an exponential function <em>O(b<sup>d</sup>)</em>, where <em>b</em> is the branching factor (the average number of unexplored, adjoining vertices) and <em>d</em> stands for the depth of the shortest path to a solution.</p>



<p>The <strong>space complexity</strong> of the A* algorithm is <em>O(v+e)</em> in terms of vertices and edges since it keeps all generated vertices and edges in memory. Expressed in terms of a branching factor and the solution depth, the space complexity of the A* algorithm is <em>O(b<sup>d</sup>)</em>. High memory requirement renders the A* algorithm less suitable as the size and density of a graph increase, which is considered to be its significant disadvantage.</p>



<p>The A* algorithm is <strong><em>optimal</em></strong>, as it will always yield an optimal, shortest possible search path. Furthermore, the A* algorithm will always find a solution if there is one, so it is also <em><strong>complete</strong></em>. Finally, A* is <em><strong>optimally efficient</strong></em>, meaning it will explore as few vertices as possible.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>In this article, we learned about the A* search algorithm.</p>



<ul class="wp-block-list"><li>First, we explained what the A* algorithm is.</li><li>Second, we took a look at what are its common purposes and applications.</li><li>Third, we went through an explanation of how the algorithm works.</li><li>Fourth, we examined the algorithm&#8217;s main properties.</li><li>Fifth, we went through the implementation of the algorithm, which is based on the Graph<em> </em>abstract data structure (<code>Graph</code> class implementation is given above). We also tested the algorithm by calling its main function, <code>a_star()</code>, and analyzed its steps of execution for two slightly different edge weight scenarios.</li><li>Sixth, we analyzed the algorithm efficiency.</li></ul>



<p>In the end, we concluded that the algorithm efficiency is optimal, and if the solution exists, the A* algorithm will always find it in its optimal form and with optimal efficiency. The algorithm always takes finite time in reaching the solution and is driven by the edges&#8217; weights, vertices&#8217; heuristic function, and the graph structure.</p>



<h2 class="wp-block-heading">Academy Course &#8211; Mastering the Top 10 Graph Algorithms</h2>



<p>If you want to improve your fundamental computer science skills, there&#8217;s nothing more effective than <strong>studying algorithms</strong>. </p>



<p>To help you master the <strong>most important graph algorithms</strong>, we&#8217;ve just launched the &#8220;Top 10 Algorithms&#8221; course at the <a rel="noreferrer noopener" href="https://academy.finxter.com/university/graph-algorithms-in-python/" data-type="URL" data-id="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank">Finxter Computer Science Academy</a>. This great course from Finxter Star Creator Matija <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> teaches you the most important graph algorithms such as BFS, DFS, A*, and Dijkstra. </p>



<p>Understanding these algorithms will not only make you a better coder, but it&#8217;ll also lay a strong foundation on which you can build your whole career as a computer scientist.</p>



<p>Click the screenshot to find out more:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><a href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="363" height="650" src="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png" alt="" class="wp-image-246565" srcset="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png 363w, https://blog.finxter.com/wp-content/uploads/2022/03/image-141-168x300.png 168w" sizes="auto, (max-width: 363px) 100vw, 363px" /></a></figure></div>



<div class="wp-block-buttons alignwide is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-50"><a class="wp-block-button__link" href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noreferrer noopener">Learn More</a></div>
</div>



<p></p>
<p>The post <a href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/">Python A* &#8211; The Simple Guide to the A-Star Search Algorithm</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Python Dijkstra Algorithm</title>
		<link>https://blog.finxter.com/python-dijkstra-algorithm/</link>
		
		<dc:creator><![CDATA[Matija Horvat]]></dc:creator>
		<pubDate>Mon, 06 Dec 2021 16:22:04 +0000</pubDate>
				<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Graph Theory]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://blog.finxter.com/?p=72692</guid>

					<description><![CDATA[<p>You can download the PDF file of the presentation here. Also, watch the presentation as a Gif here: What is Dijkstra&#8217;s Algorithm? Dijkstra&#8217;s algorithm solves the single-source shortest path (SSSP) problem. Generally, it enables finding the shortest route between two vertices in a graph. Its author is dr. Edsger W. Dijkstra, a pioneering contributor to ... <a title="Python Dijkstra Algorithm" class="read-more" href="https://blog.finxter.com/python-dijkstra-algorithm/" aria-label="Read more about Python Dijkstra Algorithm">Read more</a></p>
<p>The post <a href="https://blog.finxter.com/python-dijkstra-algorithm/">Python Dijkstra Algorithm</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Python Dijkstra Algorithm" width="937" height="527" src="https://www.youtube.com/embed/rR5G32bTkFQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>You can download the <a href="https://blog.finxter.com/wp-content/uploads/2021/12/Python-blog-Dijkstras-Algorithm.pdf" data-type="URL" data-id="https://blog.finxter.com/wp-content/uploads/2021/12/Python-blog-Dijkstras-Algorithm.pdf" target="_blank" rel="noreferrer noopener">PDF file of the presentation here</a>. Also, watch the presentation as a Gif here:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="853" height="480" src="https://blog.finxter.com/wp-content/uploads/2021/12/Python-blog-Dijkstras-Algorithm.gif" alt="" class="wp-image-72741"/></figure></div>



<p></p>



<h2 class="wp-block-heading">What is Dijkstra&#8217;s Algorithm?</h2>



<p>Dijkstra&#8217;s algorithm solves the <strong>single-source shortest path (SSSP)</strong> problem. Generally, it enables finding the shortest route between two vertices in a graph. Its author is dr. Edsger W. Dijkstra, a pioneering contributor to computer science.</p>



<p>Dijkstra&#8217;s original algorithm is an uninformed <strong>greedy algorithm</strong>. Although it uses information in a form of weights of the edges, these weights are exact and inherent to the network, so no heuristic estimation function is used. In a most common example, Dijkstra&#8217;s algorithm finds the shortest path between any two cities in a graph.</p>



<h3 class="wp-block-heading">What is Its Purpose?</h3>



<p>Common applications of Dijkstra&#8217;s algorithm are in domains of optimal pathfinding for various distribution networks, such as oil, gas, electricity, road, or computer networks. Computer network equipment employs Dijkstra&#8217;s algorithm as a decision-making algorithm for optimal packet routing between network nodes (see the <em>Open-Shortest Path First protocol</em>).</p>



<p>Before we&#8217;ll dive into the algorithm and the Python implementation, let&#8217;s first skim over some related graph tutorials you may enjoy and that may help your understanding!</p>



<h2 class="wp-block-heading" id="related-graph-tutorials">Related Graph Tutorials</h2>



<p>This algorithm is part of our graph algorithm tutorials:</p>



<ul class="wp-block-list"><li><a rel="noreferrer noopener" href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" target="_blank">Breadth-First Search (BFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-depth-first-search-dfs-algorithm/" target="_blank">Python Depth-First Search (DFS) Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/iterative-deepening-depth-first-search-dfs-algorithm-in-python/" target="_blank">Iterative Deepening Depth-First Search (DFS) Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/the-best-first-search-algorithm-in-python/" target="_blank">Python Best-First Search Algorithm</a></li><li><a href="https://blog.finxter.com/python-dijkstra-algorithm/">Python Dijkstra Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-a-the-simple-guide-to-the-a-star-search-algorithm/" target="_blank">Python A* Algorithm</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/jump-search-algorithm-in-python-a-helpful-guide-with-video/" target="_blank">Jump Search Algorithm in Python</a></li><li><a rel="noreferrer noopener" href="https://blog.finxter.com/python-backtracking-a-helpful-guide-with-video/" target="_blank">Python Backtracking</a></li><li><a href="https://blog.finxter.com/python-beam-search-algorithm/" data-type="post" data-id="204131">Python Beam Search Algorithm</a></li></ul>



<p>Each of these tutorial links opens in a new browser tab.</p>



<h2 class="wp-block-heading">Algorithm Overview: How Does Dijkstra Work?</h2>



<p>Dijkstra&#8217;s algorithm assumes the cost of all vertices except the starting one as infinite. It sets the cost of the starting vertex to 0 and updates the costs of all adjoining, unexplored vertices, according to the weights (distances) associated with the connecting edges. After being visited, each adjoining vertex is added to the priority queue. Finally, the starting vertex is marked as explored and does not participate in any further algorithm calculations.</p>



<p>In each following iteration, the vertex with the lowest cost is taken out of the priority queue and its exploration starts by visiting and conditionally updating all adjoining, non-explored vertices. The update operation implies two steps: assignment of the lower cost to the adjoining node and association with the ancestor vertex for later reconstruction of the shortest path.</p>



<p>The update condition is determined by comparing each adjoining vertex&#8217;s current cost with its new, potentially lower cost. Its new cost is calculated as the cost of the vertex being explored + the weight of the adjoining edge (the between the vertex being explored and the adjoining vertex). </p>



<p>If the current cost of the adjoining vertex is still lower than the potential new cost, the vertex will not be updated. Otherwise, it will assume the new cost (its cost will decrease) and the vertex in focus will become its ancestor vertex. Vertex cost reduction is also referred to as a <em>relaxation procedure</em>. </p>



<p>After visiting and conditionally updating all the adjoining, non-explored vertices, the vertex being explored will be marked as explored and will not participate in any further algorithm calculations. The described process continues until there are no unexplored vertices left in the priority queue.</p>



<p>When the algorithm ends, all vertices are assigned with the lowest possible costs, and the traversal algorithm yields the shortest possible path between the starting and target vertices. For comparison with the previously described best-first search algorithm: if its heuristic function would give the same relative cost for all vertices as the Dijkstra&#8217;s algorithm, it would also traverse the vertices in the same order and yield the same shortest path.</p>



<h2 class="wp-block-heading">What Are Properties of Dijkstra?</h2>



<p>Dijkstra&#8217;s algorithm doesn&#8217;t use a heuristic function and doesn&#8217;t estimate the costs of the graph&#8217;s vertices. Instead, it relies on the exact information represented by the edge&#8217;s weights. As the initial costs of non-starting vertices are set to infinity, the algorithm successively lowers their costs until they reach their minimum cost.</p>



<p>This behavior yields its optimality property: <strong><em>minimum costs assigned to vertices enable the algorithm to always find the shortest path between the starting vertex and any other vertex in the graph.</em></strong> As the shortest paths always start from the starting vertex, the algorithm is attributed as the “single-source” algorithm.</p>



<p>Besides being <strong>optimal</strong>, the algorithm is also <strong>complete</strong>, i.e., it will always take a finite time to find a solution.</p>



<p>However, Dijkstra&#8217;s algorithm <strong>cannot</strong> handle edges with <strong>negative weights</strong>.</p>



<h2 class="wp-block-heading">Implementation Python Dijkstra</h2>



<p>The implementation of Dijkstra&#8217;s algorithm is achieved by function <code>dijkstra()</code> and a modification of the underlying class Graph.</p>



<p>The <code>dijkstra()</code> function takes three parameters: </p>



<ul class="wp-block-list"><li>The <code>graph</code> parameter takes an initialized Graph object (see the blog on the <em><a rel="noreferrer noopener" href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/" data-type="post" data-id="36880" target="_blank">breadth-first search algorithm</a></em>, the section on <em><a rel="noreferrer noopener" href="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/#How_is_a_Graph_Implemented" data-type="URL" data-id="https://blog.finxter.com/breath-first-search-bfs-algorithm-in-python/#How_is_a_Graph_Implemented" target="_blank">graphs</a></em>). </li><li>The <code>start_vertex</code> parameter takes the starting vertex, which we choose freely (remember, a graph is not a tree, there is no absolute root). </li><li>The&nbsp;<code>target</code> parameter is the entity we want to find in the graph, enclosed in a vertex.</li></ul>



<p>For a better understanding of the algorithm and its implementation, each step is precisely described in the code below.</p>



<p>As we introduced several changes to the <code>Graph</code> class, the most practical approach is to show the entire class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="113-116, 118-121" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Graph:

    def __init__(self, directed=False):
        self._outgoing = {}
        # If the graph is undirected, 'self._outgoing'
        # is the universal storage.
        self._incoming = {} if directed else self._outgoing

    # If the graph is directed, the 'self._incoming' 
    # dictionary differs from the 'self._outgoing'.
    def is_directed(self):
        return self._incoming is not self._outgoing

    # The function returns a generator of incoming
    # or outgoing (default) edges of a vertex.
    def adjacent_edges(self, vertex, outgoing=True):
        # References the corresponding outer dictionary
        # (dictionary of dictionaries)
        adj_edges = self._outgoing if outgoing else self._incoming

        # Access each of the edges for this endpoint vertex.
        for edge in adj_edges[vertex].values():
            yield edge

    def add_vertex(self, entity=None, h=None):
        # Constructs a new vertex from the entity.
        vertex = self.Vertex(entity, h)
        # The vertex becomes a key in the outer dictionary,
        # but the value is an internal dictionary (as we model
        # both dimensions for each edge: origin and destination).
        # e.g. {vertex_1a:{vertex_b:edge_a_b}, vertex_b:{vertex_c:edge_b_c}}.
        self._outgoing[vertex] = {}
        if self.is_directed():
            self._incoming[vertex] = {}

    def add_edge(self, origin, destination, weight=None):
        # Constructs a new edge from the vertices.
        edge = self.Edge(origin, destination, weight)
        # Adds the edge to the dictionary (dictionaries are
        # the same if the graph is undirected). The outer key
        # represents the origin, i.e. the component 'a' of
        # the edge-defining pair (a, b). The inner key stands
        # for the component 'b' of the edge-defining pair (a, b).
        self._outgoing[origin][destination] = edge
        # Even if the graph is undirected, each edge has to
        # be added twice, i.e. once for each of its endpoints.
        self._incoming[destination][origin] = edge

    def vertices(self):
        return self._outgoing.keys()

    def edges(self):
        # All the edges are collected into a set.
        result = set()
        for inner_dict in self._outgoing.values():
            result.update(inner_dict.values())
        return result

    class Vertex:
        __slots__ = '_entity', '_h'

        def __init__(self, entity, h=None):
            self.entity = entity
            self.h = h

        # The real-world entity is represented by the Vertex object.
        @property
        def entity(self):
            return self._entity

        @entity.setter
        def entity(self, entity):
            self._entity = entity

        # The real-world entity has a cost of h.
        @property
        def h(self):
            return self._h

        @h.setter
        def h(self, h):
            self._h = h

        # We have to implement __hash__ to use the object as a dictionary key.
        def __hash__(self):
            return hash(id(self))

        def __lt__(self, other):
            if self.h is None:
                return False
            elif other.h is None:
                return True
            else:
                return self.h &lt; other.h

    class Edge:
        __slots__ = '_origin', '_destination', '_weight'

        def __init__(self, origin, destination, weight=None):
            self._origin = origin
            self._destination = destination
            self._weight = weight

        def endpoints(self):
            return self._origin, self._destination

        # Returns the other component of the edge-defining pair (a, b)
        # for a given component a or b, respectively.
        def opposite(self, vertex):
            return self._destination if self._origin is vertex \
                else self._origin

        # Returns the weight of the edge.
        @property
        def weight(self):
            return self._weight

        # Sets the weight of the edge
        @weight.setter
        def weight(self, weight):
            self._weight = weight

        def __hash__(self):
            return hash((self._origin, self._destination))
</pre>



<p>A significant difference to the previous version of the Graph class is the introduction of the <em>property</em> <a rel="noreferrer noopener" href="https://blog.finxter.com/closures-and-decorators-in-python/" data-type="post" data-id="11909" target="_blank">decorator</a> and the <code>weight</code> attribute, as highlighted in the code.</p>



<p>With these changes in place, implementation of the core function, <code>dijkstra()</code> is:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">from graph import Graph
from queue import PriorityQueue


def dijkstra(graph, start_vertex, target):
    # Create the priority queue for open vertices.
    vertices_pq = PriorityQueue()

    # Initialize the starting vertex to cost 0.
    start_vertex.h = 0

    # Adds the start vertex to the priority queue.
    print(f'Visiting/queueing vertex {start_vertex.entity}')
    vertices_pq.put(start_vertex)
    print('Prioritized vertices (v, h(v)):',
          *((vert.entity, vert.h) for vert in vertices_pq.queue), end=2 * '\n')

    # The starting vertex is visited first and has no leading edges.
    # If we did not put it into 'visited' in the first iteration,
    # it would end up in 'visited' during the second iteration, pointed to
    # by one of its children vertices as a previously unvisited vertex.
    visited[start_vertex] = None

    # Loops until the priority list gets empty.
    while not vertices_pq.empty():
        # Gets the vertex with the lowest cost.
        vertex = vertices_pq.get()
        # If the vertex being explored is a target vertex, ends the algorithm.
        print(f'Exploring vertex {vertex.entity}')
        if vertex.entity == target:
            return vertex
        # Examines each non-visited adjoining edge/vertex.
        for edge in graph.adjacent_edges(vertex):
            # Gets the second endpoint.
            v_2nd_endpoint = edge.opposite(vertex)

            # Skips the explored vertices.
            if v_2nd_endpoint in explored:
                continue

            # Checks if the endpoint has a cost and is the cost the cheapest one.
            if v_2nd_endpoint.h is None or vertex.h + edge.weight &lt; v_2nd_endpoint.h:
                # Adds the second endpoint to 'visited' and maps
                # the leading edge for the search path reconstruction.
                v_2nd_endpoint.h = vertex.h + edge.weight
                # Prevents reinsertion to the priority queue. The
                # endpoint distance value will be updated.
                if v_2nd_endpoint not in visited:
                    print(f'Visiting/queueing vertex {v_2nd_endpoint.entity}')
                    vertices_pq.put(v_2nd_endpoint)
                # Forces the priority queue to reorder in case of an
                # inner vertex update resulting with the highest priority
                vertices_pq.put(vertices_pq.get())
                # Replaces the previous vertex' ancestor with a cheaper one.
                visited[v_2nd_endpoint] = edge
        print('Prioritized vertices (v, h(v)):',
              *((vert.entity, vert.h) for vert in vertices_pq.queue), end=2 * '\n')
        # The vertex is used for update and put aside.
        explored.append(vertex)
    return None
</pre>



<p>Before we can test the algorithm, we have to initialize a <a href="https://blog.finxter.com/graph-applications/" data-type="post" data-id="955" target="_blank" rel="noreferrer noopener">graph</a> and build it by adding vertices and edges to it:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Initializes an empty graph (object).
g = Graph()

# Loads the graph with the first seven vertices.
for i in range(0, 7):
    g.add_vertex(i)

# Constructs the 'vertices' dictionary for a more
# convenient access during the graph construction.
vertices = {k.entity: k for k in g.vertices()}

# Constructs an arbitrary graph from
# the existing vertices and edges.
g.add_edge(vertices[0], vertices[1], 4)
g.add_edge(vertices[0], vertices[2], 2)
g.add_edge(vertices[2], vertices[4], 1)
g.add_edge(vertices[4], vertices[3], 3)
g.add_edge(vertices[3], vertices[5], 2)
g.add_edge(vertices[0], vertices[5], 5)
g.add_edge(vertices[2], vertices[6], 5)

# Initializes the search path and a dictionary of visited vertices.
path = []
explored = []
visited = {}
</pre>



<p>Now that we have prepared everything, we can test <code>dijkstra()</code> and see how it works. Here is the part of the code that runs the algorithm, constructs the search path (if there is one), and shows in a step-by-step manner how it proceeds through the graph:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Starts the search.
result = dijkstra(g, vertices[5], 6)

# If the entity is found...
if result is not None:
    # The search path ends with the found vertex (entity).
    # Each vertex is a container for its real-world entity.
    path_vertex = result
    # The entity is added to the 'path'.
    path.append(path_vertex.entity)
    # Constructs the rest of the search path (if it exists)...
    while True:
        # Gets a discovery edge leading to the vertex.
        path_edge = visited.get(path_vertex)
        # If the path vertex is the root, it has no discovery edge...
        if path_edge is None:
            break
        # Otherwise, gets the second (parent vertex) endpoint.
        path_vertex = path_edge.opposite(path_vertex)
        # The entity is added to the 'path'.
        path.append(path_vertex.entity)
    print('Search path found:', end=' ')
    # The path is reversed and starts with the root vertex.
    print(*reversed(path), sep=' -> ')
# Otherwise...
else:
    print('\nEntity is not found')
The test run gave us the output:
Visiting/queueing vertex 5
Prioritized vertices (v, h(v)): (5, 0)

Exploring vertex 5
Visiting/queueing vertex 3
Visiting/queueing vertex 0
Prioritized vertices (v, h(v)): (3, 2) (0, 5)

Exploring vertex 3
Visiting/queueing vertex 4
Prioritized vertices (v, h(v)): (0, 5) (4, 5)

Exploring vertex 0
Visiting/queueing vertex 1
Visiting/queueing vertex 2
Prioritized vertices (v, h(v)): (4, 5) (1, 9) (2, 7)

Exploring vertex 4
Prioritized vertices (v, h(v)): (2, 6) (1, 9)

Exploring vertex 2
Visiting/queueing vertex 6
Prioritized vertices (v, h(v)): (1, 9) (6, 11)

Exploring vertex 1
Prioritized vertices (v, h(v)): (6, 11)

Exploring vertex 6
Search path found: 5 -> 3 -> 4 -> 2 -> 6
</pre>



<p>Based on the <a rel="noreferrer noopener" href="https://blog.finxter.com/python-print/" data-type="post" data-id="20731" target="_blank">output</a>, we can see that the search started from vertex 5 and that the <code>dijkstra()</code> has found the entity vertex 6. The entire search path is also displayed, and we should note that the search path will always be the shortest one: </p>



<p><code>5 -&gt; 3 -&gt; 4 -&gt; 2 -&gt; 6</code>. </p>



<p>However, a modification of just one weight might lead to a different solution, as we will demonstrate with the next example. With that in mind, lets tweak the weight on one of our edges:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="python" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Constructs an arbitrary graph from
# the existing vertices and edges.
g.add_edge(vertices[0], vertices[1], 4)
g.add_edge(vertices[0], vertices[2], 2)
g.add_edge(vertices[2], vertices[4], 1)
g.add_edge(vertices[4], vertices[3], 3)
g.add_edge(vertices[3], vertices[5], 2)
g.add_edge(vertices[0], vertices[5], 4)
g.add_edge(vertices[2], vertices[6], 5)
The re-run gave us the output:
Visiting/queueing vertex 5
Prioritized vertices (v, h(v)): (5, 0)

Exploring vertex 5
Visiting/queueing vertex 3
Visiting/queueing vertex 0
Prioritized vertices (v, h(v)): (3, 2) (0, 4)

Exploring vertex 3
Visiting/queueing vertex 4
Prioritized vertices (v, h(v)): (0, 4) (4, 5)

Exploring vertex 0
Visiting/queueing vertex 1
Visiting/queueing vertex 2
Prioritized vertices (v, h(v)): (4, 5) (1, 8) (2, 6)

Exploring vertex 4
Prioritized vertices (v, h(v)): (2, 6) (1, 8)

Exploring vertex 2
Visiting/queueing vertex 6
Prioritized vertices (v, h(v)): (1, 8) (6, 11)

Exploring vertex 1
Prioritized vertices (v, h(v)): (6, 11)

Exploring vertex 6
Search path found: 5 -> 0 -> 2 -> 6
</pre>



<p>After a re-run, we got a different solution without modifying the algorithm, but only by changing one of our edges&#8217; weights. Our simple demonstration just pointed out the dependence of Dijkstra&#8217;s algorithm on the edge weights.</p>



<h2 class="wp-block-heading">Efficiency Analysis</h2>



<p>The algorithm&#8217;s worst-case <strong>time complexity</strong> depends on the implementation choice of data structure as storage for visited vertices, which in turn depends on the number of vertices <em>v</em> and edges <em>e</em>.</p>



<p>A heap implementation is more appropriate when the number of edges <em>e</em> in the graph is small, i.e. when <em>e</em> &lt; <em>v</em><sup>2</sup>/log <em>v</em>. In this case, the time complexity is <em>O((e+v) </em>log<em> v)</em>.</p>



<p>On the contrary, the sequence implementation is more appropriate when the number of edges <em>e</em> in the graph is large, i.e. when <em>e</em> &gt; <em>v</em><sup>2</sup>/log <em>v.</em> In this case, the time complexity is <em>O(v<sup>2</sup>)</em>.</p>



<p>On another note, a more advanced approach to implementation of the priority queue, such as a <em>Fibonacci heap</em>, can yield time complexity of <em>O(e+v</em> log <em>v)</em>.</p>



<p><strong>Space complexity</strong> of the Dijkstra&#8217;s algorithm is <em>O(v+e)</em>.</p>



<p>Dijkstra&#8217;s algorithm is <em>optimal</em>, as it will always yield an optimal search path. Furthermore, Dijkstra&#8217;s algorithm will always find a solution if there is one, so it is also <em>complete</em>.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>In this article, we learned about Dijkstra&#8217;s search algorithm.</p>



<ul class="wp-block-list"><li>First, we explained what Dijkstra&#8217;s algorithm is.</li><li>Second, we took a look at what are its common purposes and applications.</li><li>Third, we went through an explanation of how the algorithm works.</li><li>Fourth, we examined the algorithm&#8217;s main properties.</li><li>Fifth, we went through the implementation of the algorithm, which is based on the Graph<em> </em>abstract data structure (<code>Graph</code> class implementation is given above). We also tested the algorithm by calling its main function, <code>dijkstra()</code>, and analyzed its steps of execution for two slightly different edge weight scenarios.</li><li>Sixth, we analyzed the algorithm efficiency.</li></ul>



<p>In the end, we concluded that the algorithm efficiency is optimal, and if the solution exists, Dijkstra&#8217;s algorithm will always find it in its optimal form. The algorithm always takes finite time in reaching the solution and is driven solely by the edges&#8217; weights and the graph structure.</p>






<h2 class="wp-block-heading">Academy Course &#8211; Mastering the Top 10 Graph Algorithms</h2>



<p>If you want to improve your fundamental computer science skills, there&#8217;s nothing more effective than <strong>studying algorithms</strong>. </p>



<p>To help you master the <strong>most important graph algorithms</strong>, we&#8217;ve just launched the &#8220;Top 10 Algorithms&#8221; course at the <a rel="noreferrer noopener" href="https://academy.finxter.com/university/graph-algorithms-in-python/" data-type="URL" data-id="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank">Finxter Computer Science Academy</a>. This great course from Finxter Star Creator Matija <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> teaches you the most important graph algorithms such as BFS, DFS, A*, and Dijkstra. </p>



<p>Understanding these algorithms will not only make you a better coder, but it&#8217;ll also lay a strong foundation on which you can build your whole career as a computer scientist.</p>



<p>Click the screenshot to find out more:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><a href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="363" height="650" src="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png" alt="" class="wp-image-246565" srcset="https://blog.finxter.com/wp-content/uploads/2022/03/image-141.png 363w, https://blog.finxter.com/wp-content/uploads/2022/03/image-141-168x300.png 168w" sizes="auto, (max-width: 363px) 100vw, 363px" /></a></figure></div>



<div class="wp-block-buttons alignwide is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button has-custom-width wp-block-button__width-50"><a class="wp-block-button__link" href="https://academy.finxter.com/university/graph-algorithms-in-python/" target="_blank" rel="noreferrer noopener">Learn More</a></div>
</div>



<p></p>
<p>The post <a href="https://blog.finxter.com/python-dijkstra-algorithm/">Python Dijkstra Algorithm</a> appeared first on <a href="https://blog.finxter.com">Be on the Right Side of Change</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 
Minified using Disk

Served from: blog.finxter.com @ 2026-06-27 11:31:54 by W3 Total Cache
-->