<p>Multiplying on the left of right has no relation to the memory layout. Matrices have no notion of memory layout, they are 2D arrays that exist independently of any linearized memory representation. If your memory layout is leaking into your matrix computations then you have a problem.</p>
<p>As far as your main question goes, yes, by transposing both sides you can see
(here I have taken <span class="math-container">$p$</span> and <span class="math-container">$q$</span> to be column vectors):
<span class="math-container">$$q = BAp \iff q^T = p^T A^T B^T.$$</span></p>
<p>Now you may ask why in GLSL this looks rather as follows:</p>
<pre><code>q = B*A*p vs q = p * transpose(A) * transpose(B).
</code></pre>
<p>The answer is that <span class="math-container">$p$</span> and <span class="math-container">$q$</span> are not really treated as column or
row vectors, but rather they get reinterpreted as those whenever
it is convenient in order to carry out the matrix-vector multiplication.
E.g. in <code>A*p</code>, <code>p</code> gets interpreted as a column vector,
while in <code>p*transpose(A)</code> it gets interpreted as a row vector.</p>
<p>However I kind of doubt that you want <span class="math-container">$q = SRTp$</span>. Typically people want <span class="math-container">$q=TRSp$</span> or respectively <span class="math-container">$q^T = p^TS^TR^TT^T$</span>, since they want scaling to be applied around the origin and along the main axes, then rotation to be applied around the origin, and finally translation to be applied. Of course it may also make sense to have <span class="math-container">$q=T_gRT_lSp$</span>, where <span class="math-container">$T_g$</span> is a global offset with respect to the global coordinate axes, while <span class="math-container">$T_l$</span> is an offset w.r.t. the orientation given by <span class="math-container">$R$</span>, e.g., if you want the point <span class="math-container">$p$</span> to move along where it is &quot;looking&quot; according to <span class="math-container">$R$</span> you would have a <span class="math-container">$T_l$</span> with a translation vector e.g. <span class="math-container">$(0,0,1)$</span> if <span class="math-container">$+Z$</span> is forward for you.</p>
<hr />
<p><strong>Matrix-Vector and Vector-Matrix Multiplication</strong></p>
<p>Given <span class="math-container">$A\in\mathbb{R}^{m\times n}$</span> and <span class="math-container">$B\in\mathbb{R}^{n\times o}$</span> the matrix
product <span class="math-container">$AB = C\in\mathbb{R}^{m\times o}$</span> is defined as follows:
<span class="math-container">$$C_{ij} = \sum_{k=1}^n A_{ik} B_{kj}, \quad 1\leq i \leq m, \quad 1\leq j \leq n.$$</span></p>
<p>In the special case when <span class="math-container">$o=1$</span>, <span class="math-container">$B\in\mathbb{R}^{n\times 1}$</span> is known as a
column vector (<strong>a column vector is a matrix</strong>), and then <span class="math-container">$C\in\mathbb{R}^{m\times 1}$</span> is also a column vector.
Vice versa, if <span class="math-container">$m=1$</span> then <span class="math-container">$A\in\mathbb{R}^{1\times n}$</span> is a row vector
(<strong>a row vector is a matrix</strong>) and <span class="math-container">$C\in\mathbb{R}^{1\times o}$</span>
is also a row vector.</p>
<p>Note that a vector <span class="math-container">$x\in\mathbb{R}^n$</span> is technically neither, since it is
not a <span class="math-container">$n\times 1$</span> or a <span class="math-container">$1\times n$</span> matrix, which would have indicated whether
it is a row or column.
But often in mathematics, physics, engineering, etc., the coordinates
of contravariant vectors are identified with column vectors, while the
coordinates of covariant vectors are identified with row vectors.
This generally means that one prefers <span class="math-container">$Mx$</span> for geometric transformations
as opposed to <span class="math-container">$xM^T$</span>.</p>
<p>In GLSL a vector <code>vecn x;</code> models an element <span class="math-container">$x\in\mathbb{R}^n$</span>. As such it
is neither a row vector nor a column vector. If you multiply an <span class="math-container">$m\times n$</span>
matrix <span class="math-container">$M$</span> with <span class="math-container">$x$</span> on the right <span class="math-container">$Mx$</span>, you can think of it as <span class="math-container">$x\in\mathbb{R}^n$</span> getting promoted to a column vector <span class="math-container">$\tilde{x}\in\mathbb{R}^{n\times 1}$</span>
in order to carry out the matrix-matrix multiplication <span class="math-container">$M\tilde{x}$</span>
using the matrix product rule, before you store the resulting
column vector <span class="math-container">$\tilde{y}\in\mathbb{R}^{m\times 1}$</span> as a vector <span class="math-container">$y\in\mathbb{R}^m$</span>:</p>
<p><span class="math-container">$$Mx \stackrel{x\in\mathbb{R}^n\mapsto \tilde{x}\in\mathbb{R}^{n\times 1}}{\longrightarrow} 
M\tilde{x} = \tilde{y} 
\stackrel{\tilde{y}\in\mathbb{R}^{m\times 1}\mapsto y\in\mathbb{R}^m}{\longrightarrow} 
Mx = y.$$</span></p>
<p>Vice versa, let <span class="math-container">$u\in\mathbb{R}^m$</span>,
then <span class="math-container">$uM = v\in\mathbb{R}^n$</span> has you promote <span class="math-container">$u\in\mathbb{R}^m$</span> to a row
vector <span class="math-container">$\tilde{u}^T\in\mathbb{R}^{1\times m}$</span>, multiplying
by <span class="math-container">$M$</span>, which results in a row vector <span class="math-container">$\tilde{v}^T\in\mathbb{R}^{1\times n}$</span>, and then converting back to a vector <span class="math-container">$v\in\mathbb{R}^n$</span>.</p>
<p><span class="math-container">$$uM \stackrel{u\in\mathbb{R}^m\mapsto \tilde{u}^T\in\mathbb{R}^{1\times m}}{\longrightarrow} 
\tilde{u}^TM = \tilde{v}^T
\stackrel{\tilde{v}^T\in\mathbb{R}^{1\times n}\mapsto v\in\mathbb{R}^m}{\longrightarrow} 
uM = v.$$</span></p>
<p>In mathematics people virtually everywhere use column vectors, and do not
write any tilde even when they use the same symbol to refer to both
the vector and its column vector representation. So you would see
<span class="math-container">$y = Mx$</span> and <span class="math-container">$u^TM = v^T$</span> typically. <span class="math-container">$uM=v$</span> will be generally deemed undefined
unless <span class="math-container">$M\in\mathbb{R}^{1\times n}$</span>, since <span class="math-container">$u$</span> would typically be interpreted
as a column vector, and not a row vector. Instead <span class="math-container">$u^T$</span> is typically used to
denote a row vector. That said, remember that the <span class="math-container">$^T$</span> is lost in your GLSL code,
at least when it comes to vectors.</p>
<hr />
<p><strong>Transformations</strong></p>
<p>Now consider a point <span class="math-container">$p\in\mathbb{R}^{4\times 1}$</span> in homogeneous coordinates: <span class="math-container">$\begin{bmatrix} p_x &amp; p_y &amp; p_z &amp; 1\end{bmatrix}^T$</span>. If we want to translate it with a vector <span class="math-container">$t\in\mathbb{R}^3$</span>, we could multiply it from the left with a translation matrix as follows:</p>
<p><span class="math-container">\begin{equation*}
q= T_tp = \begin{bmatrix} 
1 &amp; 0 &amp; 0 &amp; t_x \\
0 &amp; 1 &amp; 0 &amp; t_y \\
0 &amp; 0 &amp; 1 &amp; t_z \\
0 &amp; 0 &amp; 0 &amp; 1 \end{bmatrix}
\begin{bmatrix}
p_x \\ p_y \\ p_z \\ 1 \end{bmatrix} =
\begin{bmatrix}
p_x + t_x \\ p_y + t_y \\ p_z + t_z \\ 1 
\end{bmatrix}
\end{equation*}</span></p>
<p>If we wanted to achieve the same but treating <span class="math-container">$p$</span> as a row vector, we would need the transposed of said matrix as you observed:</p>
<p><span class="math-container">\begin{equation*}
q^T = p^TT_t^T = 
\begin{bmatrix}
p_x &amp; p_y &amp; p_z &amp; 1 \end{bmatrix} =
\begin{bmatrix} 
1 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; 1 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 1 &amp; 0 \\
t_x &amp; t_y &amp; t_z &amp; 1 
\end{bmatrix}
= \begin{bmatrix}
p_x + t_x &amp; p_y + t_y &amp; p_z + t_z &amp; 1 
\end{bmatrix}.
\end{equation*}</span></p>
<p>Thus if in your code you had <code>q = B * A * p</code> then this is equivalent to
<code>q = p * transpose(B * A) = p * transpose(A) * transpose(B).</code></p>
<hr />
<hr />
<h2><strong>Rant regarding GLSL's &quot;Column-Major&quot; Matrices</strong></h2>
<hr />
<hr />
<p><strong>Definition of Column-Major and Row-Major Arrays</strong></p>
<p>Suppose I have a <span class="math-container">$2\times 3$</span> array (I have indexed it from 0 for convenience since that's what GLSL uses)</p>
<p><span class="math-container">\begin{equation*}
M = \begin{bmatrix}
M(0,0) &amp; M(0,1) &amp; M(0,2) \\
M(1,0) &amp; M(1,1) &amp; M(1,2)
\end{bmatrix}.
\end{equation*}</span></p>
<p>Then if I order the elements so that the entries in the rows are consecutive we call that a row-major layout:
<span class="math-container">\begin{equation*}
M_{row} = (M(0,0), M(0,1), M(0,2), M(1,0), M(1,1), M(1,2)).
\end{equation*}</span></p>
<p>For the row-major version above the map for the indexing for a <span class="math-container">$m\times n$</span> matrix is <span class="math-container">$\textrm{idx_row_maj}(i,j)\mapsto i\cdot n + j$</span>. Vice versa, if you had the index <span class="math-container">$k$</span> of an element in <span class="math-container">$M_{row}$</span> and wanted to find its indices in the array you could use <span class="math-container">$\textrm{idx_row_maj}^{-1}(k) = (k/n, k\%n)$</span>, where the division is integer division and <span class="math-container">$k\%n = k -  (k/n) * n$</span>.</p>
<p>If I order the elements so that the entries in the columns are consecutive we call that a column-major layout:
<span class="math-container">\begin{equation*}
M_{col} = (M(0,0), M(1,0), M(0,1), M(1,1), M(0,2), M(1,2)).
\end{equation*}</span></p>
<p>For the column-major version above the map for the indexing for a <span class="math-container">$m\times n$</span> matrix is <span class="math-container">$\textrm{idx_col_maj}(i,j)\mapsto i + j\cdot m$</span>. Vice versa, if you had the index <span class="math-container">$k$</span> of an element in <span class="math-container">$M_{col}$</span> and wanted to find its indices in the array you could use <span class="math-container">$\textrm{idx_col_maj}^{-1}(k) = (k\%m, k/m)$</span>, where the division is integer division and <span class="math-container">$k\%m = k -  (k/m) * m$</span>.</p>
<p>This means that having an array I can store it in memory in any of the layouts I want (or in neither, if I take some other order). That was the case where I have some array and I need to put it in memory. But what if I have some memory, and I need to figure out what the array is? Typically in code this is made clear by the syntax for the access to the elements. I illustrate this below with some code.</p>
<p>Suppose I have the following 2D array-like structures in C++:</p>
<pre class="lang-cpp prettyprint-override"><code>template&lt;int m, int n&gt;
struct matA
{
float e[m*n];
float&amp; operator()(int i, int j) { return e[i*n + j]; }
};

template&lt;int m, int n&gt;
struct matB
{
float e[m*n];
float&amp; operator()(int i, int j) { return e[i + j*m]; }
};
</code></pre>
<p>From the maps above <span class="math-container">$(i,j)\mapsto i\cdot n +j$</span> for <code>matA</code> and <span class="math-container">$(i,j)\mapsto i+j\cdot m$</span> for <code>matB</code> you can figure out that the first is meant to represent an array with row-major memory layout, while the second represents an array with column-major memory layout. Of course, <code>float e[m*n]</code> is just memory, and I could technically take any array with at most <span class="math-container">$mn$</span> elements and shove it in the <code>A.e</code> belonging to <code>matA&lt;m,n&gt; A;</code> in whatever order I wish, while ignoring the <code>operator()</code> definition. The main issue then, is that the accessor <span class="math-container">$(i,j)\mapsto i\cdot n  + j$</span> would be misleading you to believe that the array is in row-major layout and that it is of size <span class="math-container">$m\times n$</span>, while it could have been anything.</p>
<p>And here's the nasty part - GLSL's <code>matnxm M;</code> array behaves like matA, i.e. like a row-major array, where <code>M[i][j]</code> and <code>M[i][j+1]</code> are consecutive in memory, while <code>M[i][j]</code> and <code>M[i+1][j]</code> are not. However, you are supposed to shove an <span class="math-container">$m\times n$</span> (note <code>matnxm</code> but the matrix is <code>m\times n</code>) matrix in it in column-major memory layout, and then <code>M[i][j]</code> denotes the <span class="math-container">$i$</span>-th <strong>column</strong> and <span class="math-container">$j$</span>-th <strong>row</strong> of said matrix. That is, everything is reversed.</p>
<hr />
<p><strong>Why this Happened and How to Deal with It</strong></p>
<hr />
<p>In the previous I mentioned that</p>
<blockquote>
<p>you are supposed to shove an <span class="math-container">$m\times n$</span> (note <code>matnxm</code> but
the matrix is <code>m\times n</code>) matrix in it in column-major memory layout</p>
</blockquote>
<p>Technically you don't have to, but with the way the matrix multiplication was defined in GLSL, you have to do it like this if you want to make use of the matrix multiplication in a sane manner. The issue becomes apparent if you try to multiply e.g. a <code>mat2x3 A;</code> with a <code>mat3x4 B;</code>. If you try this, you get an error, but the product <span class="math-container">$C=AB\in\mathbb{R}^{2\times 4}$</span> is  supposed to be perfectly well-defined mathematically for <span class="math-container">$A\in\mathbb{R}^{2\times 3}$</span> and <span class="math-container">$B\in\mathbb{R}^{3\times 4}$</span>. The trick is that GLSL defined the matrix multiplication with the indices flipped, so you actually can only compute <code>mat2x4 C=B*A</code>. If you want for this to make sense you have to assume that <code>mat2x3 A</code> is actually some matrix <span class="math-container">$\tilde{A}\in\mathbb{R}^{3\times 2}$</span>, with the caveat that <span class="math-container">$A(i,j) = \tilde{A}(j,i)$</span>. Similarly one can argue <code>mat3x4 B</code> is actually a matrix <span class="math-container">$\tilde{B}\in\mathbb{R}^{4\times 3}$</span>, then <code>mat2x4 C=B*A;</code> is <span class="math-container">$\tilde{C}=\tilde{B}\tilde{A}\in\mathbb{R}^{4\times 2}$</span>.</p>
<p>Then if you keep in mind that a <span class="math-container">$m\times n$</span> matrix is <code>matnxm</code> and that <code>A[j][i]</code> is really <span class="math-container">$\tilde{A}(i,j)$</span>, then you can cope with this.</p>
<p>The reasons as to why this happened are <a href="https://en.wikipedia.org/wiki/Row-_and_column-major_order#External_libraries" rel="nofollow noreferrer">described in wikipedia</a>. But it essentially boils down to mistakes. The effect also hasn't been good overall:</p>
<blockquote>
<p>As a result, many developers will now simply declare that having the
column as the first index is the definition of column-major, even
though this is clearly not the case with a real column-major language
like Fortran.</p>
</blockquote>
<p>There are many ways that this could be addressed, but they would break backwards compatibility. Clearly calling an <span class="math-container">$m\times n$</span> matrix <code>matnxm</code> has to go, this is pretty egregious. And also having the accessor be such that <code>A[j][i]</code> is <span class="math-container">$\tilde{A}(i,j)$</span> can likely be addressed by just introducing an accessor <code>A(i,j)</code> such that <code>A(i,j) = A[j][i]</code>. Then one could interpret <code>A[j][i]</code> just as a column-major internal representation. Here's some pseudocode illustrating how simple this idea is:</p>
<pre class="lang-cpp prettyprint-override"><code>struct matmxn_glsl_fixed
{
matnxm e;
float&amp; operator()(int i, int j) {return e[j][i];}
vecn&amp; col()(int j) {return e[j];}
// potentially can be kept, but may be confusing:
vecn&amp; operator[](int j) {return this-&gt;col(j);}
};
</code></pre>
<p>The other option relies on actually fixing the matrix multiplication to be the proper one. Then <code>matmxn A;</code> could work perfectly well as a row-major representation of a matrix, and there would be no issues whatsoever. There <code>A[i]</code> would return the <span class="math-container">$i$</span>-th row as expected. One could of course fix the multiplication and change <code>matmxn A</code> to work as a column-major array like in Fortran, i.e., that <code>A(i,j)</code> and <code>A(i+1,j)</code> are consecutive elements and that <code>A(i,j)</code> and <code>A(i,j+1)</code> are not consecutive for <span class="math-container">$m&gt;1$</span>. Moreover if we want to extract the <span class="math-container">$j$</span>-th column, again Fortran's syntax <code>A(:,j)</code> could be used (but not <code>A[j]</code>). One could even create proxy objects so that <code>A(i,:)</code> is well-defined even if the memory is non-consecutive.</p>
<hr />
<p><strong>Simple C++ Example</strong></p>
<hr />
<p>There are of course some efficiency related implementation details related to mainly SIMD that depend on the memory layout. Below you can find the general idea of how these can be implemented (one could unroll the loops, use SIMD for the <code>dot</code>, fmas for the linear combination of the vectors, etc.). It will not compile as I have written it currently (and there may be small typos here and there).</p>
<pre class="lang-cpp prettyprint-override"><code>
template&lt;typename T, int n&gt;
struct vec
{
T e[n];
T&amp; operator[](int i){return e[i];}
const T&amp; operator[](int i) const {return e[i];}
};

template&lt;typename T, int n&gt;
vec&lt;T,n&gt; operator+(const vec&lt;T,n&gt;&amp; l, const vec&lt;T,n&gt;&amp; r)
{
vec&lt;T,n&gt; res;
for (int i=0; i&lt;n; ++i)
  res[i] = l[i] + r[i];
return res;
}

template&lt;typename T, int n&gt;
vec&lt;T,n&gt; operator*(const T&amp; l, const vec&lt;T, n&gt;&amp; r)
{
vec&lt;T,n&gt; res;
for (int i=0; i&lt;n; ++i)
  res[i] = l*r[i];
return res;
}

// in the unlikely scenario your mult does not commute 
// e.g. vectors with entries that are quaternions
template&lt;typename T, int n&gt;
vec&lt;T,n&gt; operator*(const vec&lt;T, n&gt;&amp; l, const T&amp; r)
{
vec&lt;T,n&gt; res;
for (int i=0; i&lt;n; ++i)
  res[i] = l[i]*r;
return res;
}

template&lt;typename T, int n&gt;
T dot(const vec&lt;T, n&gt;&amp; l, const vec&lt;T, n&gt;&amp; r)
{
T res = l[0]*r[0];
for (int i=1; i&lt;n; ++i)
  res += l[i]*r[i];
return res;
}

// row-major matrix
template&lt;typename T, int m, int n&gt;
struct mat_row
{
vec&lt;vec&lt;T,n&gt;,m&gt; e;
// returns the i-th row
vec&lt;T,n&gt;&amp; row(int i){return e[i];}
const vec&lt;T,n&gt;&amp; row(int i) const {return e[i];}
T&amp; operator()(int i, int j){return e[i][j];}
const T&amp; operator()(int i, int j) const {return e[i][j];}
}

// column-major matrix
template&lt;typename T, int m, int n&gt;
struct mat_col
{
vec&lt;vec&lt;T,m&gt;,n&gt; e;
// returns the j-th column
vec&lt;T,m&gt;&amp; col(int j){return e[j];}
const vec&lt;T,m&gt;&amp; col(int j) const {return e[j];}
T&amp; operator()(int i, int j){return e[j][i];}
const T&amp; operator()(int i, int j) const {return e[j][i];}
}

// matrix-vector mult row-major
//       [  -- l.row(0) --  ]       [ dot(l.row(0), r)   ]
// l*r = [      ...         ] * r = [      ...           ]
//       [ -- l.row(m-1) -- ]       [ dot(l.row(m-1), r) ]
template&lt;typename T, int m, int n&gt;
vec&lt;T,m&gt; operator*(const mat_row&lt;T,m,n&gt;&amp; l, const vec&lt;T,n&gt;&amp; r)
{
vec&lt;T, m&gt; res;
for (int i=0; i&lt;m; ++i)
  res[i] = dot(l.row(i), r);
return res;
}

// matrix-vector mult col-major
//       [   |               |      ]   [  r[0]  ]
// l*r = [ l.col(0)  ...  l.col(n-1)] * [   ...  ] 
//       [   |               |      ]   [ r[n-1] ]
//
//     = l.col[0] * r[0] + ... + l.col[n-1] * r[n-1]
template&lt;typename T, int m, int n&gt;
vec&lt;T,m&gt; operator*(const mat_col&lt;T,m,n&gt;&amp; l, const vec&lt;T,n&gt;&amp; r)
{
vec&lt;T, m&gt; res = l.col(0) * r[0];
for (int j=1; j&lt;n; ++j)
  res += l.col(j) * r[j];
return res;
}

// vector-matrix mult row-major
//                               [  -- r.row(0) --  ]
// l*r = [ l[0]  ...  l[m-1] ] * [      ...         ] 
//                               [ -- r.row(m-1) -- ]
//
//     = l[0] * r.row[0] + ... + l[m-1] * r.row[m-1]
template&lt;typename T, int m, int n&gt;
vec&lt;T,n&gt; operator*(const vec&lt;T,m&gt;&amp; l, const mat_row&lt;T,m,n&gt;&amp; r)
{
vec&lt;T, n&gt; res = l[0] * r.row(0);
for (int i=1; i&lt;m; ++i)
  res += l[i] * r.row(i);
return res;
}

// vector-matrix mult col-major
//           [    |            |        ] 
// l*r = l * [ r.col(0)  ... l.col(n-1) ]
//           [    |            |        ]
//  
//     = [ dot(l, r.col(0))  ...  dot(l,r.col(n-1)) ]
template&lt;typename T, int m, int n&gt;
vec&lt;T,n&gt; operator*(const vec&lt;T,m&gt;&amp; l, const mat_col&lt;T,m,n&gt;&amp; r)
{
vec&lt;T, n&gt; res;
for (int j=0; j&lt;n; ++j)
  res[j] = dot(l, r.col(j));
return res;
}

/* The Basic Matrix Mults */

// matrix-matrix mult: row-major * row-major = row-major
//       [  -- l.row(0) --  ]       [  -- l.row(0) * r --  ]
// l*r = [       ...        ] * r = [         ...          ]
//       [ -- l.row(m-1) -- ]       [ -- l.row(m-1) * r -- ]
// reuses row-major vector-matrix mult
template&lt;typename T, int m, int k, int n&gt;
mat_row&lt;T,m,n&gt; operator*(const mat_row&lt;T,m,k&gt;&amp; l, const mat_row&lt;T,k,n&gt;&amp; r)
{
mat_row&lt;T,m,n&gt; res;
for (int i=0; i&lt;m; ++i)
  res.row(i) = l.row(i) * r;
return res;
}

// matrix-matrix mult: col-major * col-major = col-major
//           [    |             |      ]   [    |                 |      ]
// l*r = l * [ r.col(0) ... r.col(n-1) ] = [ l*r.col(0) ... l*r.col(n-1) ]
//           [    |             |      ]   [    |                 |      ]
// reuses col-major matrix-vector mult
template&lt;typename T, int m, int k, int n&gt;
mat_col&lt;T,m,n&gt; operator*(const mat_col&lt;T,m,k&gt;&amp; l, const mat_col&lt;T,k,n&gt;&amp; r)
{
mat_col&lt;T,m,n&gt; res;
for (int j=0; j&lt;n; ++j)
  res.col(j) = l * r.col(j)
return res;
}

/* row-major * col-major - c++ can't differentiate based on return type alone though */

// matrix-matrix mult: row-major * col-major = row_major
//       [  -- l.row(0) --  ]       [  -- l.row(0) * r --  ]
// l*r = [       ...        ] * r = [         ...          ]
//       [ -- l.row(m-1) -- ]       [ -- l.row(m-1) * r -- ]
// reuses col-major vector-matrix mult
template&lt;typename T, int m, int k, int n&gt;
mat_row&lt;T,m,n&gt; operator*(const mat_row&lt;T,m,k&gt;&amp; l, const mat_col&lt;T,k,n&gt;&amp; r)
{
mat_row&lt;T,m,n&gt; res;
for (int i=0; i&lt;m; ++i)
  res.row(i) = l.row(i) * r;
return res;
}

// matrix-matrix mult: row-major * col-major = col-major
//           [    |             |      ]   [    |                 |      ]
// l*r = l * [ r.col(0) ... r.col(n-1) ] = [ l*r.col(0) ... l*r.col(n-1) ]
//           [    |             |      ]   [    |                 |      ]
// reuses row-major matrix-vector mult
template&lt;typename T, int m, int k, int n&gt;
mat_col&lt;T,m,n&gt; operator*(const mat_row&lt;T,m,k&gt;&amp; l, const mat_col&lt;T,k,n&gt;&amp; r)
{
mat_col&lt;T,m,n&gt; res;
for (int j=0; j&lt;n; ++j)
  res.col(j) = l * r.col(j)
return res;
}

/* The Nasty Stuff (I doubt this is actually very efficient, it's just elegant) */
// note: c++ cannot differentiate based on return type only

// tensor product producing a row-major matrix
//       [  l[0]  ]       [  -- l[0] * r --  ]
// lxr = [  ...   ] x r = [       ...        ]
//       [ l[m-1] ]       [ -- l[m-1] * r -- ]
template&lt;typename T, int m, int n&gt;
mat_row&lt;T,m,n&gt; tensor_row(const vec&lt;T,m&gt;&amp; l, const vec&lt;T,n&gt;&amp; r)
{
mat_row&lt;T,m,n&gt; res;
for (int i=0; i&lt;m; ++i)
  res[i] = l[i] * r;
return res;
}

template&lt;typename T, int m, int n&gt;
mat_row&lt;T,m,n&gt; operator+(const mat_row&lt;T,m,n&gt;&amp; l, const mat_row&lt;T,m,n&gt;&amp; r)
{
mat_row&lt;T,m,n&gt; res;
for (int i=0; i&lt;m; ++i)
  res.row(i) = l.row(i) + r.row(i);
return res;
}

// matrix-matrix mult: col-major * row-major = row_major      
// l*r = l.col(0) x r.row(0) + ... + l.col(k-1) x r.row(k-1)
// uses tensor product resulting in a row-major matrix
template&lt;typename T, int m, int p, int n&gt;
mat_row&lt;T,m,n&gt; operator*(const mat_col&lt;T,m,p&gt;&amp; l, const mat_row&lt;T,p,n&gt;&amp; r)
{
mat_row&lt;T,m,n&gt; res = tensor_row(l.col(0), r.row(0));
for (int k=1; k&lt;p; ++k)
  res +=  tensor_row(l.col(k), r.row(k));
return res;
}

// tensor product producing a col-major matrix
//                                 [  |               |    ]
// lxr = l x [ r[0] ... r[n-1] ] = [ l*r[0]  ...  l*r[n-1] ]
//                                 [  |               |    ]
template&lt;typename T, int m, int n&gt;
mat_col&lt;T,m,n&gt; tensor_col(const vec&lt;T,m&gt;&amp; l, const vec&lt;T,n&gt;&amp; r)
{
mat_col&lt;T,m,n&gt; res;
for (int j=0; j&lt;n; ++j)
  res[j] = l * r[j];
return res;
}

template&lt;typename T, int m, int n&gt;
mat_col&lt;T,m,n&gt; operator+(const mat_col&lt;T,m,n&gt;&amp; l, const mat_col&lt;T,m,n&gt;&amp; r)
{
mat_col&lt;T,m,n&gt; res;
for (int j=0; j&lt;n; ++j)
  res.col(j) = l.col(j) + r.col(j);
return res;
}

// matrix-matrix mult: col-major * row-major = col_major      
// l*r = l.col(0) x r.row(0) + ... + l.col(k-1) x r.row(k-1)
// uses tensor product resulting in a col-major matrix
template&lt;typename T, int m, int p, int n&gt;
mat_col&lt;T,m,n&gt; operator*(const mat_col&lt;T,m,p&gt;&amp; l, const mat_row&lt;T,p,n&gt;&amp; r)
{
mat_col&lt;T,m,n&gt; res = tensor_col(l.col(0), r.row(0));
for (int k=1; k&lt;p; ++k)
  res +=  tensor_col(l.col(k), r.row(k));
return res;
}
</code></pre>
<p>The various matrix-vector, vector-matrix, and matrix-matrix multiplications above are based off the following properties. Let <span class="math-container">$A\in\mathbb{R}^{m\times n}$</span>, and let <span class="math-container">$A^i$</span> denote the <span class="math-container">$i$</span>-th row of <span class="math-container">$A$</span> (as a row vector),<span class="math-container">$A_j$</span> denote the <span class="math-container">$j$</span>-th column of <span class="math-container">$A$</span> (as a column vector), <span class="math-container">$v^i$</span> denote the <span class="math-container">$i$</span>-th coordinate of <span class="math-container">$v\in\mathbb{R}^{n\times 1}$</span>, and <span class="math-container">$w_j$</span> denote the <span class="math-container">$j$</span>-th coordinate of <span class="math-container">$w^T\in\mathbb{R}^{1\times m}$</span>, then one can compute the matrix-vector products in various ways:
<span class="math-container">\begin{align}
Av &amp;= 
\begin{bmatrix} - A^1 - \\ \vdots \\ - A^m - \end{bmatrix} v = 
\begin{bmatrix} (A^1)^T \cdot v \\ \vdots \\ (A^m)^T \cdot v\end{bmatrix} \tag{1}  \\
Av &amp;=\begin{bmatrix} | &amp; &amp; | \\ A_1 &amp; \ldots &amp; A_n \\ | &amp; &amp; | \end{bmatrix}v = A_1 v^1 + \ldots + A_n v^n \tag{2} \\
w^TA &amp;= \begin{bmatrix} w_1 &amp; \ldots &amp; w_m \end{bmatrix}\begin{bmatrix} - A^1 - \\ \vdots \\ - A^m - \end{bmatrix} = w_1 A^1 + \ldots w_m A^m \tag{3} \\
w^TA &amp;= w^T \begin{bmatrix} | &amp; &amp; | \\ A_1 &amp; \ldots &amp; A_n \\ | &amp; &amp; | \end{bmatrix} = 
\begin{bmatrix} w\cdot A_1 &amp; \ldots &amp; w\cdot A_n \end{bmatrix} \tag{4}
\end{align}</span></p>
<p>The above computation can be reused to compute matrix-matrix products. Let <span class="math-container">$A\in\mathbb{R}^{m\times p}$</span> and <span class="math-container">$B\in\mathbb{R}^{p\times n}$</span>, and <span class="math-container">$AB=C\in\mathbb{R}^{m\times n}$</span>. We can compute the latter product in multiple ways:
<span class="math-container">\begin{align}
AB &amp;= A \begin{bmatrix} | &amp; &amp; | \\ B_1 &amp; \ldots &amp; B_n \\ | &amp; &amp; | \end{bmatrix} 
\stackrel{(1,2)}{=} \begin{bmatrix} | &amp; &amp; | \\ AB_1 &amp; \ldots &amp; AB_n \\ | &amp; &amp; | \end{bmatrix} \\
AB &amp;= \begin{bmatrix} - A^1 - \\ \vdots \\ - A^m - \end{bmatrix}B \stackrel{(3,4)}{=} 
\begin{bmatrix} - (A^1B) - \\ \vdots \\ - (A^m B) - \end{bmatrix} \\
AB &amp;= \begin{bmatrix} | &amp; &amp; | \\ A_1 &amp; \ldots &amp; A_p \\ | &amp; &amp; | \end{bmatrix} \begin{bmatrix} - B^1 - \\ \vdots \\ - B^p -\end{bmatrix} =
A_1 \otimes (B^1)^T + \ldots + A_p \otimes (B^p)^T,
\end{align}</span>
where <span class="math-container">$\otimes$</span> is the outer or tensor product of two vectors, it is equal to the matrix product when you make the first vector a column vector and the second a row vector. Let <span class="math-container">$v^T\in\mathbb{R}^{1\times n}$</span> and <span class="math-container">$w\in\mathbb{R}^{m\times 1}$</span> then
<span class="math-container">\begin{align*}
w\otimes v &amp;= w v^T = \begin{bmatrix} w^1 \\ \vdots \\ w^m \end{bmatrix} v^T =  
\begin{bmatrix} - w^1 v^T - \\ \vdots \\ - w^m v^T - \end{bmatrix} 
= \begin{bmatrix} w^1v_1 &amp; \ldots &amp; w^1 v_n \\ \vdots &amp; &amp; \vdots \\
w^m v_1 &amp; \ldots &amp; w^m v_n \end{bmatrix},
\\
w\otimes v &amp;= w v^T = w \begin{bmatrix} v_1 &amp; \ldots &amp; v_n \end{bmatrix}  
= \begin{bmatrix} | &amp; &amp; | \\ 
w v_1 &amp;  \ldots &amp; w v_n \\ | &amp; &amp; | \end{bmatrix}  =
\begin{bmatrix} w^1v_1 &amp; \ldots &amp; w^1 v_n \\ \vdots &amp; &amp; \vdots \\
w^m v_1 &amp; \ldots &amp; w^m v_n \end{bmatrix}.
\end{align*}</span></p>
<p>You will notice that the following two cases (row-major <span class="math-container">$\times$</span> row-major = column-major and column-major <span class="math-container">$\times$</span> column-major = row-major) are missing:
<span class="math-container">\begin{align*}
AB &amp;= \begin{bmatrix} - A^1 - \\ \vdots \\ - A^m - \end{bmatrix}
\begin{bmatrix} - B^1 - \\ \vdots \\  - B^p - \end{bmatrix}
= \begin{bmatrix} | &amp; &amp; | \\ C_1 &amp; \ldots &amp; C_n \\ | &amp; &amp; | \end{bmatrix},
\\
AB &amp;= \begin{bmatrix} | &amp; &amp; | \\ A_1 &amp; \ldots &amp; A_p \\ | &amp; &amp; | \end{bmatrix}
\begin{bmatrix} | &amp; &amp; | \\ B_1 &amp; \ldots &amp; B_n \\ | &amp; &amp; |\end{bmatrix}
= \begin{bmatrix} - C^1 - \\ \vdots \\ - C^m - \end{bmatrix}.
\end{align*}</span>
As far as I am aware there is no nice way to vectorize these two while respecting the memory continuity. You're probably best off computing row-major <span class="math-container">$\times$</span> row-major and producing a row-major matrix, and then transposing to get col-major. Similarly for col-major <span class="math-container">$\times$</span> col-major = row-major.</p>

CC BY-SA 4.0
2024-10-29T19:15:58.323Z
2024-10-29T20:22:13.080Z
2024-10-29T20:22:13.080Z
lightxbulb
<p>I was going to do a bunch of fancy matrices but I really I think your confusion is surrounding matrix-major order.</p>
<p>A matrix is either column major or row major. It's best to pick one and stick to it. Such as in OpenGL we almost always talk column major order which is the world of post multiply. So for the rest of this question I will stick to column major.</p>
<p>Transposing a column major matrix doesn't change it into a Row major matrix, we still have a column major matrix it is just transposed. We can make equivocations between row and column major but the two worlds really should be kept separated.</p>
<p>So when we talk about multiplying column major matrices we should be careful to use only column major matrices in the calculation.</p>
<p><span class="math-container">$ p_1 = C*p1 $</span>  // C and p1 are column major</p>
<p><span class="math-container">$p_2 = p1^T *C^T$</span> // the superscript indicates transpose</p>
<p><span class="math-container">$p_1 == p_2$</span></p>
<p>These 3 statement make sense only because we are talking column major matrices. We can switch between row and column major but it should be a clean break so to speak.</p>
<p>The question seems to treat the matrices kind of as both at the same time. That will get you into trouble quickly. Even though we all know that if we transpose a column major matrix it is equivalent to a row major matrix, it is much better to say it is a column major matrix transposed.</p>
<p>I'm not sure if I got to the heart of your question here, but hopefully it helps clear things up a little.</p>
<p>A Column Major 4x4 matrix is laid out like this:</p>
<p><span class="math-container">$\begin{bmatrix}
    a  &amp; e &amp; i &amp; m \\
    b  &amp; f &amp; j &amp; n \\
    c  &amp; g &amp; k &amp; o \\
    d  &amp; h &amp; l &amp; p
\end{bmatrix}$</span>
Think of it as 4 4x1 vectors stacked next to each other.</p>
<p>A row major 4x4 matrix has a data layout out like this:</p>
<p><span class="math-container">$\begin{bmatrix}
    a  &amp; b &amp; c &amp; d \\
    e  &amp; f &amp; g &amp; h \\
    i  &amp; j &amp; k &amp; l \\
    m  &amp; n &amp; o &amp; p
\end{bmatrix}$</span>
Think of it as 4 1x4 vectors stacked on top of each other.</p>
<p>Notice that the diagonals of each have the same values and that the transpose of each produces the other.</p>

CC BY-SA 4.0
2024-01-31T23:45:38.213Z
I still quite don't understand why the transpose of row major matrix will not be a column major matrix? Like the transpose of 4x1 matrix is supposed to be 1x4 right?
makra
CC BY-SA 4.0
2024-02-01T00:20:16.887Z
If you want to convert between the two systems, then take the transpose and call it row major.  But when working with a matrix doing translation, rotation, scale, it is done in the matrix major order the matrix was defined to be in. So yeah you can switch and it's easy, but do work in one system or the other.  For example math libraries are often written to work in one system, like column major. All the operations follow column major order, if some are written in row major and some written in column major then chaos will result.
pmw1234
CC BY-SA 4.0
2024-02-01T15:04:08.240Z
Totally agree with that.. 
However my question was that if we follow the column-major order we define WST matrix as $P1=WST∗p1=S∗Rx∗Ry∗Rz∗T∗p1$ 
So shouldn't we define the WST matrix as $P2=p2∗WST′=p2∗T′∗Rz′∗Ry′∗Rx′∗S'
$ when dealing with row-major order
makra
CC BY-SA 4.0
2024-02-01T15:27:06.613Z
And what I am saying is that your question doesn't make any sense. Equation 1 is talking column major, equation 2 is talking row major,  and equation 3 is talking row major transopose. But in order for equation 2 to be meaningful in the first place that matrices need to be in row major order which *is* the transpose of the matrices in equation 1.  But if equation 2 is talking column major then it is incorrect since the matrix data hasn't been converted to row major format. So the equations are switching back and forth without defining the matrix-major order and any meaning is getting lost.
pmw1234
CC BY-SA 4.0
2024-02-01T23:22:25.333Z
$P2, p2$ is row major (1x4) and $P1, p1$ are column major (4x1), all other matrices are 4x4
makra
CC BY-SA 4.0
2024-02-02T00:06:59.183Z
The 4x4 matrix is also either row or column major, I put an example of each in the answer.
pmw1234
CC BY-SA 4.0
2024-01-31T20:45:27.833Z
2024-02-02T00:05:29.617Z
2024-02-02T00:05:29.617Z
pmw1234
<p>I'm currently studying about world space transformation matrices and encountered some confusion regarding their application in different matrix orders (row major vs column major).</p>
<p><strong>Context</strong></p>
<p>In row major order, a point is represented as <span class="math-container">\begin{bmatrix}
x,y,z
\end{bmatrix}</span>
In column major order, the same point is represented as
<span class="math-container">\begin{bmatrix}
x \\
y \\
z
\end{bmatrix}</span></p>
<p><strong>World Space Transformation</strong></p>
<p>For column major order, we use post-multiplication: <span class="math-container">$P1 = WST * p1 = S * Rx * Ry * Rz * T * p1$</span></p>
<p>For row major order, it's we use pre-multiplication: <span class="math-container">$P2 = p2 * WST = p2 * T * Rz * Ry * Rx * S'$</span></p>
<p>However, I feel, for row major it should instead be: <span class="math-container">$P2 = p2 * WST' = p2 * T' * Rz' * Ry' * Rx' * S'$</span> where ' denotes transpose of the matrix.</p>
<p><strong>My Reasoning</strong></p>
<p>Both P1 and P2 represent the same transformed point, just in different orders (column major vs row major).</p>
<p>So, <span class="math-container">$P2 = P1' = (S * Rx * Ry * Rz * T *  p1)'$</span></p>
<p>Since, <span class="math-container">$(AB)' = B'A'$</span></p>
<p>We can say that, <span class="math-container">$P2 = p1' * T' * Rz' * Ry' * Rx' * S' =  p2 * T' * Rz' * Ry' * Rx' * S'$</span> (as <span class="math-container">$p1' = p2$</span>)</p>

