Arrays

%reload_ext rubberize
from rubberize.config import config

The rendering of numpy.ndarray type is supported by Rubberize.

Creating Arrays

Arrays created using array() are rendered as the resulting array:

Tip

Append _mat or _vec to the variable name to render them in bold font, as in textbooks.

%%tap --grid
import numpy as np

a_mat = np.array([1, 2, 3])
b_mat = np.array([[1, 2], [3, 4]])
c_mat = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
\( \displaystyle \mathbf{a} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix} \)
\( \displaystyle \mathbf{b} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \)
\( \displaystyle \mathbf{c} = \begin{bmatrix} \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \\ \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \end{bmatrix} \)

Array Delimiters

@array_delimiter controls the appearance of delimiters used in an array. Use "pmatrix" for parentheses and "bmatrix" for square brackets.

config.array_delimiter
'bmatrix'
%%tap --grid @array_delimiter="pmatrix"
a_mat; b_mat; c_mat
\( \displaystyle \mathbf{a} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix} \)
\( \displaystyle \mathbf{b} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \)
\( \displaystyle \mathbf{c} = \begin{bmatrix} \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \\ \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \end{bmatrix} \)

Array Creation Routines

The following array creation routines are also supported:

%%tap
A_mat = np.eye(2,3,1)
B_mat = np.identity(2)
\( \displaystyle \mathbf{A} = \mathbf{I}_{2 \times 3}^{\left( 1 \right)} = \begin{bmatrix} 0.00 & 1.00 & 0.00 \\ 0.00 & 0.00 & 1.00 \end{bmatrix} \)
\( \displaystyle \mathbf{B} = \mathbf{I}_{2} = \begin{bmatrix} 1.00 & 0.00 \\ 0.00 & 1.00 \end{bmatrix} \)
%%tap
C_mat = np.ones((3,2)) 
C_mat_star = np.ones(3)
D_mat = np.ones_like(B_mat)
\( \displaystyle \mathbf{C} = \mathbf{1}_{3 \times 2} = \begin{bmatrix} 1.00 & 1.00 \\ 1.00 & 1.00 \\ 1.00 & 1.00 \end{bmatrix} \)
\( \displaystyle \mathbf{C}^{*} = \mathbf{1}_{1 \times 3} = \begin{bmatrix} 1.00 \\ 1.00 \\ 1.00 \end{bmatrix} \)
\( \displaystyle \mathbf{D} = \mathbf{1}_{\mathbf{B}} = \begin{bmatrix} 1.00 & 1.00 \\ 1.00 & 1.00 \end{bmatrix} \)
%%tap
E_mat = np.zeros((3,2))
E_mat_star = np.zeros(2)
F_mat = np.zeros_like(A_mat)
\( \displaystyle \mathbf{E} = \mathbf{0}_{3 \times 2} = \begin{bmatrix} 0.00 & 0.00 \\ 0.00 & 0.00 \\ 0.00 & 0.00 \end{bmatrix} \)
\( \displaystyle \mathbf{E}^{*} = \mathbf{0}_{1 \times 2} = \begin{bmatrix} 0.00 \\ 0.00 \end{bmatrix} \)
\( \displaystyle \mathbf{F} = \mathbf{0}_{\mathbf{A}} = \begin{bmatrix} 0.00 & 0.00 & 0.00 \\ 0.00 & 0.00 & 0.00 \end{bmatrix} \)
%%tap
G_mat = np.full((2,1), 69.0)
H_mat = np.full_like(E_mat, 420.0)
\( \displaystyle \mathbf{G} = 69.00 \cdot \mathbf{1}_{2 \times 1} = \begin{bmatrix} 69.00 \\ 69.00 \end{bmatrix} \)
\( \displaystyle \mathbf{H} = 420.00 \cdot \mathbf{1}_{\mathbf{E}} = \begin{bmatrix} 420.00 & 420.00 \\ 420.00 & 420.00 \\ 420.00 & 420.00 \end{bmatrix} \)

1D Arrays

@show_1d_as_col specifies whether to render 1-dimension arrays vertically or horizontally:

