Matrix of matrices in python - python

Hey so I'm working on this code for a material analysis. I have a matrix generated for each layer of the material and I want to save each of these matrices as their own element. The way I was doing this was by saving it to a dictionary. I then form one matrix by summing all the values of the dictionary. Now I do this for three different conditions which leaves me with 3 matrices: A, B, and D. I want to make a matrix of all of these so that it looks like:
| A B |
| B D |
However I can't get it to print properly as it always says matrix: then one of the matrices such as A. It prints the second matrix, B, on the third line where A ended instead of being next to A. I also need to perform future operations on this massive matrix so I'm wondering what the best way to go about that would be. This is a part of my code:
Qbars = {}
for i in plies:
Qbar11 = Q11 * math.cos(float(thetas[j]))**4 + Q22 *math.sin(float(thetas[j]))**4 + \
2 * (Q12 + 2 * Q66) * math.sin(float(thetas[j]))**2 * math.cos(float(thetas[j]))**2
Qbar22 = Q11 * math.sin(float(thetas[j]))**4 + Q22 *math.cos(float(thetas[j]))**4 + \
2 * (Q12 + 2 * Q66) * math.sin(float(thetas[j]))**2 * math.cos(float(thetas[j]))**2
Qbar12 = (Q11 + Q22 - 4 * Q66) * math.sin(float(thetas[j]))**2 * \
math.cos(float(thetas[j]))**2 + Q12 * (math.cos(float(thetas[j]))**4 + \
math.sin(float(thetas[j]))**4)
Qbar66 = (Q11 + Q22 - 2 * Q12 - 2 * Q66) * math.sin(float(thetas[j]))**2 * \
math.cos(float(thetas[j])) **2 + Q66 * (math.sin(float(thetas[j]))**4 + \
math.cos(float(thetas[j]))**4)
Qbar16 = (Q11 - Q12 - 2 * Q66) * math.cos(float(thetas[j]))**3 * \
math.sin(float(thetas[j])) - (Q22 - Q12 - 2 * Q66) * math.cos(float(thetas[j])) * \
math.sin(float(thetas[j]))**3
Qbar26 = (Q11 - Q12 - 2 * Q66) * math.cos(float(thetas[j])) * \
math.sin(float(thetas[j]))**3 - (Q22 - Q12 - 2 * Q66) * \
math.cos(float(thetas[j]))**3 * math.sin(float(thetas[j]))
Qbar = np.matrix ([[Qbar11, Qbar12, Qbar16], [Qbar12, Qbar22, Qbar26], \
[Qbar16, Qbar26, Qbar66]])
Qbars[i] = Qbar
if len(thetas) == 1:
j = 0
else:
j = j + 1
k=0
Alist = {}
for i in plies:
Alist[i] = Qbars[i].dot(h[k])
if len(h) == 1:
k = 0
else:
k = k + 1
A = sum(Alist.values())
ABD = ([A, B],[B, D])
print ABD
One of the next operations I intend to perform would be to multiply the matrix by a 6x1 array that would look like such:
| Nx | | A A A B B B |
| Ny | | A A A B B B |
| Nxy| | A A A B B B |
------ * ----------------
| Mx | | B B B D D D |
| My | | B B B D D D |
| Mxy| | B B B D D D |
What would be the best way to go about doing this?
EDIT: I made this shorter code to reproduce what I'm dealing with, I couldn't think of how to make it even smaller.
import os
import numpy as np
import math
os.system('cls')
ang = raw_input("ENTER 0 (SPACE) 45 ")
thetas = [int(i) for i in ang.split()]
x = 40
h = [3, 5]
y = [1,2]
j = 0
Qbars = {}
for i in y:
theta = [thetas[j] * math.pi / 180]
Q = math.sin(float(thetas[j]))
Qbar = np.matrix ([[Q, Q, Q], [Q, Q, Q], [Q, Q, Q]])
Qbars[i] = Qbar
if len(thetas) == 1:
j = 0
else:
j = j + 1
print Qbars
k=0
Alist = {}
for i in y:
Alist[i] = Qbars[i].dot(h[k])
if len(h) == 1:
k = 0
else:
k = k + 1
A = sum(Alist.values())
AAAA = ([A, A], [A, A])
print AAAA
test = raw_input("Press ENTER to close")