CC BY-SA 4.0
2024-01-31T11:59:59.773Z
Did you miss a transpose on S for the third equation?
pmw1234
CC BY-SA 4.0
2024-01-31T15:11:37.483Z
Also, are these matrices row major or column major?
pmw1234
CC BY-SA 4.0
2024-01-31T19:08:51.733Z
@pmw1234 yup that was a typo, I fixed it.

$S, Rx, Ry, Rz, T$ are 4x4 matrices (scaling, rotation, translation)
makra
<transformations><matrix>
Pre and Post Multiplication World Space Transform Matrix ambiguity
makra
# Pre and Post Multiplication World Space Transform Matrix ambiguity

(Asked by: username_0 on 2024-01-31)

I'm currently studying about world space transformation matrices and encountered some confusion regarding their application in different matrix orders (row major vs column major).

**Context**

In row major order, a point is represented as \begin{bmatrix}
x,y,z
\end{bmatrix}
In column major order, the same point is represented as
\begin{bmatrix}
x \\
y \\
z
\end{bmatrix}

**World Space Transformation**

For column major order, we use post-multiplication: $P1 = WST \* p1 = S \* Rx \* Ry \* Rz \* T \* p1$

For row major order, it's we use pre-multiplication: $P2 = p2 \* WST = p2 \* T \* Rz \* Ry \* Rx \* S'$