config.show_1d_as_col
True
%%tap --grid
a_mat  # @show_1d_as_col=False
a_mat  # @show_1d_as_col=True
\( \displaystyle \mathbf{a} = \begin{bmatrix} 1 & 2 & 3 \end{bmatrix} \)
\( \displaystyle \mathbf{a} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix} \)

Accessing Elements

Element access is rendered like other collection types:

%%tap
b_mat
b_mat[0][1]
b_mat[0, 1]  # Tuple access
b_mat[:, 0]  # Slice access
\( \displaystyle \mathbf{b} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \)
\( \displaystyle \mathbf{b}_{\left( 0,\, 1 \right)} = 2 \)
\( \displaystyle \mathbf{b}_{\left( 0,\, 1 \right)} = 2 \)
Tuple access
\( \displaystyle \mathbf{b}_{\left( : ,\, 0 \right)} = \begin{bmatrix} 1 \\ 3 \end{bmatrix} \)
Slice access

Array Operations

Common array operations are supported:

Arithmetic Operations

%%tap
d_mat = np.array([[5, 6], [7, 8]])

b_mat + d_mat
b_mat * d_mat
b_mat / d_mat
\( \displaystyle \mathbf{d} = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \)
\( \displaystyle \mathbf{b} + \mathbf{d} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} + \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} = \begin{bmatrix} 6 & 8 \\ 10 & 12 \end{bmatrix} \)
\( \displaystyle \mathbf{b}\,\mathbf{d} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}\,\begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} = \begin{bmatrix} 5 & 12 \\ 21 & 32 \end{bmatrix} \)
\( \displaystyle \frac{\mathbf{b}}{\mathbf{d}} = \frac{\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}}{\begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix}} = \begin{bmatrix} 0.20 & 0.33 \\ 0.43 & 0.50 \end{bmatrix} \)

Scalar Operations

%%tap
1 + d_mat
2 * d_mat
3 / d_mat
\( \displaystyle 1 + \mathbf{d} = 1 + \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} = \begin{bmatrix} 6 & 7 \\ 8 & 9 \end{bmatrix} \)
\( \displaystyle 2\,\mathbf{d} = 2\,\begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} = \begin{bmatrix} 10 & 12 \\ 14 & 16 \end{bmatrix} \)
\( \displaystyle \frac{3}{\mathbf{d}} = \frac{3}{\begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix}} = \begin{bmatrix} 0.60 & 0.50 \\ 0.43 & 0.38 \end{bmatrix} \)

Array Transpose

%%tap
b_mat.transpose()
np.transpose(b_mat)
np.linalg.matrix_transpose(b_mat)
b_mat.T  # Substituted form not displayed
\( \displaystyle \mathbf{b}^{\intercal} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}^{\intercal} = \begin{bmatrix} 1 & 3 \\ 2 & 4 \end{bmatrix} \)
\( \displaystyle \mathbf{b}^{\intercal} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}^{\intercal} = \begin{bmatrix} 1 & 3 \\ 2 & 4 \end{bmatrix} \)
\( \displaystyle \mathbf{b}^{\intercal} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}^{\intercal} = \begin{bmatrix} 1 & 3 \\ 2 & 4 \end{bmatrix} \)
\( \displaystyle \mathbf{b}^{\intercal} = \begin{bmatrix} 1 & 3 \\ 2 & 4 \end{bmatrix} \)
Substituted form not displayed

Matrix Multiplication

Matrix multiplication always uses a center dot (\(\cdot\)) as the multiplication symbol.

%%tap
e_mat = np.array([[9, 10], [11, 12]])

