Kronecker product of 3 matrices using Python - python

Suppose that we have 2 2X2 numpy arrays:
X=np.array([[0,1],[1,0]])
and
I=np.array([[1,0],[0,1]])
Consider the Kronecker product
XX=X^X
where I have let the symbol ^ be the symbol for Kronecker product. This can easily be computed via the numpy.kron() function in python:
import numpy as np
kronecker_product = np.kron(X, X)
Now, suppose that we want to compute
XX=I^X^X
numpy.kron() only takes two arrays as arguments and expects them to be the same dimension. How can I perform this operation using numpy.kron() or other technique in python?

As with anything like this, try:
XX = np.kron(I, np.kron(X, X))
Output:
>>> XX
array([[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0]])
You can nest calls to kron any number of times. For example, for XX = A^B^C^D^E, use
XX = np.kron(A, np.kron(B, np.kron(C, np.kron(D, E))))
If you don't like the verbosity there, you could create an alias for np.kron:
k = np.kron
XX = k(A, k(B, k(C, k(D, E))))
Or, better yet, use reduce from the Python built-in module functools to do it in an even more readable fashion:
import functools as ft
lst = [A, B, C, D, E]
XX = ft.reduce(np.kron, lst)
Note: I tested all of this and it works perfectly.

Related

Plot a tree from multiple adjacency matrices

I'm trying to plot a tree from multiple adjacency matrices. To better explain, I will do an example with 3 matrices. I have 3 matrices a, b and c. The rows of a point to the columns of a. The columns of a, that have the same name of the rows of b, point to the columns of b, and so on with the c matrix.
So, the a rows are the 1st level of the tree, the b rows (a columns) are the 2nd, the c rows (b columns) are the 3rd.
These are the adjacency matrices:
#Adjacency matrices
a = [[2, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 1, 0, 0, 1]]
b = [[2, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 3, 0],
[1, 0, 0, 0, 0, 0, 1]]
c = [[2, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 2, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 2, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 1, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 3, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 1, 0]]
I convert them to pandas datafames to give the names to the nodes
import pandas as pd
data_a = pd.DataFrame(a)
data_a.index = ['0a','0b','0c']
data_a.columns = ['1a','1b','1c','1d','1e']
data_b = pd.DataFrame(b)
data_b.index = data_a.columns
data_b.columns = ['2a','2b','2c','2d','2e','2f','2g']
data_c = pd.DataFrame(c)
data_c.index = data_b.columns
data_c.columns = ['3a','3b','3c','3d','3e','3f','3g','3h','3i']
Data are now structured in this way:
I would like to obtain, from these adjacency matrix, a tree with a structure like this, or any other graphical representation possible:
What can I do?
I propose to combine the three adjacency matrices a, b, c into a single adjacency matrix.
aa ab ..
ba bb bc
.. cb cc
Then you can use plot(layout=layout_with_sugiyama) in [R], [rigraph] to visualize a tree-like structure.

Generate multiple arrays simultaniously in python

Assuming that amount is the amount of the array, and b is the length of an array. I have no idea how to fill this
def MultiList(amount,length)
I want to if i call MultiList function like
MultiList(5,5)
Yhe output will be
(array ([0,0,0,0,0]), array ([0,0,0,0,0]), array ([0,0,0,0,0]), array ([0,0,0,0,0]),array ([0,0,0,0,0]))
For your simple case:
def gen_multi_list(amount, length, value=0):
return [[value]*length for _ in range(amount)]
print(gen_multi_list(5,5))
The output:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
You can use numpy tuple to do this task.
import numpy as np
def multilist(amount, length):
return tuple(np.zeros(length, dtype=np.int) for _ in range(amount))
print(multilist(5,5))
Output :
(array([0, 0, 0, 0, 0]), array([0, 0, 0, 0, 0]), array([0, 0, 0, 0, 0]), array([0, 0, 0, 0, 0]), array([0, 0, 0, 0, 0]))
You can create the multiple array just using consecutive loops in function. to create list of list then convert it into tuple as we want tuple like output.
def Multilist(amount, length):
tup = [];
for i in range(amount):
arr = []
for j in range(length):
arr.append(0)
tup.append(arr)
return tuple(tup)
print(Multilist(5,5))
Output :
([0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0])
Multilist = lambda amount, length : tuple([[0]*amount ]*length)
print(Multilist(5,5))
Output:
([0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0])

How can I manipulate a list of lists?