However, I feel, for row major it should instead be: $P2 = p2 \* WST' = p2 \* T' \* Rz' \* Ry' \* Rx' \* S'$ where ' denotes transpose of the matrix.

**My Reasoning**

Both P1 and P2 represent the same transformed point, just in different orders (column major vs row major).

So, $P2 = P1' = (S \* Rx \* Ry \* Rz \* T \* p1)'$

Since, $(AB)' = B'A'$

We can say that, $P2 = p1' \* T' \* Rz' \* Ry' \* Rx' \* S' = p2 \* T' \* Rz' \* Ry' \* Rx' \* S'$ (as $p1' = p2$)

**Tags:** transformations, matrix

> **Comments:**
> **username_1**: Did you miss a transpose on S for the third equation?  
> **username_1**: Also, are these matrices row major or column major?  
> **username_0**: @username_1 yup that was a typo, I fixed it.  $S, Rx, Ry, Rz, T$ are 4x4 matrices (scaling, rotation, translation)  

---

## 2 answers

### Answer by username_2 on 2024-10-29. Score: 2

Multiplying on the left of right has no relation to the memory layout. Matrices have no notion of memory layout, they are 2D arrays that exist independently of any linearized memory representation. If your memory layout is leaking into your matrix computations then you have a problem.

As far as your main question goes, yes, by transposing both sides you can see
(here I have taken $p$ and $q$ to be column vectors):
$$q = BAp \iff q^T = p^T A^T B^T.$$