d_mat @ e_mat
d_mat.dot(e_mat)
np.dot(d_mat, e_mat)
np.matmul(d_mat, e_mat)
np.linalg.matmul(d_mat, e_mat)
\( \displaystyle \mathbf{e} = \begin{bmatrix} 9 & 10 \\ 11 & 12 \end{bmatrix} \)
\( \displaystyle \mathbf{d} \cdot \mathbf{e} = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \cdot \begin{bmatrix} 9 & 10 \\ 11 & 12 \end{bmatrix} = \begin{bmatrix} 111 & 122 \\ 151 & 166 \end{bmatrix} \)
\( \displaystyle \mathbf{d} \cdot \mathbf{e} = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \cdot \begin{bmatrix} 9 & 10 \\ 11 & 12 \end{bmatrix} = \begin{bmatrix} 111 & 122 \\ 151 & 166 \end{bmatrix} \)
\( \displaystyle \mathbf{d} \cdot \mathbf{e} = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \cdot \begin{bmatrix} 9 & 10 \\ 11 & 12 \end{bmatrix} = \begin{bmatrix} 111 & 122 \\ 151 & 166 \end{bmatrix} \)
\( \displaystyle \mathbf{d} \cdot \mathbf{e} = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \cdot \begin{bmatrix} 9 & 10 \\ 11 & 12 \end{bmatrix} = \begin{bmatrix} 111 & 122 \\ 151 & 166 \end{bmatrix} \)
\( \displaystyle \mathbf{d} \cdot \mathbf{e} = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} \cdot \begin{bmatrix} 9 & 10 \\ 11 & 12 \end{bmatrix} = \begin{bmatrix} 111 & 122 \\ 151 & 166 \end{bmatrix} \)

Cross Product

Associativity rules are accounted for when rendering cross products:

%%tap
Q_mat = np.array([[1, 2, 3], [4, 5, 6]])
W_mat = np.array([[7, 8, 9], [10, 11, 12]])
E_mat = np.array([[7, 8, 9], [10, 11, 12]])

np.cross(Q_mat, W_mat)
np.cross(np.cross(Q_mat, W_mat), E_mat)
np.cross(Q_mat, np.cross(W_mat, E_mat))
\( \displaystyle \mathbf{Q} = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} \)
\( \displaystyle \mathbf{W} = \begin{bmatrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{bmatrix} \)
\( \displaystyle \mathbf{E} = \begin{bmatrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{bmatrix} \)
\( \displaystyle \mathbf{Q} \times \mathbf{W} = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} \times \begin{bmatrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{bmatrix} = \begin{bmatrix} -6 & 12 & -6 \\ -6 & 12 & -6 \end{bmatrix} \)
\( \displaystyle \left( \mathbf{Q} \times \mathbf{W} \right) \times \mathbf{E} = \left( \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} \times \begin{bmatrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{bmatrix} \right) \times \begin{bmatrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{bmatrix} = \begin{bmatrix} 156 & 12 & -132 \\ 210 & 12 & -186 \end{bmatrix} \)
\( \displaystyle \mathbf{Q} \times \left( \mathbf{W} \times \mathbf{E} \right) = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} \times \left( \begin{bmatrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{bmatrix} \times \begin{bmatrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{bmatrix} \right) = \begin{bmatrix} 0 & 0 & 0 \\ 0 & 0 & 0 \end{bmatrix} \)

Inner Product

%%tap
np.inner(Q_mat, W_mat)
\( \displaystyle \left\langle \mathbf{Q},\, \mathbf{W} \right\rangle = \left\langle \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix},\, \begin{bmatrix} 7 & 8 & 9 \\ 10 & 11 & 12 \end{bmatrix} \right\rangle = \begin{bmatrix} 50 & 68 \\ 122 & 167 \end{bmatrix} \)

Outer Product

%%tap
u_vec = np.array([1, 2, 3])
v_vec = np.array([4, 5])

np.outer(u_vec, v_vec)
np.linalg.outer(u_vec, v_vec)
\( \displaystyle \mathbf{u} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix} \)
\( \displaystyle \mathbf{v} = \begin{bmatrix} 4 \\ 5 \end{bmatrix} \)
\( \displaystyle \mathbf{u} \otimes \mathbf{v} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix} \otimes \begin{bmatrix} 4 \\ 5 \end{bmatrix} = \begin{bmatrix} 4 & 5 \\ 8 & 10 \\ 12 & 15 \end{bmatrix} \)
\( \displaystyle \mathbf{u} \otimes \mathbf{v} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix} \otimes \begin{bmatrix} 4 \\ 5 \end{bmatrix} = \begin{bmatrix} 4 & 5 \\ 8 & 10 \\ 12 & 15 \end{bmatrix} \)

Norm