How can i iterate through a list of lists so as to make any of the lists with a "1" have the top(0), top left(0), top right(0), bottom(0), bottom right(0),bottom left(0) also become a "1" as shown below? making list 1 become list 2
list_1 =[[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0],
[0,0,0,0,0,0,0,0]]
list_2 =[[0,0,0,0,0,0,0,0],
[0,0,1,1,1,0,0,0],
[0,0,1,1,1,0,0,0],
[0,0,1,1,1,0,0,0]]
This is a common operation known as "dilation" in image processing. Your problem is 2-dimensional, so you would be best served using
a more appropriate 2-d data structure than a list of lists, and
an already available library function, rather than reinvent the wheel
Here is an example using a numpy ndarray and scipy's binary_dilation respectively:
>>> import numpy as np
>>> from scipy import ndimage
>>> a = np.array([[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0],
[0,0,0,0,0,0,0,0]], dtype=int)
>>> ndimage.binary_dilation(a, structure=ndimage.generate_binary_structure(2, 2)).astype(a.dtype)
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0]])
With numpy, which is more suitable to manipulate 2D list in general. If you're doing image analysis, see #wim answer. Otherwise here is how you could manage it with numpy only.
> import numpy as np
> list_1 =[[0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0],
[0,0,0,0,0,0,0,0]]
> l = np.array(list_1) # convert the list into a numpy array
> pos = np.where(l==1) # get the position where the array is equal to one
> pos
(array([2]), array([3]))
# make a lambda function to limit the lower indexes:
get_low = lambda x: x-1 if x>0 else x
# get_high is not needed.
# slice the array around that position and set the value to one
> l[get_low(pos[0]):pos[0]+2,
get_low(pos[1]):pos[1]+2] = 1
> l
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0]])
> corner
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1]])
> p = np.where(corner==1)
> corner[get_low(p[0]):p[0]+2,
get_low(p[1]):p[1]+2] = 1
> corner
array([[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0, 1, 1]])
HTH

Generating all possible combinations of a zeros and b ones

Is there an efficient way to generate a list (or an array) of all possible combinations of say 2 ones and 8 zeros? E.g.
[[0,0,0,0,0,0,0,0,1,1],
[0,0,0,0,0,0,0,1,0,1,],
...]
This works, but there could be a better way?
import numpy as np
result = []
for subset in itertools.combinations(range(10), 2):
subset = list(subset)
c = np.zeros(10)
c[subset] = 1
result.append(c)
Would love to have some ideas on how to optimize this code.
Well, it's not much different but doing bulk operations on Numpy arrays is bound to have much less overhead:
import itertools
import numpy
which = numpy.array(list(itertools.combinations(range(10), 2)))
grid = numpy.zeros((len(which), 10), dtype="int8")
# Magic
grid[numpy.arange(len(which))[None].T, which] = 1
grid
#>>> array([[1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
#>>> [1, 0, 1, 0, 0, 0, 0, 0, 0, 0],
#>>> [1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
#>>> [1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
#>>> [1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
#>>> ...
The bulk of the time is then spent doing numpy.array(list(itertools.combinations(range(10), 2))). I tried using numpy.fromiter but I didn't get any speed improvements. Since half the time is literally generating the tuples, the only real way to improve further is to generate the combinations in something like C or Cython.
Alternative using numpy.bincount:
>>> [np.bincount(xs, minlength=10) for xs in itertools.combinations(range(10), 2)]
[array([1, 1, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int64),
array([1, 0, 1, 0, 0, 0, 0, 0, 0, 0], dtype=int64),
array([1, 0, 0, 1, 0, 0, 0, 0, 0, 0], dtype=int64),
array([1, 0, 0, 0, 1, 0, 0, 0, 0, 0], dtype=int64),
...]
Shouldn't we be using permutations for this? Eg,
from itertools import permutations as perm
a, b = 6, 2
print '\n'.join(sorted([''.join(s) for s in set(t for t in perm(a*'0' + b*'1'))]))

How to use combinations

I have 6 lists, say,
a=[1,1,0,0]
b=[0,1,1,0]
c=[0,0,1,1]
d .... until f.
I want to generate the results of the sum for all possible combination of the lists starting from 2 lists till 6 lists. For example, I want to calculate the result of a+b, a+c, .. a+f. Then, a+b+c, a+b+d, ...etc. I know hoe to compute the result of two or three lists but I am stuck in how to generate the combinations for lists. I tried to define list of lists and use combinations with argument 2 to generate all possible 2 combinations for 3 lists (as example) as follows:
import itertools
alphabet = [[0,0,0],[0,0,1],[0,1,0]]
combos = itertools.combinations(alphabet, 2)
usable_combos = []
for e in combos:
usable_combos.append(e)
But this simply does not produce anything. When I print usable_combos, I get:
[[0,0,0],[0,0,1],[0,1,0]]
My question is: using combinations, how can I produce all possible combinations (from 2 to 6 combinations) for the 6 different sets I have?
Use range(1, len(lis)+1) to get the value for the second parameter(r) that is passed to combinations. or range(2, len(lis)+1) if you want to start from 2.
>>> from itertools import combinations
>>> lis = [[0,0,0],[0,0,1],[0,1,0]]
>>> for i in range(1, len(lis)+1):
... for c in combinations(lis,i):
... print c
...
([0, 0, 0],)
([0, 0, 1],)
([0, 1, 0],)
([0, 0, 0], [0, 0, 1])
([0, 0, 0], [0, 1, 0])
([0, 0, 1], [0, 1, 0])
([0, 0, 0], [0, 0, 1], [0, 1, 0])
As pointed out may #abarnert in the comment, may be you want this:
>>> from pprint import pprint
>>> from itertools import chain
>>> flatten = chain.from_iterable
>>> ans = [list(flatten(c)) for i in range(2, len(lis)+1) for c in permutations(lis,i)]
>>> pprint(ans)
[[0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 0],
[0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 1, 0, 1, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 1],
[0, 0, 1, 0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 1],
[0, 1, 0, 0, 0, 1, 0, 0, 0]]

Categories

Resources