Now you may ask why in GLSL this looks rather as follows:

```
q = B*A*p vs q = p * transpose(A) * transpose(B).

```

The answer is that $p$ and $q$ are not really treated as column or
row vectors, but rather they get reinterpreted as those whenever
it is convenient in order to carry out the matrix-vector multiplication.
E.g. in `A*p`, `p` gets interpreted as a column vector,
while in `p*transpose(A)` it gets interpreted as a row vector.

However I kind of doubt that you want $q = SRTp$. Typically people want $q=TRSp$ or respectively $q^T = p^TS^TR^TT^T$, since they want scaling to be applied around the origin and along the main axes, then rotation to be applied around the origin, and finally translation to be applied. Of course it may also make sense to have $q=T\_gRT\_lSp$, where $T\_g$ is a global offset with respect to the global coordinate axes, while $T\_l$ is an offset w.r.t. the orientation given by $R$, e.g., if you want the point $p$ to move along where it is "looking" according to $R$ you would have a $T\_l$ with a translation vector e.g. $(0,0,1)$ if $+Z$ is forward for you.

---

**Matrix-Vector and Vector-Matrix Multiplication**

Given $A\in\mathbb{R}^{m\times n}$ and $B\in\mathbb{R}^{n\times o}$ the matrix
product $AB = C\in\mathbb{R}^{m\times o}$ is defined as follows:
$$C\_{ij} = \sum\_{k=1}^n A\_{ik} B\_{kj}, \quad 1\leq i \leq m, \quad 1\leq j \leq n.$$