As others have noted, the matrix class is pretty much deprecated by now. They are more limited than ndarrays, with very little additional functionality. The main reason why people prefer to use numpy matrices is that linear algebra (in particular, matrix multiplication) works more naturally for matrices.
However, as far as I can tell you're using np.dot rather than the overloaded arithmetic operators of the matrix class to begin with, so you would not see any loss of functionality from using np.array instead. Furthermore, if you would switch to python 3.5 or newer, you could use the # matrix multiplication operator that would let you write things such as
Alist[i] = Qbars[i] # h[k]
In the following I'll use the ndarray class instead of the matrix class for the above reasons.
So, your question has two main parts: creating your block matrix and multiplying the result with a vector. I suggest using an up-to-date numpy version, since there's numpy.block introduced in version 1.13. This conveniently does exactly what you want it to do:
>>> import numpy as np
>>> A,B,C = (np.full((3,3),k) for k in range(3))
>>> A
array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
>>> B
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
>>> C
array([[2, 2, 2],
[2, 2, 2],
[2, 2, 2]])
>>> np.block([[A,B],[B,C]])
array([[0, 0, 0, 1, 1, 1],
[0, 0, 0, 1, 1, 1],
[0, 0, 0, 1, 1, 1],
[1, 1, 1, 2, 2, 2],
[1, 1, 1, 2, 2, 2],
[1, 1, 1, 2, 2, 2]])
Similarly, you can concatenate your two 3-length vectors using np.concatenate or one of the stacking methods (these are available in older versions too).
Now, the problem is that you can't multiply a matrix of shape (6,1) with a matrix of shape (6,6), so the question is what you're really trying to do here. In case you want to multiply each element of your matrix with the corresponding row of your vector, you can just multiply your arrays (of class np.ndarray!) and make use of array broadcasting:
>>> Q = np.block([[A,B],[B,C]]) # (6,6)-shape array
>>> v = np.arange(6).reshape(-1,1) # (6,1)-shape array
>>> v * Q
array([[ 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 1, 1, 1],
[ 0, 0, 0, 2, 2, 2],
[ 3, 3, 3, 6, 6, 6],
[ 4, 4, 4, 8, 8, 8],
[ 5, 5, 5, 10, 10, 10]])
The other option is that you want to do matrix-vector multiplication, but then either you have to transpose your vector (in order to multiply it with the matrix from the right) or swap the order of the matrix and the vector (multiplying the vector with the matrix from the left). Example for the former:
>>> v.T # Q # python 3.5 and up
array([[12, 12, 12, 27, 27, 27]])
>>> v.T.dot(Q)
array([[12, 12, 12, 27, 27, 27]])
Another benefit of arrays (rather than matrices) is that arrays can be multidimensional. Instead of putting numpy arrays inside a dict and summing them that way, you could define a 3d array (a collection of 2d arrays along a third axis), then you could sum along the third dimension. One huge benefit of numpy is its efficient memory need and performance, and these aspects are strongest if you use numpy objects and methods all through your code. Mixing native python objects (such as dicts, zips, loops) typically hinders performance.

Related

Construct equivalent transform for vectorized Matrix