%%tap
np.linalg.vector_norm(a_mat)
np.linalg.matrix_norm(b_mat)
np.linalg.matrix_norm(b_mat, ord="nuc")
\( \displaystyle \left\| \mathbf{a} \right\| = \begin{Vmatrix} 1 \\ 2 \\ 3 \end{Vmatrix} = 3.74 \)
\( \displaystyle \left\| \mathbf{b} \right\|_{F} = \begin{Vmatrix} 1 & 2 \\ 3 & 4 \end{Vmatrix}_{F} = 5.48 \)
\( \displaystyle \left\| \mathbf{b} \right\|_{*} = \begin{Vmatrix} 1 & 2 \\ 3 & 4 \end{Vmatrix}_{*} = 5.83 \)

Power

%%tap
np.linalg.matrix_power(b_mat, 3)
\( \displaystyle \mathbf{b}^{3} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}^{3} = \begin{bmatrix} 37 & 54 \\ 81 & 118 \end{bmatrix} \)

Determinant

%%tap
np.linalg.det(b_mat)
\( \displaystyle \det \left( \mathbf{b} \right) = \det \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix} = -2.00 \)

Rank

%%tap
np.linalg.matrix_rank(b_mat)
\( \displaystyle \operatorname{rank} \left( \mathbf{b} \right) = \operatorname{rank} \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix} = 2 \)

Trace

%%tap
np.trace(b_mat)
np.linalg.trace(b_mat)
\( \displaystyle \operatorname{Tr} \left( \mathbf{b} \right) = \operatorname{Tr} \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix} = 5 \)
\( \displaystyle \operatorname{Tr} \left( \mathbf{b} \right) = \operatorname{Tr} \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix} = 5 \)

Inverse and Pseudo-inverse

%%tap
np.linalg.inv(b_mat)
np.linalg.pinv(b_mat)
\( \displaystyle \mathbf{b}^{-1} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}^{-1} = \begin{bmatrix} -2.00 & 1.00 \\ 1.50 & -0.50 \end{bmatrix} \)
\( \displaystyle \mathbf{b}^{+} = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}^{+} = \begin{bmatrix} -2.00 & 1.00 \\ 1.50 & -0.50 \end{bmatrix} \)

Solving Systems of Equations

%%tap @show_1d_as_col=True
# **Define stiffness matrix**
k_1, k_2, k_3 = 10, 15, 20  # Example stiffness values
K_mat = np.array([[k_1 + k_2, -k_2],
                  [-k_2, k_2 + k_3]])

# **Force vector**
F_mat = np.array([100, 150])  # Example forces

u_mat = np.linalg.inv(K_mat) @ F_mat  # Solve for displacements
Define stiffness matrix
\( \displaystyle k_{1},\, k_{2},\, k_{3} = \left( 10,\, 15,\, 20 \right) \)
Example stiffness values
\( \displaystyle \mathbf{K} = \begin{bmatrix} k_{1} + k_{2} & -k_{2} \\ -k_{2} & k_{2} + k_{3} \end{bmatrix} = \begin{bmatrix} 10 + 15 & -15 \\ -15 & 15 + 20 \end{bmatrix} = \begin{bmatrix} 25 & -15 \\ -15 & 35 \end{bmatrix} \)
Force vector
\( \displaystyle \mathbf{F} = \begin{bmatrix} 100 \\ 150 \end{bmatrix} \)
Example forces
\( \displaystyle \mathbf{u} = \mathbf{K}^{-1} \cdot \mathbf{F} = \begin{bmatrix} 25 & -15 \\ -15 & 35 \end{bmatrix}^{-1} \cdot \begin{bmatrix} 100 \\ 150 \end{bmatrix} = \begin{bmatrix} 8.85 \\ 8.08 \end{bmatrix} \)
Solve for displacements

Or using numpy.linalg.solve():

%%tap @show_1d_as_col=True
u_mat_alt = np.linalg.solve(K_mat, F_mat)
\( \displaystyle \mathbf{u}_{\mathrm{alt}} = \underbracket{\mathbf{K}^{-1} \cdot \mathbf{F}}_{\text{via LAPACK}} = \underbracket{\begin{bmatrix} 25 & -15 \\ -15 & 35 \end{bmatrix}^{-1} \cdot \begin{bmatrix} 100 \\ 150 \end{bmatrix}}_{\text{via LAPACK}} = \begin{bmatrix} 8.85 \\ 8.08 \end{bmatrix} \)