<?xml version="1.0" encoding="UTF-8"?>

<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     >
  <channel>
    <atom:link href="http://kitchingroup.cheme.cmu.edu/blog/feed/index.xml" rel="self" type="application/rss+xml" />
    <title>The Kitchin Research Group</title>
    <link>https://kitchingroup.cheme.cmu.edu/blog</link>
    <description>Chemical Engineering at Carnegie Mellon University</description>
    <pubDate>Sat, 01 Nov 2025 13:47:46 GMT</pubDate>
    <generator>Blogofile</generator>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    
    <item>
      <title>Calling lapack directly from scipy</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/05/21/Calling-lapack-directly-from-scipy</link>
      <pubDate>Tue, 21 May 2013 11:28:27 EDT</pubDate>
      <category><![CDATA[linear algebra]]></category>
      <guid isPermaLink="false">d42RG0svX3zDrt0Zm7fkqO5UxyE=</guid>
      <description>Calling lapack directly from scipy</description>
      <content:encoded><![CDATA[


&lt;p&gt;
If the built in linear algebra functions in numpy and scipy do not meet your needs, it is often possible to directly call lapack functions. Here we call a function to solve a set of complex linear equations. The lapack function for this is ZGBSV. The description of this function (&lt;a href="http://linux.die.net/man/l/zgbsv"&gt;http://linux.die.net/man/l/zgbsv&lt;/a&gt;) is:
&lt;/p&gt;

&lt;p&gt;
ZGBSV computes the solution to a complex system of linear equations A * X = B, where A is a band matrix of order N with KL subdiagonals and KU superdiagonals, and X and B are N-by-NRHS matrices. The LU decomposition with partial pivoting and row interchanges is used to factor A as A = L * U, where L is a product of permutation and unit lower triangular matrices with KL subdiagonals, and U is upper triangular with KL+KU superdiagonals. The factored form of A is then used to solve the system of equations A * X = B. 
&lt;/p&gt;

&lt;p&gt;
The python signature is (&lt;a href="http://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lapack.zgbsv.html#scipy.linalg.lapack.zgbsv"&gt;http://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lapack.zgbsv.html#scipy.linalg.lapack.zgbsv&lt;/a&gt;): 
&lt;/p&gt;

&lt;p&gt;
lub,piv,x,info = zgbsv(kl,ku,ab,b,[overwrite_ab,overwrite_b])
&lt;/p&gt;

&lt;p&gt;
We will look at an example from &lt;a href="http://www.nag.com/lapack-ex/node22.html"&gt;http://www.nag.com/lapack-ex/node22.html&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
We solve \(A x = b\) with
&lt;/p&gt;

&lt;p&gt;
\( 
A = \left(
&lt;/p&gt;
\begin{array}{cccc}
   -1.65 + 2.26 i &amp; -2.05 - 0.85 i &amp;  0.97 - 2.84 i &amp;       0        \\
           6.30 i &amp; -1.48 - 1.75 i &amp; -3.99 + 4.01 i &amp;  0.59 - 0.48 i \\
         0        &amp; -0.77 + 2.83 i &amp; -1.06 + 1.94 i &amp;  3.33 - 1.04 i \\
         0        &amp;       0        &amp;  4.48 - 1.09 i &amp; -0.46 - 1.72 i
\end{array}
&lt;p&gt;
       \right)
\)
&lt;/p&gt;

&lt;p&gt;
\(
b = \left(
&lt;/p&gt;
\begin{array}{cc}
    -1.06 + 21.50 i \\
   -22.72 - 53.90 i \\
    28.24 - 38.60 i \\
   -34.56 + 16.73 i
\end{array}
&lt;p&gt;
       \right).
\)
&lt;/p&gt;

&lt;p&gt;
The \(A\) matrix has one lower diagonal (kl = 1) and two upper diagonals (ku = 2), four equations (n = 4) and one right-hand side.
&lt;/p&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; scipy.linalg.lapack &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; la

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;http://www.nag.com/lapack-ex/node22.html&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
A = np.array([[-1.65 + 2.26j, -2.05 - 0.85j,  0.97 - 2.84j,  0.0         ],
              [6.30j,         -1.48 - 1.75j, -3.99 + 4.01j,  0.59 - 0.48j],
              [0.0,           -0.77 + 2.83j, -1.06 + 1.94j,  3.33 - 1.04j],
              [0.0,            0.0,           4.48 - 1.09j, -0.46 - 1.72j]])

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;construction of Ab is tricky.  Fortran indexing starts at 1, not&lt;/span&gt;
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;0. This code is based on the definition of Ab at&lt;/span&gt;
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;http://linux.die.net/man/l/zgbsv. First, we create the Fortran&lt;/span&gt;
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;indices based on the loops, and then subtract one from them to index&lt;/span&gt;
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;the numpy arrays.&lt;/span&gt;
Ab = np.zeros((5,4),dtype=np.complex)
n, kl, ku = 4, 1, 2

&lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; j &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;range&lt;/span&gt;(1, n + 1):
    &lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; i &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;range&lt;/span&gt;(max(1, j - ku), &lt;span style="color: #8b0000;"&gt;min&lt;/span&gt;(n, j + kl) + 1):
        Ab[kl + ku + 1 + i - j - 1, j - 1] = A[i-1, j-1]

b = np.array([[-1.06  + 21.50j],
              [-22.72 - 53.90j],
              [28.24 - 38.60j],
              [-34.56 + 16.73j]])

lub, piv, x, info = la.flapack.zgbsv(kl, ku, Ab, b)

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;compare to results at http://www.nag.com/lapack-ex/examples/results/zgbsv-ex.r&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'x = '&lt;/span&gt;,x
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'info = '&lt;/span&gt;,info

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;check solution&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'solved: '&lt;/span&gt;,np.all(np.dot(A,x) - b &amp;lt; 1e-12)

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;here is the easy way!!!&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'\n\nbuilt-in solver'&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.linalg.solve(A,b)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
x =  [[-3.+2.j]
 [ 1.-7.j]
 [-5.+4.j]
 [ 6.-8.j]]
info =  0
solved:  True


built-in solver
[[-3.+2.j]
 [ 1.-7.j]
 [-5.+4.j]
 [ 6.-8.j]]
&lt;/pre&gt;

&lt;p&gt;
Some points of discussion. 
&lt;/p&gt;

&lt;ol class="org-ol"&gt;
&lt;li&gt;Kind of painful! but, nevertheless, possible. You have to do a lot more work figuring out the dimensions of the problem, how to setup the problem, keeping track of indices, etc&amp;#x2026;  
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
But, one day it might be helpful to know this can be done, e.g. to debug an installation, to validate an approach against known results, etc&amp;#x2026;
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/05/21/Calling-lapack-directly-from-scipy.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Computing determinants from matrix decompositions</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/04/01/Computing-determinants-from-matrix-decompositions</link>
      <pubDate>Mon, 01 Apr 2013 19:57:29 EDT</pubDate>
      <category><![CDATA[linear algebra]]></category>
      <guid isPermaLink="false">Gn1GPig0M4iD-jjvFYpXr7NCaK4=</guid>
      <description>Computing determinants from matrix decompositions</description>
      <content:encoded><![CDATA[


&lt;p&gt;

There are a few properties of a matrix that can make it easy to compute determinants.
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The determinant of a triangular matrix is the product of the elements on the diagonal. 
&lt;/li&gt;
&lt;li&gt;The determinant of a permutation matrix is (-1)**n where n is the number of permutations. Recall a permutation matrix is a matrix with a one in each row, and column, and zeros everywhere else. 
&lt;/li&gt;
&lt;li&gt;The determinant of a product of matrices is equal to the product of the determinant of the matrices.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
The LU decomposition computes three matrices such that \(A = P L U\). Thus, \(\det A = \det P \det L \det U\). \(L\) and \(U\) are triangular, so we just need to compute the product of the diagonals. \(P\) is not triangular, but if the elements of the diagonal are not 1, they will be zero, and then there has been a swap. So we simply subtract the sum of the diagonal from the length of the diagonal and then subtract 1 to get the number of swaps.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
&lt;span style="color: #8b0000;"&gt;from&lt;/span&gt; scipy.linalg &lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; lu

A = np.array([[6, 2, 3],
              [1, 1, 1],
              [0, 4, 9]])

P, L, U = lu(A)

nswaps = &lt;span style="color: #8b0000;"&gt;len&lt;/span&gt;(np.diag(P)) - np.sum(np.diag(P)) - 1

detP = (-1)**nswaps
detL =  np.prod(np.diag(L)) 
detU = np.prod(np.diag(U))

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; detP * detL * detU

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.linalg.det(A)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
24.0
24.0
&lt;/pre&gt;

&lt;p&gt;
According to the numpy documentation, a method similar to this is used to compute the determinant. 
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/04/01/Computing-determinants-from-matrix-decompositions.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Potential gotchas in linear algebra in numpy</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/03/12/Potential-gotchas-in-linear-algebra-in-numpy</link>
      <pubDate>Tue, 12 Mar 2013 22:19:53 EDT</pubDate>
      <category><![CDATA[linear algebra]]></category>
      <category><![CDATA[gotcha]]></category>
      <guid isPermaLink="false">TZM2RkZNaMrwMjC4SLUQnVHywSU=</guid>
      <description>Potential gotchas in linear algebra in numpy</description>
      <content:encoded><![CDATA[


&lt;p&gt;
Numpy has some gotcha features for linear algebra purists. The first is that a 1d array is neither a row, nor a column vector. That is, \(a\) = \(a^T\) if \(a\) is a 1d array. That means you can take the dot product of \(a\) with itself, without transposing the second argument. This would not be allowed in Matlab.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

a = np.array([0, 1, 2])
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; a.shape
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; a
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; a.T

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(a, a)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(a, a.T)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
&amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; (3L,)
[0 1 2]
[0 1 2]
&amp;gt;&amp;gt;&amp;gt;
5
5
&lt;/pre&gt;

&lt;p&gt;
Compare the previous behavior with this 2d array. In this case, you cannot take the dot product of \(b\) with itself, because the dimensions are incompatible. You must transpose the second argument to make it dimensionally consistent. Also, the result of the dot product is not a simple scalar, but a 1 &amp;times; 1 array.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;b = np.array([[0, 1, 2]])
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; b.shape
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; b
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; b.T

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(b, b)    &lt;span style="color: #ff0000; font-weight: bold;"&gt;# this is not ok, the dimensions are wrong.&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(b, b.T)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(b, b.T).shape
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
(1L, 3L)
[[0 1 2]]
[[0]
 [1]
 [2]]
&amp;gt;&amp;gt;&amp;gt; Traceback (most recent call last):
  File "&amp;lt;stdin&amp;gt;", line 1, in &amp;lt;module&amp;gt;
ValueError: objects are not aligned
[[5]]
(1L, 1L)
&lt;/pre&gt;

&lt;p&gt;
Try to figure this one out! x is a column vector, and y is a 1d vector. Just by adding them you get a 2d array.
&lt;/p&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;x = np.array([[2], [4], [6], [8]])
y = np.array([1, 1, 1, 1, 1, 2])
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; x + y
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
&amp;gt;&amp;gt;&amp;gt; [[ 3  3  3  3  3  4]
 [ 5  5  5  5  5  6]
 [ 7  7  7  7  7  8]
 [ 9  9  9  9  9 10]]
&lt;/pre&gt;

&lt;p&gt;
Or this crazy alternative way to do the same thing.
&lt;/p&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;x = np.array([2, 4, 6, 8])
y = np.array([1, 1, 1, 1, 1, 1, 2])

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; x[:, np.newaxis] + y
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
&amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; [[ 3  3  3  3  3  3  4]
 [ 5  5  5  5  5  5  6]
 [ 7  7  7  7  7  7  8]
 [ 9  9  9  9  9  9 10]]
&lt;/pre&gt;

&lt;p&gt;
In the next example,  we have a 3 element vector and a 4 element vector. We convert \(b\) to a 2D array with np.newaxis, and compute the outer product of the two arrays. The result is a 4 &amp;times; 3 array.
&lt;/p&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;a = np.array([1, 2, 3])
b = np.array([10, 20, 30, 40])

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; a * b[:, np.newaxis]
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
&amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; [[ 10  40  90]
 [ 20  80 180]
 [ 30 120 270]
 [ 40 160 360]]
&lt;/pre&gt;

&lt;p&gt;
These concepts are known in numpy as array broadcasting. See &lt;a href="http://www.scipy.org/EricsBroadcastingDoc" &gt;http://www.scipy.org/EricsBroadcastingDoc&lt;/a&gt; and &lt;a href="http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html" &gt;http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html&lt;/a&gt; for more details.
&lt;/p&gt;

&lt;p&gt;
These are points to keep in mind, as the operations do not strictly follow the conventions of linear algebra, and may be confusing at times.
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/03/12/Potential-gotchas-in-linear-algebra-in-numpy.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Determining linear independence of a set of vectors</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/03/01/Determining-linear-independence-of-a-set-of-vectors</link>
      <pubDate>Fri, 01 Mar 2013 16:44:46 EST</pubDate>
      <category><![CDATA[linear algebra]]></category>
      <guid isPermaLink="false">4sPRgpQwos2UdI1hgVqlmfRMzHc=</guid>
      <description>Determining linear independence of a set of vectors</description>
      <content:encoded><![CDATA[


&lt;p&gt;
 &lt;a href="http://matlab.cheme.cmu.edu/2011/08/02/determining-linear-independence-of-a-set-of-vectors/" &gt;Matlab post&lt;/a&gt;
Occasionally we have a set of vectors and we need to determine whether the vectors are linearly independent of each other. This may be necessary to determine if the vectors form a basis, or to determine how many independent equations there are, or to determine how many independent reactions there are.
&lt;/p&gt;

&lt;p&gt;
Reference: Kreysig, Advanced Engineering Mathematics, sec. 7.4
&lt;/p&gt;

&lt;p&gt;
Matlab provides a rank command which gives you the number of singular values greater than some tolerance. The numpy.rank function, unfortunately, does not do that. It returns the number of dimensions in the array. We will just compute the rank from singular value decomposition.
&lt;/p&gt;

&lt;p&gt;
The default tolerance used in Matlab is max(size(A))*eps(norm(A)). Let us break that down. eps(norm(A)) is the positive distance from abs(X) to the next larger in magnitude floating point number of the same precision as X. Basically, the smallest significant number. We multiply that by the size of A, and take the largest number. We have to use some judgment in what the tolerance is, and what &amp;ldquo;zero&amp;rdquo; means.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
v1 = [6, 0, 3, 1, 4, 2];
v2 = [0, -1, 2, 7, 0, 5];
v3 = [12, 3, 0, -19, 8, -11];

A = np.row_stack([v1, v2, v3])

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;matlab definition&lt;/span&gt;
eps = np.finfo(np.linalg.norm(A).dtype).eps
TOLERANCE = &lt;span style="color: #8b0000;"&gt;max&lt;/span&gt;(eps * np.array(A.shape))

U, s, V = np.linalg.svd(A)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; s
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.sum(s &amp;gt; TOLERANCE)

TOLERANCE = 1e-14
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.sum(s &amp;gt; TOLERANCE)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
&amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; ... &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; [  2.75209239e+01   9.30584482e+00   1.42425400e-15]
3
&amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; 2
&lt;/pre&gt;

&lt;p&gt;
You can see if you choose too small a TOLERANCE, nothing looks like zero. the result with TOLERANCE=1e-14 suggests the rows are not linearly independent. Let us show that one row can be expressed as a linear combination of the other rows. 
&lt;/p&gt;

&lt;p&gt;
The number of rows is greater than the rank, so these vectors are not
independent. Let's demonstrate that one vector can be defined as a linear
combination of the other two vectors. Mathematically we represent this
as:
&lt;/p&gt;

&lt;p&gt;
\(x_1 \mathit{v1} + x_2 \mathit{v2} = v3\)
&lt;/p&gt;

&lt;p&gt;
or
&lt;/p&gt;

&lt;p&gt;
\([x_1 x_2][v1; v2] = v3\)
&lt;/p&gt;

&lt;p&gt;
This is not the usual linear algebra form of Ax = b. To get there, we
transpose each side of the equation to get:
&lt;/p&gt;

&lt;p&gt;
[v1.T v2.T][x_1; x_2] = v3.T
&lt;/p&gt;

&lt;p&gt;
which is the form Ax = b. We solve it in a least-squares sense.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;A = np.column_stack([v1, v2])
x = np.linalg.lstsq(A, v3)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; x[0]
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
&amp;gt;&amp;gt;&amp;gt; [ 2. -3.]
&lt;/pre&gt;

&lt;p&gt;
This shows that v3 = 2*v1 - 3*v2
&lt;/p&gt;

&lt;div id="outline-container-1" class="outline-2"&gt;
&lt;h2 id="sec-1"&gt;&lt;span class="section-number-2"&gt;1&lt;/span&gt; another example&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-1"&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;#&lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;Problem set 7.4 #17&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

v1 = [0.2, 1.2, 5.3, 2.8, 1.6]
v2 = [4.3, 3.4, 0.9, 2.0, -4.3]

A = np.row_stack([v1, v2])
U, s, V = np.linalg.svd(A)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; s
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
[ 7.57773162  5.99149259]
&lt;/pre&gt;

&lt;p&gt;
You can tell by inspection the rank is 2 because there are no near-zero singular values. 
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-2" class="outline-2"&gt;
&lt;h2 id="sec-2"&gt;&lt;span class="section-number-2"&gt;2&lt;/span&gt; Near deficient rank&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-2"&gt;
&lt;p&gt;
the rank command roughly works in the following way: the matrix is converted to a reduced row echelon form, and then the number of rows that are not all equal to zero are counted. Matlab uses a tolerance to determine what is equal to zero. If there is uncertainty in the numbers, you may have to define what zero is, e.g. if the absolute value of a number is less than 1e-5, you may consider that close enough to be zero. The default tolerance is usually very small, of order 1e-15. If we believe that any number less than 1e-5 is practically equivalent to zero, we can use that information to compute the rank like this.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

A = [[1, 2, 3],
     [0, 2, 3],
     [0, 0, 1e-6]]

U, s, V = np.linalg.svd(A)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; s
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.sum(np.abs(s) &amp;gt; 1e-15)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.sum(np.abs(s) &amp;gt; 1e-5)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
[  5.14874857e+00   7.00277208e-01   5.54700196e-07]
3
2
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-3" class="outline-2"&gt;
&lt;h2 id="sec-3"&gt;&lt;span class="section-number-2"&gt;3&lt;/span&gt; Application to independent chemical reactions.&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-3"&gt;
&lt;p&gt;
reference: Exercise 2.4 in Chemical Reactor Analysis and Design Fundamentals by Rawlings and Ekerdt.
&lt;/p&gt;

&lt;p&gt;
The following reactions are proposed in the hydrogenation of bromine:
&lt;/p&gt;

&lt;p&gt;
Let this be our species vector: v = [H2 H Br2 Br HBr].T
&lt;/p&gt;

&lt;p&gt;
the reactions are then defined by M*v where M is a stoichometric matrix in which each row represents a reaction with negative stoichiometric coefficients for reactants, and positive stoichiometric coefficients for products. A stoichiometric coefficient of 0 is used for species not participating in the reaction.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

&lt;span style="color: #ff0000; font-weight: bold;"&gt;#    &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;[H2  H Br2 Br HBr]&lt;/span&gt;
M = [[-1,  0, -1,  0,  2],  &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;H2 + Br2 == 2HBR&lt;/span&gt;
     [ 0,  0, -1,  2,  0],  &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;Br2 == 2Br&lt;/span&gt;
     [-1,  1,  0, -1,  1],  &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;Br + H2 == HBr + H&lt;/span&gt;
     [ 0, -1, -1,  1,  1],  &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;H + Br2 == HBr + Br&lt;/span&gt;
     [ 1, -1,  0,  1,  -1], &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;H + HBr == H2 + Br&lt;/span&gt;
     [ 0,  0,  1, -2,  0]]  &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;2Br == Br2&lt;/span&gt;

U, s, V = np.linalg.svd(M)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; s
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.sum(np.abs(s) &amp;gt; 1e-15)

&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; sympy 
M = sympy.Matrix(M)
reduced_form, inds = M.rref()

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; reduced_form

labels = [&lt;span style="color: #228b22;"&gt;'H2'&lt;/span&gt;,  &lt;span style="color: #228b22;"&gt;'H'&lt;/span&gt;, &lt;span style="color: #228b22;"&gt;'Br2'&lt;/span&gt;, &lt;span style="color: #228b22;"&gt;'Br'&lt;/span&gt;, &lt;span style="color: #228b22;"&gt;'HBr'&lt;/span&gt;]
&lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; row &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; reduced_form.tolist():
    s = &lt;span style="color: #228b22;"&gt;'0 = '&lt;/span&gt;
    &lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; nu,species &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;zip&lt;/span&gt;(row,labels):
        &lt;span style="color: #8b0000;"&gt;if&lt;/span&gt; nu != 0:
            
            s += &lt;span style="color: #228b22;"&gt;' {0:+d}{1}'&lt;/span&gt;.format(&lt;span style="color: #8b0000;"&gt;int&lt;/span&gt;(nu), species)
    &lt;span style="color: #8b0000;"&gt;if&lt;/span&gt; s != &lt;span style="color: #228b22;"&gt;'0 = '&lt;/span&gt;: &lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; s
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
[  3.84742803e+00   3.32555975e+00   1.46217301e+00   1.73313660e-16
   8.57422679e-17]
3
[1, 0, 0,  2, -2]
[0, 1, 0,  1, -1]
[0, 0, 1, -2,  0]
[0, 0, 0,  0,  0]
[0, 0, 0,  0,  0]
[0, 0, 0,  0,  0]
0 =  +1H2 +2Br -2HBr
0 =  +1H +1Br -1HBr
0 =  +1Br2 -2Br
&lt;/pre&gt;

&lt;p&gt;
6 reactions are given, but the rank of the matrix is only 3. so there
are only three independent reactions. You can see that reaction 6 is just
the opposite of reaction 2, so it is clearly not independent. Also,
reactions 3 and 5 are just the reverse of each other, so one of them can
also be eliminated. finally, reaction 4 is equal to reaction 1 minus
reaction 3.
&lt;/p&gt;

&lt;p&gt;
There are many possible independent reactions. In the code above, we use sympy to put the matrix into reduced row echelon form, which enables us to identify three independent reactions, and shows that three rows are all zero, i.e. they are not independent of the other three reactions. The choice of independent reactions is not unique.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/03/01/Determining-linear-independence-of-a-set-of-vectors.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Solving linear equations</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/02/27/Solving-linear-equations</link>
      <pubDate>Wed, 27 Feb 2013 13:13:06 EST</pubDate>
      <category><![CDATA[linear algebra]]></category>
      <guid isPermaLink="false">PQGrZU2xBR9CFf7svj1qXI99WCM=</guid>
      <description>Solving linear equations</description>
      <content:encoded><![CDATA[


&lt;p&gt;
Given these equations, find [x1, x2, x3]
&lt;/p&gt;
\begin{eqnarray}
x_1 - x_2 + x_3 &amp;=&amp; 0 \\
10 x_2 + 25 x_3 &amp;=&amp; 90 \\
20 x_1 + 10 x_2 &amp;=&amp; 80
\end{eqnarray}

&lt;p&gt;
reference: Kreysig, Advanced Engineering Mathematics, 9th ed. Sec. 7.3
&lt;/p&gt;

&lt;p&gt;
When solving linear equations, we can represent them in matrix form. The we simply use &lt;code&gt;numpy.linalg.solve&lt;/code&gt; to get the solution.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
A = np.array([[1, -1, 1],
              [0, 10, 25],
              [20, 10, 0]])

b = np.array([0, 90, 80])

x = np.linalg.solve(A, b)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; x
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(A,x)

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;Let us confirm the solution.&lt;/span&gt;
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;this shows one element is not equal because of float tolerance&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(A,x) == b

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;here we use a tolerance comparison to show the differences is less&lt;/span&gt;
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;than a defined tolerance.&lt;/span&gt;
TOLERANCE = 1e-12
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.abs((np.dot(A, x) - b)) &amp;lt;= TOLERANCE
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
[ 2.  4.  2.]
[  2.66453526e-15   9.00000000e+01   8.00000000e+01]
[False  True  True]
[ True  True  True]
&lt;/pre&gt;

&lt;p&gt;
It can be useful to confirm there should be a solution, e.g. that the equations are all independent. The matrix rank will tell us that. Note that numpy:rank does not give you the matrix rank, but rather the number of dimensions of the array. We compute the rank by computing the number of singular values of the matrix that are greater than zero, within a prescribed tolerance. We use the &lt;code&gt;numpy.linalg.svd&lt;/code&gt; function for that. In Matlab you would use the rref command to see if there are any rows that are all zero, but this command does not exist in numpy. That command does not have practical use in numerical linear algebra and has not been implemented.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
A = np.array([[1, -1, 1],
              [0, 10, 25],
              [20, 10, 0]])

b = np.array([0, 90, 80])

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;determine number of independent rows in A we get the singular values&lt;/span&gt;
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;and count the number greater than 0.&lt;/span&gt;
TOLERANCE = 1e-12
u, s, v = np.linalg.svd(A)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'Singular values: {0}'&lt;/span&gt;.format(s)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'# of independent rows: {0}'&lt;/span&gt;.format(np.sum(np.abs(s) &amp;gt; TOLERANCE))

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;to illustrate a case where there are only 2 independent rows&lt;/span&gt;
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;consider this case where row3 = 2*row2.&lt;/span&gt;
A = np.array([[1, -1, 1],
              [0, 10, 25],
              [0, 20, 50]])

u, s, v = np.linalg.svd(A)

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'Singular values: {0}'&lt;/span&gt;.format(s)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'# of independent rows: {0}'&lt;/span&gt;.format(np.sum(np.abs(s) &amp;gt; TOLERANCE))
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
Singular values: [ 27.63016717  21.49453733   1.5996022 ]
# of independent rows: 3
Singular values: [ 60.21055203   1.63994657  -0.        ]
# of independent rows: 2
&lt;/pre&gt;

&lt;p&gt;
&lt;a href="http://matlab.cheme.cmu.edu/2011/08/01/solving-linear-equations/" &gt;Matlab comparison&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/02/27/Solving-linear-equations.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Rules for transposition</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/02/27/Rules-for-transposition</link>
      <pubDate>Wed, 27 Feb 2013 13:12:45 EST</pubDate>
      <category><![CDATA[linear algebra]]></category>
      <guid isPermaLink="false">FJeof2Gi2gk9XC2_UF1yunzWgNg=</guid>
      <description>Rules for transposition</description>
      <content:encoded><![CDATA[


&lt;p&gt;

&lt;a href="http://matlab.cheme.cmu.edu/2011/08/01/illustrating-matrix-transpose-rules-in-matrix-multiplication/" &gt;Matlab comparison&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Here are the four rules for matrix multiplication and transposition
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;\((\mathbf{A}^T)^T = \mathbf{A}\)
&lt;/li&gt;

&lt;li&gt;\((\mathbf{A}+\mathbf{B})^T = \mathbf{A}^T+\mathbf{B}^T\)
&lt;/li&gt;

&lt;li&gt;\((\mathit{c}\mathbf{A})^T = \mathit{c}\mathbf{A}^T\)
&lt;/li&gt;

&lt;li&gt;\((\mathbf{AB})^T = \mathbf{B}^T\mathbf{A}^T\)
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
reference: Chapter 7.2 in Advanced Engineering Mathematics, 9th edition.
by E. Kreyszig.
&lt;/p&gt;

&lt;div id="outline-container-1" class="outline-2"&gt;
&lt;h2 id="sec-1"&gt;&lt;span class="section-number-2"&gt;1&lt;/span&gt; The transpose in Python&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-1"&gt;
&lt;p&gt;
There are two ways to get the transpose of a matrix: with a notation, and
with a function.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
A = np.array([[5, -8, 1],
              [4, 0, 0]])

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;function&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.transpose(A)


&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;notation&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; A.T
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
[[ 5  4]
 [-8  0]
 [ 1  0]]
[[ 5  4]
 [-8  0]
 [ 1  0]]
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-2" class="outline-2"&gt;
&lt;h2 id="sec-2"&gt;&lt;span class="section-number-2"&gt;2&lt;/span&gt; Rule 1&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-2"&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

A = np.array([[5, -8, 1],
              [4, 0, 0]])

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.all(A == (A.T).T)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
True
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-3" class="outline-2"&gt;
&lt;h2 id="sec-3"&gt;&lt;span class="section-number-2"&gt;3&lt;/span&gt; Rule 2&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-3"&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
A = np.array([[5, -8, 1],
              [4, 0, 0]])

B = np.array([[3, 4, 5], [1, 2,3]])

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.all( A.T + B.T == (A + B).T)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
True
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-4" class="outline-2"&gt;
&lt;h2 id="sec-4"&gt;&lt;span class="section-number-2"&gt;4&lt;/span&gt; Rule 3&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-4"&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
A = np.array([[5, -8, 1],
              [4, 0, 0]])

c = 2.1

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.all( (c*A).T == c*A.T)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
True
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-5" class="outline-2"&gt;
&lt;h2 id="sec-5"&gt;&lt;span class="section-number-2"&gt;5&lt;/span&gt; Rule 4&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-5"&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
A = np.array([[5, -8, 1],
              [4, 0, 0]])

B = np.array([[0, 2],
              [1, 2],
              [6, 7]])

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.all(np.dot(A, B).T == np.dot(B.T, A.T))
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
True
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-6" class="outline-2"&gt;
&lt;h2 id="sec-6"&gt;&lt;span class="section-number-2"&gt;6&lt;/span&gt; Summary&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-6"&gt;
&lt;p&gt;
That wraps up showing numerically the transpose rules work for these examples.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/02/27/Rules-for-transposition.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Conservation of mass in chemical reactions</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/02/27/Conservation-of-mass-in-chemical-reactions</link>
      <pubDate>Wed, 27 Feb 2013 10:54:08 EST</pubDate>
      <category><![CDATA[linear algebra]]></category>
      <guid isPermaLink="false">2ODnefiZYh22emOG_OKqU6d3-ns=</guid>
      <description>Conservation of mass in chemical reactions</description>
      <content:encoded><![CDATA[


&lt;p&gt;
&lt;a href="http://matlab.cheme.cmu.edu/2011/12/18/conservation-of-mass-in-chemical-reactions/" &gt;Matlab post&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Atoms cannot be destroyed in non-nuclear chemical reactions, hence it follows that the same number of atoms entering a reactor must also leave the reactor. The atoms may leave the reactor in a different molecular configuration due to the reaction, but the total mass leaving the reactor must be the same. Here we look at a few ways to show this.
&lt;/p&gt;

&lt;p&gt;
We consider the water gas shift reaction : \(CO + H_2O \rightleftharpoons H_2 + CO_2\). We can illustrate the conservation of mass with the following equation: \(\bf{\nu}\bf{M}=\bf{0}\). Where \(\bf{\nu}\) is the stoichiometric coefficient vector and \(\bf{M}\) is a column vector of molecular weights. For simplicity, we use pure isotope molecular weights, and not the isotope-weighted molecular weights. This equation simply examines the mass on the right side of the equation and the mass on left side of the equation. 
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
nu = [-1, -1, 1, 1];
M = [28, 18, 2, 44];
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(nu, M)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
0
&lt;/pre&gt;

&lt;p&gt;
You can see that sum of the stoichiometric coefficients times molecular weights is zero. In other words a CO and H_2O have the same mass as H_2 and CO_2.
&lt;/p&gt;

&lt;p&gt;
For any balanced chemical equation, there are the same number of each kind of atom on each side of the equation. Since the mass of each atom is unchanged with reaction, that means the mass of all the species that are reactants must equal the mass of all the species that are products! Here we look at the number of C, O, and H on each side of the reaction. Now if we add the mass of atoms in the reactants and products, it should sum to zero (since we used the negative sign for stoichiometric coefficients of reactants).
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
            &lt;span style="color: #ff0000; font-weight: bold;"&gt;# C   O   H&lt;/span&gt;
reactants = [-1, -2, -2]
products  = [ 1,  2,  2]

atomic_masses = [12.011, 15.999, 1.0079]  &lt;span style="color: #ff0000; font-weight: bold;"&gt;# atomic masses&lt;/span&gt;

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(reactants, atomic_masses) + np.dot(products, atomic_masses)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
&amp;gt;&amp;gt;&amp;gt; ... &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; &amp;gt;&amp;gt;&amp;gt; 0.0
&lt;/pre&gt;

&lt;p&gt;
That is all there is to mass conservation with reactions. Nothing changes if there are lots of reactions, as long as each reaction is properly balanced, and none of them are nuclear reactions!
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/02/27/Conservation-of-mass-in-chemical-reactions.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Sums products and linear algebra notation - avoiding loops where possible</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/02/26/Sums-products-and-linear-algebra-notation-avoiding-loops-where-possible</link>
      <pubDate>Tue, 26 Feb 2013 09:00:00 EST</pubDate>
      <category><![CDATA[linear algebra]]></category>
      <guid isPermaLink="false">bwZpvktGHtXRQDqcNi0wiN7-e2E=</guid>
      <description>Sums products and linear algebra notation - avoiding loops where possible</description>
      <content:encoded><![CDATA[



&lt;p&gt;
&lt;a href="http://matlab.cheme.cmu.edu/2012/01/03/sums-products-and-linear-algebra-notation-avoiding-loops-where-possible/" &gt;Matlab comparison&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Today we examine some methods of linear algebra that allow us to
avoid writing explicit loops in Matlab for some kinds of
mathematical operations. 
&lt;/p&gt;


&lt;p&gt;
Consider the operation on two vectors \(\bf{a}\)
and \(\bf{b}\).
&lt;/p&gt;


&lt;p&gt;
$$y=\sum\limits_{i=1}^n a_ib_i$$
&lt;/p&gt;

&lt;p&gt;
a = [1 2 3 4 5]
&lt;/p&gt;

&lt;p&gt;
b = [3 6 8 9 10]
&lt;/p&gt;

&lt;div id="outline-container-1" class="outline-2"&gt;
&lt;h2 id="sec-1"&gt;&lt;span class="section-number-2"&gt;1&lt;/span&gt; Old-fashioned way with a loop&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-1"&gt;
&lt;p&gt;
We can compute this with a loop, where you initialize y, and then
 add the product of the ith elements of a and b to y in each
iteration of the loop. This is known to be slow for large vectors
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;a = [1, 2, 3, 4, 5]
b = [3, 6, 8, 9, 10]

&lt;span style="color: #8b0000;"&gt;sum&lt;/span&gt; = 0
&lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; i &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;range&lt;/span&gt;(len(a)):
    &lt;span style="color: #8b0000;"&gt;sum&lt;/span&gt; = &lt;span style="color: #8b0000;"&gt;sum&lt;/span&gt; + a[i] * b[i]
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; sum
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
125
&lt;/pre&gt;

&lt;p&gt;
This is an old fashioned style of coding. A more modern, pythonic approach is:
&lt;/p&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;a = [1, 2, 3, 4, 5]
b = [3, 6, 8, 9, 10]

&lt;span style="color: #8b0000;"&gt;sum&lt;/span&gt; = 0
&lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; x,y &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;zip&lt;/span&gt;(a,b):
    &lt;span style="color: #8b0000;"&gt;sum&lt;/span&gt; += x * y
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; sum
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
125
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-2" class="outline-2"&gt;
&lt;h2 id="sec-2"&gt;&lt;span class="section-number-2"&gt;2&lt;/span&gt; The numpy approach&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-2"&gt;
&lt;p&gt;
The most compact method is to use the  methods in numpy.
&lt;/p&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

a = np.array([1, 2, 3, 4, 5])
b = np.array([3, 6, 8, 9, 10])

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.sum(a * b)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
125
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-3" class="outline-2"&gt;
&lt;h2 id="sec-3"&gt;&lt;span class="section-number-2"&gt;3&lt;/span&gt; Matrix algebra approach.&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-3"&gt;
&lt;p&gt;
The operation defined above is actually a dot product. We an directly compute the dot product in numpy. Note that with 1d arrays, python knows what to do and does not require any transpose operations.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

a = np.array([1, 2, 3, 4, 5])
b = np.array([3, 6, 8, 9, 10])

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(a, b)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
125
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-4" class="outline-2"&gt;
&lt;h2 id="sec-4"&gt;&lt;span class="section-number-2"&gt;4&lt;/span&gt; Another example&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-4"&gt;
&lt;p&gt;
Consider \(y = \sum\limits_{i=1}^n w_i x_i^2\). This operation is like a weighted sum of squares.
The old-fashioned way to do this is with a loop.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;w = [0.1, 0.25, 0.12, 0.45, 0.98];
x = [9, 7, 11, 12, 8];
y = 0
&lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; wi, xi &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;zip&lt;/span&gt;(w,x):
   y += wi * xi**2
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; y
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
162.39
&lt;/pre&gt;

&lt;p&gt;
Compare this to the more modern numpy approach.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
w = np.array([0.1, 0.25, 0.12, 0.45, 0.98])
x = np.array([9, 7, 11, 12, 8])
y = np.sum(w * x**2)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; y
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
162.39
&lt;/pre&gt;

&lt;p&gt;
We can also express this in matrix algebra form. The operation is equivalent to \(y = \vec{x} \cdot D_w \cdot \vec{x}^T\) where \(D_w\) is a diagonal matrix with the weights on the diagonal.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
w = np.array([0.1, 0.25, 0.12, 0.45, 0.98])
x = np.array([9, 7, 11, 12, 8])
y = np.dot(x, np.dot(np.diag(w), x))
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; y
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
162.39
&lt;/pre&gt;

&lt;p&gt;
This last form avoids explicit loops and sums, and relies on fast linear algebra routines.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-5" class="outline-2"&gt;
&lt;h2 id="sec-5"&gt;&lt;span class="section-number-2"&gt;5&lt;/span&gt; Last example&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-5"&gt;
&lt;p&gt;
Consider the sum of the product of three vectors. Let \(y = \sum\limits_{i=1}^n w_i x_i y_i\). This is like a weighted sum of products. 
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

w = np.array([0.1, 0.25, 0.12, 0.45, 0.98])
x = np.array([9, 7, 11, 12, 8])
y = np.array([2, 5, 3, 8, 0])

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.sum(w * x * y)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; np.dot(w, np.dot(np.diag(x), y))
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
57.71
57.71
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id="outline-container-6" class="outline-2"&gt;
&lt;h2 id="sec-6"&gt;&lt;span class="section-number-2"&gt;6&lt;/span&gt; Summary&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-6"&gt;
&lt;p&gt;
We showed examples of the following equalities between traditional
sum notations and linear algebra
&lt;/p&gt;


&lt;p&gt;
$$\bf{a}\bf{b}=\sum\limits_{i=1}^n a_ib_i$$
&lt;/p&gt;

&lt;p&gt;
$$\bf{x}\bf{D_w}\bf{x^T}=\sum\limits_{i=1}^n w_ix_i^2$$
&lt;/p&gt;


&lt;p&gt;
$$\bf{x}\bf{D_w}\bf{y^T}=\sum\limits_{i=1}^n w_i x_i y_i$$
&lt;/p&gt;

&lt;p&gt;
These relationships enable one to write the sums as a single line of
python code, which utilizes fast linear algebra subroutines, avoids
the construction of slow loops, and reduces the opportunity for
errors in the code. Admittedly, it introduces the opportunity for
new types of errors, like using the wrong relationship, or linear
algebra errors due to matrix size mismatches.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/02/26/Sums-products-and-linear-algebra-notation---avoiding-loops-where-possible.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Linear least squares fitting with linear algebra</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/02/18/Linear-least-squares-fitting-with-linear-algebra</link>
      <pubDate>Mon, 18 Feb 2013 09:00:00 EST</pubDate>
      <category><![CDATA[data analysis]]></category>
      <category><![CDATA[linear algebra]]></category>
      <guid isPermaLink="false">pouOC1bSgsp9CbyPQLG4lOITSjw=</guid>
      <description>Linear least squares fitting with linear algebra</description>
      <content:encoded><![CDATA[


&lt;p&gt;
&lt;a href="http://matlab.cheme.cmu.edu/2011/09/24/linear-least-squares-fitting-with-linear-algebra/" &gt;Matlab post&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
The idea here is to formulate a set of linear equations that is easy to solve. We  can express the equations in terms of our unknown fitting parameters \(p_i\) as:
&lt;/p&gt;

&lt;pre class="example"&gt;
x1^0*p0 + x1*p1 = y1
x2^0*p0 + x2*p1 = y2
x3^0*p0 + x3*p1 = y3
etc...
&lt;/pre&gt;

&lt;p&gt;
Which we write in matrix form as \(A p = y\) where \(A\) is a matrix of column vectors, e.g. [1, x_i]. \(A\) is not a square matrix, so we cannot solve it as written. Instead, we form \(A^T A p = A^T y\) and solve that set of equations.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
x = np.array([0, 0.5, 1, 1.5, 2.0, 3.0, 4.0, 6.0, 10])
y = np.array([0, -0.157, -0.315, -0.472, -0.629, -0.942, -1.255, -1.884, -3.147])

A = np.column_stack([x**0, x])

M = np.dot(A.T, A)
b = np.dot(A.T, y)

i1, slope1 = np.dot(np.linalg.inv(M), b)
i2, slope2 = np.linalg.solve(M, b) &lt;span style="color: #ff0000; font-weight: bold;"&gt;# an alternative approach.&lt;/span&gt;

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; i1, slope1
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; i2, slope2

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# plot data and fit&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; plt

plt.plot(x, y, &lt;span style="color: #228b22;"&gt;'bo'&lt;/span&gt;)
plt.plot(x, np.dot(A, [i1, slope1]), &lt;span style="color: #228b22;"&gt;'r--'&lt;/span&gt;)
plt.xlabel(&lt;span style="color: #228b22;"&gt;'x'&lt;/span&gt;)
plt.ylabel(&lt;span style="color: #228b22;"&gt;'y'&lt;/span&gt;)
plt.savefig(&lt;span style="color: #228b22;"&gt;'images/la-line-fit.png'&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
0.00062457337884 -0.3145221843
0.00062457337884 -0.3145221843
&lt;/pre&gt;

&lt;p&gt;&lt;img src="/img/./images/la-line-fit.png"&gt;&lt;p&gt;

&lt;p&gt;
This method can be readily extended to fitting any polynomial model, or other linear model that is fit in a least squares sense. This method does not provide confidence intervals.
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/02/18/Linear-least-squares-fitting-with-linear-algebra.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
  </channel>
</rss>