In the special case when $o=1$, $B\in\mathbb{R}^{n\times 1}$ is known as a
column vector (**a column vector is a matrix**), and then $C\in\mathbb{R}^{m\times 1}$ is also a column vector.
Vice versa, if $m=1$ then $A\in\mathbb{R}^{1\times n}$ is a row vector
(**a row vector is a matrix**) and $C\in\mathbb{R}^{1\times o}$
is also a row vector.

Note that a vector $x\in\mathbb{R}^n$ is technically neither, since it is
not a $n\times 1$ or a $1\times n$ matrix, which would have indicated whether
it is a row or column.
But often in mathematics, physics, engineering, etc., the coordinates
of contravariant vectors are identified with column vectors, while the
coordinates of covariant vectors are identified with row vectors.
This generally means that one prefers $Mx$ for geometric transformations
as opposed to $xM^T$.

In GLSL a vector `vecn x;` models an element $x\in\mathbb{R}^n$. As such it
is neither a row vector nor a column vector. If you multiply an $m\times n$
matrix $M$ with $x$ on the right $Mx$, you can think of it as $x\in\mathbb{R}^n$ getting promoted to a column vector $\tilde{x}\in\mathbb{R}^{n\times 1}$
in order to carry out the matrix-matrix multiplication $M\tilde{x}$
using the matrix product rule, before you store the resulting
column vector $\tilde{y}\in\mathbb{R}^{m\times 1}$ as a vector $y\in\mathbb{R}^m$:

