How to Balance Chemical Equations in Python using Constraint Optimization (PuLP)
Tags: python, programming, codenewbie, tutorial
Published: 2021-06-15 07:11:36

--- 
Originally posted on [realpythonproject.com](https://www.realpythonproject.com/how-to-balance-chemical-equations-in-python-using-constraint-optimization-pulp/)

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

<!-- wp:heading {"level":4} -->
<h4>We will be using PuLP and the chemparse libraries to balance chemical equations</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>You can find the source code<a href="https://github.com/rahulbanerjee26/Chemical-Equation-Balancer" rel="noreferrer noopener" target="_blank"> here</a></p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Pre-Requisites</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li>Familiarity with Constraint Optimization. Check out my previous article for an introduction to <a href="https://www.realpythonproject.com/basic-linear-programming-in-python-with-pulp/" rel="noreferrer noopener" target="_blank">Constraint Optimization and PuLp</a></li><li>Some Familiarity with Balancing Chemical Equations. </li><li>It is good to have some familiarity with Streamlit. </li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3>How can we balance Chemical Equations using Constraint Optimization?</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Balancing a chemical equation essentially means respecting the conservation of mass and ensuring the same number of atoms of an element are present on the left-hand side (Reactants) and the right-hand side (Products). Basically if you X grams of an element as a reactant, the product will also have X grams of that element in the Products (ideal conditions).&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*7oIbJWMsmLzKx7rjWm0Hsg.png" alt=""/><figcaption>Picture by&nbsp;Author</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>In the above picture, you can notice the following</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>In the unbalanced equations, there are 2 atoms of H and Cl in the Products. However, there is only a single atom of H and Cl in the Reactants. This does not respect the law of conservation of mass</li><li>In the balanced equation, we are using 2 atoms of H and Cl in the reactants. The number of atoms in the Products remains unchanged. As a result, the equation is balanced and it no longer violates the law of conservation of mass.</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>The above equation was easy to solve and can be done manually. However, things get complicated as the number of elements increases and the number of reactants/products increases. Eg: The below equation although doable manually will require quite a bit of trial and error.</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*FTDONbGgFIMpbiZu12VoiQ.png" alt=""/><figcaption>Example of an unbalanced equation</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>So how can we use Constraint Optimization?&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let’s consider the first equation we had looked at</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*R0Z_txrViqpEwjFHZXBrrA.png" alt=""/><figcaption>Example of an Unbalanced Equation</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>The coefficient of each reactant/product can be thought of as a variable.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*QgdJMR8Fm88JdNN17l4U6Q.png" alt=""/><figcaption>Equation with Variable Coefficients</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>X1, X2, X3, and X4 are the variable coefficients. Each variable must be an integer greater than or equal to 1.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Each element adds a constraint,i.e</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>For Zn: The number of Zinc Atoms in Reactant must equal to the number of Zinc Atoms in Products</li></ul>
<!-- /wp:list -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*ElBM_4GTwrZ1c_APtPQmvA.png" alt=""/><figcaption>Constraint due to&nbsp;Zn</figcaption></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>For Cl: The number of Chlorine Atoms in Reactant must equal to the number of Chlorine Atoms in Products</li></ul>
<!-- /wp:list -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*49EaN487z2pyl7jaVA6JLQ.png" alt=""/><figcaption>Constraint due to&nbsp;Cl</figcaption></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>For H: The number of Hydrogen Atoms in Reactant must equal to the number of Hydrogen Atoms in Products</li></ul>
<!-- /wp:list -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*V97td_GXzTuqrlm_LgdIHQ.png" alt=""/><figcaption>Constraint due to&nbsp;H</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>The Problem can be considered as a Minimizing Problem since we need to find the smallest coefficients that can balance the equation.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The problem has no objective other than minimizing the coefficients, which means the objective is basically 0 (None).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To summarize this is how our problem is setup</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*qftt_wyaEhTvFXP2_bslKg.png" alt=""/><figcaption>Problem Setup</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>This problem can be set up using PuLP and solver using PuLP’s default solver.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, we can move on to generalizing this to support other equations as well.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Parsing the Chemical&nbsp;Equation</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We will use the chemparse library to parse the reactants and products.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">pip3 install chemparse</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Below are a few examples of what chemparse returns. They are taken from the library’s documentation</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">“CH4” returns {“C”:1.0, “H”:4.0}

“C1.5O3” returns {“C”:1.5, “O”:3.0}

"(CH3)2(CH2)4" returns {"C":6.0, "H":14.0}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Let's create a function to parse the equations. The function will expect an input similar to the one below</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">Zn + HCL -&gt; ZnCl2 + H2</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>We can split by ‘-&gt;’ to get the Left Hand Side and the Right Hande Side]</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*cqnrVo8LDw3iVVx9mz-buA.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>To get the compounds we can split by “+” and remove the trailing spaces.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We need to store the unique elements so we can form constraints for each and convert each reactant and product into a dictionary produced by chemparse.</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*pGz9Yydc6ZvcrC4kXtXv5g.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>First, we iterate over the lhsCompounds and store the result from chemparse as well as the unique elements.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>After that we iterate over rhsCompounds, we do not need to store the unique elements again. However, we store the coefficients as a negative number since this will make it easier when setting up our constraints.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Function to set up and solve Constraint Optimization Problem</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Now, we can move on to the problem-solving stuff.</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*yg6uMBP_0E18iTyqQF9KwA.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>We will call the parse function we had written earlier and store the returned values.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Every reactant/product will have a co-efficient, therefore we can simply loop over the variable allCompounds (this contains the output from chemparse for each reactant/product) and create a variable during each iteration.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The variables will have a category of Integer and a lower bound value of 0</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*cGfh0HzW1zTWF3yi8V7aAg.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>As discussed earlier, the problem is a Minimization problem with no Objective.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, let’s set up our constraints</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*_3WRmR8VNelQYiUMe8R49Q.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>As discussed earlier, each element will add a constraint associated with it.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>we loop over the uniqueElements</li><li>get the number of atoms of the element in each reactant/product</li><li>sum up the coefficients (Remember all the Product coefficients are stored as negative values)</li><li>Add a constraint that the sum should be 0</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Now, we are ready to solve the problem and create the balanced equation</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*Xrh18t0Xs-9oGQ9BvITOwQ.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:heading {"level":3} -->
<h3>Streamlit WebApp</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Install Streamlit</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="bash" class="language-bash">pip install streamlit</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>This will be a pretty minimalistic app.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*PkyDf07wmLJXBPA-Pfg7RA.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>We create a text_input component and set the default value to an unbalanced equation. The balance() function is imported and we pass the text_input’s value as an argument.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Additionally, we can also display the problem before we solve it. This should be inside the balance() function</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code lang="python" class="language-python">st.text(prob)</code></pre>
<!-- /wp:code -->

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

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><em>Connect with me on </em><a href="https://www.linkedin.com/in/rahulbanerjee2699/" rel="noreferrer noopener" target="_blank"><em>LinkedIn</em></a><em>, </em><a href="https://twitter.com/rahulbanerjee99" rel="noreferrer noopener" target="_blank"><em>Twitter</em></a></p></blockquote>
<!-- /wp:quote -->