Equivalent transform for vectorized solution
For a given symmetric 4x4 matrix Q and a 3x4 matrix P the 3x3 matrix C is obtained through
C=P # Q # P.T
It can be shown that the output C will be symmetric again. The same problem can be formulated using only the unique elements in Q and C exploiting their symmetry. To do so, the matrices are vectorized as seen below.
I want to construct a matrix B that maps the vectorized matrices onto each other like so:
c = B # q
B must be a 6x10 and should be constructable from P only. How can I get B from P?
I tried this, but it doesnt seem to work. Maybe someone has experienced a similar problem?
import numpy as np
def vectorize(A, ord='c'):
"""
Symmetric matrix to vector e.g:
[[1, 2, 3],
[2, 4, 5],
[3, 5, 6]] -> [1, 2, 3, 4, 5, 6] (c-order, row-col)
-> [1, 2, 4, 3, 5, 6] (f-order, col-row)
"""
# upper triangle mask
m = np.triu(np.ones_like(A, dtype=bool)).flatten(order=ord)
return A.flatten(order=ord)[m]
def B(P):
B = np.zeros((6, 10))
counter = 0
# the i,j entry in C depends on the i, j columns in P
for i in range(3):
for j in range(i, 3):
coeffs = np.outer(P[i], P[j])
B[counter] = vectorize(coeffs)
counter += 1
return B
if __name__ == '__main__':
# original transform
P = np.arange(12).reshape((3, 4))
# calculated transform for vectorized matrix
_B = B(P)
# some random symmetric matrix
Q = np.array([[1, 2, 3, 4],
[2, 5, 6, 7],
[3, 6, 8, 9],
[4, 7, 9, 10]])
# if B is an equivilant transform to P, these should be similar
C = P # Q # P.T
c = _B # vectorize(Q)
print(f"q: {vectorize(Q)}\n"
f"C: {vectorize(C)}\n"
f"c: {c}")
Output:
q: [ 1 2 3 4 5 6 7 8 9 10]
C: [ 301 949 2973 1597 4997 8397]
c: [ 214 542 870 1946 3154 5438] <-- not the same
import numpy as np
def vec_from_mat(A, order='c'):
"""
packs the unique elements of symmetric matrix A into a vector
:param A: symmetric matrix
:return:
"""
return A[np.triu_indices(A.shape[0])].flatten(order=order)
def B_from_P(P):
"""
returns a 6x10 matrix that maps the 10 unique elements of a symmetric 4x4 matrix Q on the 6 unique elements of a
3x3 matrix C to linearize the equation C=PTQP to c=Bv
:param P: 3x4 matrix
:return: B with shape (6, 10)
"""
n, m = P.shape
b1, b2 = (n * (n + 1) // 2), (m * (m + 1) // 2)
B = np.zeros((b1, b2))
for a, (i, j) in enumerate(zip(*np.triu_indices(n))):
coeffs = np.outer(P[i], P[j])
# collect coefficients from lower and upper triangle of symmetric matrix
B[a] = vec_from_mat(coeffs) + vec_from_mat(np.triu(coeffs.T, k=1))
return B

How to convert the following trigonometric function into a python function for boundary curvature calculation?

I am trying to understand a few slides from this source
Specifically, this example at slide 59:
The part I do not understand is how to go from the chain-code to the curvature.
I believe the formula is given in slide 56:
But if I try to implement this in python I get different results.
For example:
import matplotlib.pyplot as plt
# Dataset
x = [0, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8]
y = [0, 0, 0, 1, 1, 2, 2, 1, 0, 0, 0]
# Show data
plt.scatter(x, y)
plt.plot(x, y)
plt.axis('equal')
plt.show()
import math
i = 4 # Taking the 5th point, at index 4, with supposed curvature of 1 from the slide
k = 1
a = math.atan((y[i+k]-y[i])/(x[i+k]-x[i]))
b = math.atan((y[i]-y[i-k])/(x[i]-x[i-k]))
result = (a - b) % (2 * math.pi) # = 0.7853981633974483
So clearly I a missing something, but what?
The "curvature" in the first image is the difference between two subsequent "chain-codes" modulo 8. So for example for chain codes 0 0 2 0 1 0 7 6 0 0 the 4th entry in curvature is 1-0 = 1 while the sixth is 7-0 = 7 = -1 (mod 8). In Python you can calculate it like this:
>>> def mod8(x):
... m = x % 8
... return m if m < 4 else m - 8
...
>>> cc = [0, 0, 2, 0, 1, 0, 7, 6, 0, 0]
>>> [mod8(a - b) for (a, b) in zip(cc[1:], cc[:-1])]
[0, 2, -2, 1, -1, -1, -1, 2, 0]
If you compare this with the formula that uses atan, what the formula is missing is the conversion of the angles from radians to the units where 1 is 45 degrees (pi/4). Your result 0.7853981633974483 is correct according to the formula, but if you expected to get 1.0 you would have to divide the result by math.pi/4.

How to solve this math puzzle with Python?

A + B = 8
B + D = 8
A + C = 13
C - D = 6
How to find the values of A, B, C and D?
I assumed the values would be integers and positive and did this:
a = range(0,14)
b = c = d = a
for i in a:
for x in b:
for y in c:
for z in d:
if (a[i] + b[x] == 8 and a[i] + c[y] == 13 and b[x] + d[z] == 8 and c[y]-d[z]==6):
print(a[i],b[x],c[y],d[z])
But that does not work. Even then I extend range to a = range(-100,100).
After solving the equation by hand (with Google's help) I know that floats are involved, e.g. A = 3.5 etc.
But then how to solve it with Python.
If you know linear algebra, you can frame the question as a system of equations, which is then trivial to solve using a freely-available and popular library called numpy (hat tip #Griboullis):
import numpy as np
A = [[1, 1, 0, 0],
[0, 1, 0, 1],
[1, 0, 1, 0],
[0, 0, 1, -1]]
b = [8, 8, 13, 6]
answer = np.linalg.solve(A, b)
If you want a refresher at the matrix math/linear algebra behind this python solution, you can check out https://www.mathsisfun.com/algebra/systems-linear-equations-matrices.html.
There's no need to learn matrix theory (at least not for this).
>>> from sympy import *
>>> var('A B C D')
(A, B, C, D)
>>> solve([A+B-8,B+D-8,A+C-13,C-D-6])
{B: 9/2, D: 7/2, C: 19/2, A: 7/2}
You just need to express each equation such as A+B=8 in the form A+B-8=0 and then omit the '=0' part.

Tensorflow: tensor multiplication row-by-row with more different matrices

I have a matrix A which is defined as a tensor in tensorflow, of n rows and p columns. Moreover, I have say k matrices B1,..., Bk with p rows and q columns. My goal is to obtain a resulting matrix C of n rows and q columns where each row of C is the matrix product of the corresponding row in A with one of the B matrices. Which B to choose is determined by a give index vector I of dimension n that can take values ranging from 1 to k. In my case, the B are weight variables while I is another tensor variable given as input.
An example of code in numpy would look as follows:
A = array([[1, 0, 1],
[0, 0, 1],
[1, 1, 0],
[0, 1, 0]])
B1 = array([[1, 1],
[2, 1],
[3, 6]])
B2 = array([[1, 5],
[3, 2],
[0, 2]])
B = [B1, B2]
I = [1, 0, 0, 1]
n = A.shape[0]
p = A.shape[1]
q = B1.shape[1]
C = np.zeros(shape = (n,q))
for i in xrange(n):
C[i,:] = np.dot(A[i,:],B[I[i]])
How can this be translated in tensor flow?
In my specific case the variables are defined as:
A = tf.placeholder("float", [None, p])
B1 = tf.Variable(tf.random_normal(p,q))
B2 = tf.Variable(tf.random_normal(p,q))
I = tf.placeholder("float",[None])
This is a bit tricky and there are probably better solutions. Taking your first example, my approach computes C as follows:
C = diag([0,1,1,0]) * A * B1 + diag([1,0,0,1]) * A * B2
where diag([0,1,1,0]) is the diagonal matrix having vector [0,1,1,0] in its diagonal. This can be achieved through tf.diag() in TensorFlow.
For convenience, let me assume that k<=n (otherwise some B matrices would remain unused). The following script obtains those diagonal values from vector I and computes C as mentioned above:
k = 2
n = 4
p = 3
q = 2
a = array([[1, 0, 1],
[0, 0, 1],
[1, 1, 0],
[0, 1, 0]])
index_input = [1, 0, 0, 1]
import tensorflow as tf
# Creates a dim·dim tensor having the same vector 'vector' in every row
def square_matrix(vector, dim):
return tf.reshape(tf.tile(vector,[dim]), [dim,dim])
A = tf.placeholder(tf.float32, [None, p])
B = tf.Variable(tf.random_normal(shape=[k,p,q]))
# For the first example (with k=2): B = tf.constant([[[1, 1],[2, 1],[3, 6]],[[1, 5],[3, 2],[0, 2]]], tf.float32)
C = tf.Variable(tf.zeros((n, q)))
I = tf.placeholder(tf.int32,[None])
# Create a n·n tensor 'indices_matrix' having indices_matrix[i]=I for 0<=i<n (each row vector is I)
indices_matrix = square_matrix(I, n)
# Create a n·n tensor 'row_matrix' having row_matrix[i]=[i,...,i] for 0<=i<n (each row vector is a vector of i's)
row_matrix = tf.transpose(square_matrix(tf.range(0, n, 1), n))
# Find diagonal values by comparing tensors indices_matrix and row_matrix
equal = tf.cast(tf.equal(indices_matrix, row_matrix), tf.float32)
# Compute C
for i in range(k):
diag = tf.diag(tf.gather(equal, i))
mul = tf.matmul(diag, tf.matmul(A, tf.gather(B, i)))
C = C + mul
sess = tf.Session()
sess.run(tf.initialize_all_variables())
print(sess.run(C, feed_dict={A : a, I : index_input}))
As an improvement, C may be computed using a vectorized implementation instead of using a for loop.
Just do 2 matrix multiplications
A1 = A[0:3:3,...] # this will get the first last index of your original but just make a new matrix
A2 = A[1:2]
in tensorflow
A1 = tf.constant([matrix elements go here])
A2 = tf.constant([matrix elements go here])
B = ...
B1 = tf.matmul(A1,B)
B2 = tf.matmul(A2,B)
C = tf.pack([B1,B2])
granted if you need to reorganize the C tensor you can also use gather
C = tf.gather(C,[0,3,2,1])

Summing values of numpy array based on indices in other array

Assume I have the following arrays:
N = 8
M = 4
a = np.zeros(M)
b = np.random.randint(M, size=N) # contains indices for a
c = np.random.rand(N) # contains random values
I want to sum the values of c according to the indices provided in b, and store them in a. Writing a loop for this is trivial:
for i, v in enumerate(b):
a[v] += c[i]
Since N can get quite big in my real-world problem I'd like to avoid using python loops, but I can't figure out how to write it as a numpy-statement. Can anyone help me out?
Ok, here some example values:
In [27]: b
Out[27]: array([0, 1, 2, 0, 2, 3, 1, 1])
In [28]: c
Out[28]:
array([ 0.15517108, 0.84717734, 0.86019899, 0.62413489, 0.24357903,
0.86015187, 0.85813481, 0.7071174 ])
In [30]: a
Out[30]: array([ 0.77930596, 2.41242955, 1.10377802, 0.86015187])
import numpy as np
N = 8
M = 4
b = np.array([0, 1, 2, 0, 2, 3, 1, 1])
c = np.array([ 0.15517108, 0.84717734, 0.86019899, 0.62413489, 0.24357903, 0.86015187, 0.85813481, 0.7071174 ])
a = ((np.mgrid[:M,:N] == b)[0] * c).sum(axis=1)
returns
array([ 0.77930597, 2.41242955, 1.10377802, 0.86015187])

Categories

Resources