$$Mx \stackrel{x\in\mathbb{R}^n\mapsto \tilde{x}\in\mathbb{R}^{n\times 1}}{\longrightarrow}
M\tilde{x} = \tilde{y}
\stackrel{\tilde{y}\in\mathbb{R}^{m\times 1}\mapsto y\in\mathbb{R}^m}{\longrightarrow}
Mx = y.$$

Vice versa, let $u\in\mathbb{R}^m$,
then $uM = v\in\mathbb{R}^n$ has you promote $u\in\mathbb{R}^m$ to a row
vector $\tilde{u}^T\in\mathbb{R}^{1\times m}$, multiplying
by $M$, which results in a row vector $\tilde{v}^T\in\mathbb{R}^{1\times n}$, and then converting back to a vector $v\in\mathbb{R}^n$.

$$uM \stackrel{u\in\mathbb{R}^m\mapsto \tilde{u}^T\in\mathbb{R}^{1\times m}}{\longrightarrow}
\tilde{u}^TM = \tilde{v}^T
\stackrel{\tilde{v}^T\in\mathbb{R}^{1\times n}\mapsto v\in\mathbb{R}^m}{\longrightarrow}
uM = v.$$

In mathematics people virtually everywhere use column vectors, and do not
write any tilde even when they use the same symbol to refer to both
the vector and its column vector representation. So you would see
$y = Mx$ and $u^TM = v^T$ typically. $uM=v$ will be generally deemed undefined
unless $M\in\mathbb{R}^{1\times n}$, since $u$ would typically be interpreted
as a column vector, and not a row vector. Instead $u^T$ is typically used to
denote a row vector. That said, remember that the $^T$ is lost in your GLSL code,
at least when it comes to vectors.

---

**Transformations**

Now consider a point $p\in\mathbb{R}^{4\times 1}$ in homogeneous coordinates: $\begin{bmatrix} p\_x & p\_y & p\_z & 1\end{bmatrix}^T$. If we want to translate it with a vector $t\in\mathbb{R}^3$, we could multiply it from the left with a translation matrix as follows:

\begin{equation\*}
q= T\_tp = \begin{bmatrix}
1 & 0 & 0 & t\_x \\
0 & 1 & 0 & t\_y \\
0 & 0 & 1 & t\_z \\
0 & 0 & 0 & 1 \end{bmatrix}
\begin{bmatrix}
p\_x \\ p\_y \\ p\_z \\ 1 \end{bmatrix} =
\begin{bmatrix}
p\_x + t\_x \\ p\_y + t\_y \\ p\_z + t\_z \\ 1
\end{bmatrix}
\end{equation\*}

If we wanted to achieve the same but treating $p$ as a row vector, we would need the transposed of said matrix as you observed:

\begin{equation\*}
q^T = p^TT\_t^T =
\begin{bmatrix}
p\_x & p\_y & p\_z & 1 \end{bmatrix} =
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
t\_x & t\_y & t\_z & 1
\end{bmatrix}
= \begin{bmatrix}
p\_x + t\_x & p\_y + t\_y & p\_z + t\_z & 1
\end{bmatrix}.
\end{equation\*}

Thus if in your code you had `q = B * A * p` then this is equivalent to
`q = p * transpose(B * A) = p * transpose(A) * transpose(B).`

---

---

## **Rant regarding GLSL's "Column-Major" Matrices**

---

---

**Definition of Column-Major and Row-Major Arrays**

Suppose I have a $2\times 3$ array (I have indexed it from 0 for convenience since that's what GLSL uses)

\begin{equation\*}
M = \begin{bmatrix}
M(0,0) & M(0,1) & M(0,2) \\
M(1,0) & M(1,1) & M(1,2)
\end{bmatrix}.
\end{equation\*}

Then if I order the elements so that the entries in the rows are consecutive we call that a row-major layout:
\begin{equation\*}
M\_{row} = (M(0,0), M(0,1), M(0,2), M(1,0), M(1,1), M(1,2)).
\end{equation\*}

For the row-major version above the map for the indexing for a $m\times n$ matrix is $\textrm{idx\_row\_maj}(i,j)\mapsto i\cdot n + j$. Vice versa, if you had the index $k$ of an element in $M\_{row}$ and wanted to find its indices in the array you could use $\textrm{idx\_row\_maj}^{-1}(k) = (k/n, k\%n)$, where the division is integer division and $k\%n = k - (k/n) \* n$.

If I order the elements so that the entries in the columns are consecutive we call that a column-major layout:
\begin{equation\*}
M\_{col} = (M(0,0), M(1,0), M(0,1), M(1,1), M(0,2), M(1,2)).
\end{equation\*}

For the column-major version above the map for the indexing for a $m\times n$ matrix is $\textrm{idx\_col\_maj}(i,j)\mapsto i + j\cdot m$. Vice versa, if you had the index $k$ of an element in $M\_{col}$ and wanted to find its indices in the array you could use $\textrm{idx\_col\_maj}^{-1}(k) = (k\%m, k/m)$, where the division is integer division and $k\%m = k - (k/m) \* m$.

This means that having an array I can store it in memory in any of the layouts I want (or in neither, if I take some other order). That was the case where I have some array and I need to put it in memory. But what if I have some memory, and I need to figure out what the array is? Typically in code this is made clear by the syntax for the access to the elements. I illustrate this below with some code.

Suppose I have the following 2D array-like structures in C++:

```cpp
template<int m, int n>
struct matA
{
float e[m*n];
float& operator()(int i, int j) { return e[i*n + j]; }
};

template<int m, int n>
struct matB
{
float e[m*n];
float& operator()(int i, int j) { return e[i + j*m]; }
};

```

From the maps above $(i,j)\mapsto i\cdot n +j$ for `matA` and $(i,j)\mapsto i+j\cdot m$ for `matB` you can figure out that the first is meant to represent an array with row-major memory layout, while the second represents an array with column-major memory layout. Of course, `float e[m*n]` is just memory, and I could technically take any array with at most $mn$ elements and shove it in the `A.e` belonging to `matA<m,n> A;` in whatever order I wish, while ignoring the `operator()` definition. The main issue then, is that the accessor $(i,j)\mapsto i\cdot n + j$ would be misleading you to believe that the array is in row-major layout and that it is of size $m\times n$, while it could have been anything.

And here's the nasty part - GLSL's `matnxm M;` array behaves like matA, i.e. like a row-major array, where `M[i][j]` and `M[i][j+1]` are consecutive in memory, while `M[i][j]` and `M[i+1][j]` are not. However, you are supposed to shove an $m\times n$ (note `matnxm` but the matrix is `m\times n`) matrix in it in column-major memory layout, and then `M[i][j]` denotes the $i$-th **column** and $j$-th **row** of said matrix. That is, everything is reversed.

---

**Why this Happened and How to Deal with It**

---

In the previous I mentioned that

> you are supposed to shove an $m\times n$ (note `matnxm` but
> the matrix is `m\times n`) matrix in it in column-major memory layout

Technically you don't have to, but with the way the matrix multiplication was defined in GLSL, you have to do it like this if you want to make use of the matrix multiplication in a sane manner. The issue becomes apparent if you try to multiply e.g. a `mat2x3 A;` with a `mat3x4 B;`. If you try this, you get an error, but the product $C=AB\in\mathbb{R}^{2\times 4}$ is supposed to be perfectly well-defined mathematically for $A\in\mathbb{R}^{2\times 3}$ and $B\in\mathbb{R}^{3\times 4}$. The trick is that GLSL defined the matrix multiplication with the indices flipped, so you actually can only compute `mat2x4 C=B*A`. If you want for this to make sense you have to assume that `mat2x3 A` is actually some matrix $\tilde{A}\in\mathbb{R}^{3\times 2}$, with the caveat that $A(i,j) = \tilde{A}(j,i)$. Similarly one can argue `mat3x4 B` is actually a matrix $\tilde{B}\in\mathbb{R}^{4\times 3}$, then `mat2x4 C=B*A;` is $\tilde{C}=\tilde{B}\tilde{A}\in\mathbb{R}^{4\times 2}$.

Then if you keep in mind that a $m\times n$ matrix is `matnxm` and that `A[j][i]` is really $\tilde{A}(i,j)$, then you can cope with this.

The reasons as to why this happened are [described in wikipedia](https://en.wikipedia.org/wiki/Row-_and_column-major_order#External_libraries). But it essentially boils down to mistakes. The effect also hasn't been good overall:

> As a result, many developers will now simply declare that having the
> column as the first index is the definition of column-major, even
> though this is clearly not the case with a real column-major language
> like Fortran.

There are many ways that this could be addressed, but they would break backwards compatibility. Clearly calling an $m\times n$ matrix `matnxm` has to go, this is pretty egregious. And also having the accessor be such that `A[j][i]` is $\tilde{A}(i,j)$ can likely be addressed by just introducing an accessor `A(i,j)` such that `A(i,j) = A[j][i]`. Then one could interpret `A[j][i]` just as a column-major internal representation. Here's some pseudocode illustrating how simple this idea is:

```cpp
struct matmxn_glsl_fixed
{
matnxm e;
float& operator()(int i, int j) {return e[j][i];}
vecn& col()(int j) {return e[j];}
// potentially can be kept, but may be confusing:
vecn& operator[](int j) {return this->col(j);}
};

```

The other option relies on actually fixing the matrix multiplication to be the proper one. Then `matmxn A;` could work perfectly well as a row-major representation of a matrix, and there would be no issues whatsoever. There `A[i]` would return the $i$-th row as expected. One could of course fix the multiplication and change `matmxn A` to work as a column-major array like in Fortran, i.e., that `A(i,j)` and `A(i+1,j)` are consecutive elements and that `A(i,j)` and `A(i,j+1)` are not consecutive for $m>1$. Moreover if we want to extract the $j$-th column, again Fortran's syntax `A(:,j)` could be used (but not `A[j]`). One could even create proxy objects so that `A(i,:)` is well-defined even if the memory is non-consecutive.

---

**Simple C++ Example**

---

There are of course some efficiency related implementation details related to mainly SIMD that depend on the memory layout. Below you can find the general idea of how these can be implemented (one could unroll the loops, use SIMD for the `dot`, fmas for the linear combination of the vectors, etc.). It will not compile as I have written it currently (and there may be small typos here and there).

```cpp

template<typename T, int n>
struct vec
{
T e[n];
T& operator[](int i){return e[i];}
const T& operator[](int i) const {return e[i];}
};

template<typename T, int n>
vec<T,n> operator+(const vec<T,n>& l, const vec<T,n>& r)
{
vec<T,n> res;
for (int i=0; i<n; ++i)
  res[i] = l[i] + r[i];
return res;
}

template<typename T, int n>
vec<T,n> operator*(const T& l, const vec<T, n>& r)
{
vec<T,n> res;
for (int i=0; i<n; ++i)
  res[i] = l*r[i];
return res;
}

// in the unlikely scenario your mult does not commute 
// e.g. vectors with entries that are quaternions
template<typename T, int n>
vec<T,n> operator*(const vec<T, n>& l, const T& r)
{
vec<T,n> res;
for (int i=0; i<n; ++i)
  res[i] = l[i]*r;
return res;
}

template<typename T, int n>
T dot(const vec<T, n>& l, const vec<T, n>& r)
{
T res = l[0]*r[0];
for (int i=1; i<n; ++i)
  res += l[i]*r[i];
return res;
}

// row-major matrix
template<typename T, int m, int n>
struct mat_row
{
vec<vec<T,n>,m> e;
// returns the i-th row
vec<T,n>& row(int i){return e[i];}
const vec<T,n>& row(int i) const {return e[i];}
T& operator()(int i, int j){return e[i][j];}
const T& operator()(int i, int j) const {return e[i][j];}
}

// column-major matrix
template<typename T, int m, int n>
struct mat_col
{
vec<vec<T,m>,n> e;
// returns the j-th column
vec<T,m>& col(int j){return e[j];}
const vec<T,m>& col(int j) const {return e[j];}
T& operator()(int i, int j){return e[j][i];}
const T& operator()(int i, int j) const {return e[j][i];}
}

// matrix-vector mult row-major
//       [  -- l.row(0) --  ]       [ dot(l.row(0), r)   ]
// l*r = [      ...         ] * r = [      ...           ]
//       [ -- l.row(m-1) -- ]       [ dot(l.row(m-1), r) ]
template<typename T, int m, int n>
vec<T,m> operator*(const mat_row<T,m,n>& l, const vec<T,n>& r)
{
vec<T, m> res;
for (int i=0; i<m; ++i)
  res[i] = dot(l.row(i), r);
return res;
}

// matrix-vector mult col-major
//       [   |               |      ]   [  r[0]  ]
// l*r = [ l.col(0)  ...  l.col(n-1)] * [   ...  ] 
//       [   |               |      ]   [ r[n-1] ]
//
//     = l.col[0] * r[0] + ... + l.col[n-1] * r[n-1]
template<typename T, int m, int n>
vec<T,m> operator*(const mat_col<T,m,n>& l, const vec<T,n>& r)
{
vec<T, m> res = l.col(0) * r[0];
for (int j=1; j<n; ++j)
  res += l.col(j) * r[j];
return res;
}

// vector-matrix mult row-major
//                               [  -- r.row(0) --  ]
// l*r = [ l[0]  ...  l[m-1] ] * [      ...         ] 
//                               [ -- r.row(m-1) -- ]
//
//     = l[0] * r.row[0] + ... + l[m-1] * r.row[m-1]
template<typename T, int m, int n>
vec<T,n> operator*(const vec<T,m>& l, const mat_row<T,m,n>& r)
{
vec<T, n> res = l[0] * r.row(0);
for (int i=1; i<m; ++i)
  res += l[i] * r.row(i);
return res;
}

// vector-matrix mult col-major
//           [    |            |        ] 
// l*r = l * [ r.col(0)  ... l.col(n-1) ]
//           [    |            |        ]
//  
//     = [ dot(l, r.col(0))  ...  dot(l,r.col(n-1)) ]
template<typename T, int m, int n>
vec<T,n> operator*(const vec<T,m>& l, const mat_col<T,m,n>& r)
{
vec<T, n> res;
for (int j=0; j<n; ++j)
  res[j] = dot(l, r.col(j));
return res;
}

/* The Basic Matrix Mults */

// matrix-matrix mult: row-major * row-major = row-major
//       [  -- l.row(0) --  ]       [  -- l.row(0) * r --  ]
// l*r = [       ...        ] * r = [         ...          ]
//       [ -- l.row(m-1) -- ]       [ -- l.row(m-1) * r -- ]
// reuses row-major vector-matrix mult
template<typename T, int m, int k, int n>
mat_row<T,m,n> operator*(const mat_row<T,m,k>& l, const mat_row<T,k,n>& r)
{
mat_row<T,m,n> res;
for (int i=0; i<m; ++i)
  res.row(i) = l.row(i) * r;
return res;
}

// matrix-matrix mult: col-major * col-major = col-major
//           [    |             |      ]   [    |                 |      ]
// l*r = l * [ r.col(0) ... r.col(n-1) ] = [ l*r.col(0) ... l*r.col(n-1) ]
//           [    |             |      ]   [    |                 |      ]
// reuses col-major matrix-vector mult
template<typename T, int m, int k, int n>
mat_col<T,m,n> operator*(const mat_col<T,m,k>& l, const mat_col<T,k,n>& r)
{
mat_col<T,m,n> res;
for (int j=0; j<n; ++j)
  res.col(j) = l * r.col(j)
return res;
}

/* row-major * col-major - c++ can't differentiate based on return type alone though */

// matrix-matrix mult: row-major * col-major = row_major
//       [  -- l.row(0) --  ]       [  -- l.row(0) * r --  ]
// l*r = [       ...        ] * r = [         ...          ]
//       [ -- l.row(m-1) -- ]       [ -- l.row(m-1) * r -- ]
// reuses col-major vector-matrix mult
template<typename T, int m, int k, int n>
mat_row<T,m,n> operator*(const mat_row<T,m,k>& l, const mat_col<T,k,n>& r)
{
mat_row<T,m,n> res;
for (int i=0; i<m; ++i)
  res.row(i) = l.row(i) * r;
return res;
}

// matrix-matrix mult: row-major * col-major = col-major
//           [    |             |      ]   [    |                 |      ]
// l*r = l * [ r.col(0) ... r.col(n-1) ] = [ l*r.col(0) ... l*r.col(n-1) ]
//           [    |             |      ]   [    |                 |      ]
// reuses row-major matrix-vector mult
template<typename T, int m, int k, int n>
mat_col<T,m,n> operator*(const mat_row<T,m,k>& l, const mat_col<T,k,n>& r)
{
mat_col<T,m,n> res;
for (int j=0; j<n; ++j)
  res.col(j) = l * r.col(j)
return res;
}

/* The Nasty Stuff (I doubt this is actually very efficient, it's just elegant) */
// note: c++ cannot differentiate based on return type only

// tensor product producing a row-major matrix
//       [  l[0]  ]       [  -- l[0] * r --  ]
// lxr = [  ...   ] x r = [       ...        ]
//       [ l[m-1] ]       [ -- l[m-1] * r -- ]
template<typename T, int m, int n>
mat_row<T,m,n> tensor_row(const vec<T,m>& l, const vec<T,n>& r)
{
mat_row<T,m,n> res;
for (int i=0; i<m; ++i)
  res[i] = l[i] * r;
return res;
}

template<typename T, int m, int n>
mat_row<T,m,n> operator+(const mat_row<T,m,n>& l, const mat_row<T,m,n>& r)
{
mat_row<T,m,n> res;
for (int i=0; i<m; ++i)
  res.row(i) = l.row(i) + r.row(i);
return res;
}

// matrix-matrix mult: col-major * row-major = row_major      
// l*r = l.col(0) x r.row(0) + ... + l.col(k-1) x r.row(k-1)
// uses tensor product resulting in a row-major matrix
template<typename T, int m, int p, int n>
mat_row<T,m,n> operator*(const mat_col<T,m,p>& l, const mat_row<T,p,n>& r)
{
mat_row<T,m,n> res = tensor_row(l.col(0), r.row(0));
for (int k=1; k<p; ++k)
  res +=  tensor_row(l.col(k), r.row(k));
return res;
}

// tensor product producing a col-major matrix
//                                 [  |               |    ]
// lxr = l x [ r[0] ... r[n-1] ] = [ l*r[0]  ...  l*r[n-1] ]
//                                 [  |               |    ]
template<typename T, int m, int n>
mat_col<T,m,n> tensor_col(const vec<T,m>& l, const vec<T,n>& r)
{
mat_col<T,m,n> res;
for (int j=0; j<n; ++j)
  res[j] = l * r[j];
return res;
}

template<typename T, int m, int n>
mat_col<T,m,n> operator+(const mat_col<T,m,n>& l, const mat_col<T,m,n>& r)
{
mat_col<T,m,n> res;
for (int j=0; j<n; ++j)
  res.col(j) = l.col(j) + r.col(j);
return res;
}

// matrix-matrix mult: col-major * row-major = col_major      
// l*r = l.col(0) x r.row(0) + ... + l.col(k-1) x r.row(k-1)
// uses tensor product resulting in a col-major matrix
template<typename T, int m, int p, int n>
mat_col<T,m,n> operator*(const mat_col<T,m,p>& l, const mat_row<T,p,n>& r)
{
mat_col<T,m,n> res = tensor_col(l.col(0), r.row(0));
for (int k=1; k<p; ++k)
  res +=  tensor_col(l.col(k), r.row(k));
return res;
}

```

The various matrix-vector, vector-matrix, and matrix-matrix multiplications above are based off the following properties. Let $A\in\mathbb{R}^{m\times n}$, and let $A^i$ denote the $i$-th row of $A$ (as a row vector),$A\_j$ denote the $j$-th column of $A$ (as a column vector), $v^i$ denote the $i$-th coordinate of $v\in\mathbb{R}^{n\times 1}$, and $w\_j$ denote the $j$-th coordinate of $w^T\in\mathbb{R}^{1\times m}$, then one can compute the matrix-vector products in various ways:
\begin{align}
Av &=
\begin{bmatrix} - A^1 - \\ \vdots \\ - A^m - \end{bmatrix} v =
\begin{bmatrix} (A^1)^T \cdot v \\ \vdots \\ (A^m)^T \cdot v\end{bmatrix} \tag{1} \\
Av &=\begin{bmatrix} | & & | \\ A\_1 & \ldots & A\_n \\ | & & | \end{bmatrix}v = A\_1 v^1 + \ldots + A\_n v^n \tag{2} \\
w^TA &= \begin{bmatrix} w\_1 & \ldots & w\_m \end{bmatrix}\begin{bmatrix} - A^1 - \\ \vdots \\ - A^m - \end{bmatrix} = w\_1 A^1 + \ldots w\_m A^m \tag{3} \\
w^TA &= w^T \begin{bmatrix} | & & | \\ A\_1 & \ldots & A\_n \\ | & & | \end{bmatrix} =
\begin{bmatrix} w\cdot A\_1 & \ldots & w\cdot A\_n \end{bmatrix} \tag{4}
\end{align}

The above computation can be reused to compute matrix-matrix products. Let $A\in\mathbb{R}^{m\times p}$ and $B\in\mathbb{R}^{p\times n}$, and $AB=C\in\mathbb{R}^{m\times n}$. We can compute the latter product in multiple ways:
\begin{align}
AB &= A \begin{bmatrix} | & & | \\ B\_1 & \ldots & B\_n \\ | & & | \end{bmatrix}
\stackrel{(1,2)}{=} \begin{bmatrix} | & & | \\ AB\_1 & \ldots & AB\_n \\ | & & | \end{bmatrix} \\
AB &= \begin{bmatrix} - A^1 - \\ \vdots \\ - A^m - \end{bmatrix}B \stackrel{(3,4)}{=}
\begin{bmatrix} - (A^1B) - \\ \vdots \\ - (A^m B) - \end{bmatrix} \\
AB &= \begin{bmatrix} | & & | \\ A\_1 & \ldots & A\_p \\ | & & | \end{bmatrix} \begin{bmatrix} - B^1 - \\ \vdots \\ - B^p -\end{bmatrix} =
A\_1 \otimes (B^1)^T + \ldots + A\_p \otimes (B^p)^T,
\end{align}
where $\otimes$ is the outer or tensor product of two vectors, it is equal to the matrix product when you make the first vector a column vector and the second a row vector. Let $v^T\in\mathbb{R}^{1\times n}$ and $w\in\mathbb{R}^{m\times 1}$ then
\begin{align\*}
w\otimes v &= w v^T = \begin{bmatrix} w^1 \\ \vdots \\ w^m \end{bmatrix} v^T =
\begin{bmatrix} - w^1 v^T - \\ \vdots \\ - w^m v^T - \end{bmatrix}
= \begin{bmatrix} w^1v\_1 & \ldots & w^1 v\_n \\ \vdots & & \vdots \\
w^m v\_1 & \ldots & w^m v\_n \end{bmatrix},
\\
w\otimes v &= w v^T = w \begin{bmatrix} v\_1 & \ldots & v\_n \end{bmatrix}
= \begin{bmatrix} | & & | \\
w v\_1 & \ldots & w v\_n \\ | & & | \end{bmatrix} =
\begin{bmatrix} w^1v\_1 & \ldots & w^1 v\_n \\ \vdots & & \vdots \\
w^m v\_1 & \ldots & w^m v\_n \end{bmatrix}.
\end{align\*}

You will notice that the following two cases (row-major $\times$ row-major = column-major and column-major $\times$ column-major = row-major) are missing:
\begin{align\*}
AB &= \begin{bmatrix} - A^1 - \\ \vdots \\ - A^m - \end{bmatrix}
\begin{bmatrix} - B^1 - \\ \vdots \\ - B^p - \end{bmatrix}
= \begin{bmatrix} | & & | \\ C\_1 & \ldots & C\_n \\ | & & | \end{bmatrix},
\\
AB &= \begin{bmatrix} | & & | \\ A\_1 & \ldots & A\_p \\ | & & | \end{bmatrix}
\begin{bmatrix} | & & | \\ B\_1 & \ldots & B\_n \\ | & & |\end{bmatrix}
= \begin{bmatrix} - C^1 - \\ \vdots \\ - C^m - \end{bmatrix}.
\end{align\*}
As far as I am aware there is no nice way to vectorize these two while respecting the memory continuity. You're probably best off computing row-major $\times$ row-major and producing a row-major matrix, and then transposing to get col-major. Similarly for col-major $\times$ col-major = row-major.


---

### Answer by username_1 on 2024-01-31. Score: 1

I was going to do a bunch of fancy matrices but I really I think your confusion is surrounding matrix-major order.

A matrix is either column major or row major. It's best to pick one and stick to it. Such as in OpenGL we almost always talk column major order which is the world of post multiply. So for the rest of this question I will stick to column major.

Transposing a column major matrix doesn't change it into a Row major matrix, we still have a column major matrix it is just transposed. We can make equivocations between row and column major but the two worlds really should be kept separated.

So when we talk about multiplying column major matrices we should be careful to use only column major matrices in the calculation.

$ p\_1 = C\*p1 $ // C and p1 are column major

$p\_2 = p1^T \*C^T$ // the superscript indicates transpose

$p\_1 == p\_2$

These 3 statement make sense only because we are talking column major matrices. We can switch between row and column major but it should be a clean break so to speak.

The question seems to treat the matrices kind of as both at the same time. That will get you into trouble quickly. Even though we all know that if we transpose a column major matrix it is equivalent to a row major matrix, it is much better to say it is a column major matrix transposed.

I'm not sure if I got to the heart of your question here, but hopefully it helps clear things up a little.

A Column Major 4x4 matrix is laid out like this:

$\begin{bmatrix}
a & e & i & m \\
b & f & j & n \\
c & g & k & o \\
d & h & l & p
\end{bmatrix}$
Think of it as 4 4x1 vectors stacked next to each other.

A row major 4x4 matrix has a data layout out like this:

$\begin{bmatrix}
a & b & c & d \\
e & f & g & h \\
i & j & k & l \\
m & n & o & p
\end{bmatrix}$
Think of it as 4 1x4 vectors stacked on top of each other.

Notice that the diagonals of each have the same values and that the transpose of each produces the other.

> **Comments:**
> **username_0**: I still quite don't understand why the transpose of row major matrix will not be a column major matrix? Like the transpose of 4x1 matrix is supposed to be 1x4 right?  
> **username_1**: If you want to convert between the two systems, then take the transpose and call it row major.  But when working with a matrix doing translation, rotation, scale, it is done in the matrix major order the matrix was defined to be in. So yeah you can switch and it's easy, but do work in one system or the other.  For example math libraries are often written to work in one system, like column major. All the operations follow column major order, if some are written in row major and some written in column major then chaos will result.  
> **username_0**: Totally agree with that..  However my question was that if we follow the column-major order we define WST matrix as $P1=WST∗p1=S∗Rx∗Ry∗Rz∗T∗p1$  So shouldn't we define the WST matrix as $P2=p2∗WST′=p2∗T′∗Rz′∗Ry′∗Rx′∗S' $ when dealing with row-major order  
> **username_1**: And what I am saying is that your question doesn't make any sense. Equation 1 is talking column major, equation 2 is talking row major,  and equation 3 is talking row major transopose. But in order for equation 2 to be meaningful in the first place that matrices need to be in row major order which *is* the transpose of the matrices in equation 1.  But if equation 2 is talking column major then it is incorrect since the matrix data hasn't been converted to row major format. So the equations are switching back and forth without defining the matrix-major order and any meaning is getting lost.  
> **username_0**: $P2, p2$ is row major (1x4) and $P1, p1$ are column major (4x1), all other matrices are 4x4  
> **username_1**: The 4x4 matrix is also either row or column major, I put an example of each in the answer.  

---

