simple 1D example showing convolution vs correlation to test commutative/associative property - correlation

So I've known this fact that convolution has commutative/associative property while correlation does not but never really written out a simple example to test this out. (proofs in equation forms exist out there)
I was just trying this simple example:
Image : [1 0 -1 0 1 0 1 1]
A kernel = [-1 0 1]
B kernel = [-1 0 1]
Using convolution, I * (A * B) should equal (I * A) * B, but when I tried this they were not equal.. which confused me a lot. would anyone be able to help out? maybe I made a human error in doing computation.. but they should be equal right? (assuming borders are treated as 0s)
And using correlation, the same should not be equal as I understand.. which they dont, but then, my convolution did not either so lol (but it should!)
Any help would be appreciated.
also,
A*B (convolution) would be [0 -2 0] right?
and AxB (cross correlation) would be [0 2 0]?

The convolution operator is commutative. So, you are right that I*(A*B) should be equal to (I*A)*B. Let's convert this to matrix formation first. Convolution by kernel A can be translated to multiplication by the following convolution matrix, C:
C=
[-1 0 1 0 0 0 0 0]
[ 0 -1 0 1 0 0 0 0]
[ 0 0 -1 0 1 0 0 0]
[ 0 0 0 -1 0 1 0 0]
[ 0 0 0 0 -1 0 1 0]
[ 0 0 0 0 0 -1 0 1]
[ 1 0 0 0 0 0 -1 0]
[ 0 1 0 0 0 0 0 -1]
We have taken the kernel [-1 0 1] and zero-padded it by 5 zeros on first row. Then, each row below is a cyclic shift by 1 position to the right of the preceding row.
So, if we want to compute the convolution of kernel A with I:
I = [1 0 -1 0 1 0 1 1]
We simply compute the matrix-vector multiplication:
C*I^T
(where I^T is the transposed vector).
Following the above formulation, we obtain:
I*(A*B) = (C*C)*I^T
Computing C*C you get the following matrix:
C^2=
[ 1 0 -2 0 1 0 0 0]
[ 0 1 0 -2 0 1 0 0]
[ 0 0 1 0 -2 0 1 0]
[ 0 0 0 1 0 -2 0 1]
[ 1 0 0 0 1 0 -2 0]
[ 0 1 0 0 0 1 0 -2]
[-2 0 1 0 0 0 1 0]
[ 0 -2 0 1 0 0 0 1]
and:
I*(A*B) = (C*C)*I^T =
[ 4]
[ 0]
[-2]
[ 1]
[ 0]
[-2]
[-2]
[ 1]
whereas (I*A)*B is in matrix formulation C*(C*I^T) which is equal to I*(A*B)=(C*C)*I^T from matrix associativity.
You can validate this result by running the following numpy code:
import numpy as np
C = [[-1,0,1,0,0,0,0,0]]
for k in range(7):
C.append(np.roll(C[0],k+1))
C = np.array(C)
#print(C)
I = np.transpose(np.array([[1,0,-1,0,1,0,1,1]]))
print(f'C=\n{C}\n')
print(f'C^2=\n{C#C}\n')
print(f'(C*C)*I=\n{(C#C)#I}\n')
print(f' C*(C*I)=\n{C#(C#I)}\n')
The result of running the above code is:
C=
[[-1 0 1 0 0 0 0 0]
[ 0 -1 0 1 0 0 0 0]
[ 0 0 -1 0 1 0 0 0]
[ 0 0 0 -1 0 1 0 0]
[ 0 0 0 0 -1 0 1 0]
[ 0 0 0 0 0 -1 0 1]
[ 1 0 0 0 0 0 -1 0]
[ 0 1 0 0 0 0 0 -1]]
C^2=
[[ 1 0 -2 0 1 0 0 0]
[ 0 1 0 -2 0 1 0 0]
[ 0 0 1 0 -2 0 1 0]
[ 0 0 0 1 0 -2 0 1]
[ 1 0 0 0 1 0 -2 0]
[ 0 1 0 0 0 1 0 -2]
[-2 0 1 0 0 0 1 0]
[ 0 -2 0 1 0 0 0 1]]
(C*C)*I=
[[ 4]
[ 0]
[-2]
[ 1]
[ 0]
[-2]
[-2]
[ 1]]
C*(C*I)=
[[ 4]
[ 0]
[-2]
[ 1]
[ 0]
[-2]
[-2]
[ 1]]
So you can see that the same result is obtained.
Note that A*B is not [0 -2 0] but [1 0 -2 0 1] because you take A=[-1 0 1] (zero pad it on both sides to it has 2 zeros on each side) and move it as a sliding window over B=[-1 0 1] so first you get: [-1-1, 0-1 + -10, -11 + 00 + 1-1, 10 + 01, 11] = [1 0 -2 0 1]. The resulting convolution of 2 kernels of width n will be of length 2n-1.

Related

Find 4-neighbors using J

I'm trying to find the 4-neighbors of all 1's in a matrix of 0's and 1's using the J programming language. I have a method worked out, but am trying to find a method that is more compact.
To illustrate, let's say I have the matrix M—
] M=. 4 4$0 0 0 0 0 0 1 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
and I want to generate—
0 0 1 0
0 1 0 1
0 0 1 0
0 0 0 0
I've sorted something close (which I owe to this little gem: https://www.reddit.com/r/cellular_automata/comments/9kw21u/i_made_a_34byte_implementation_of_conways_game_of/)—
] +/+/(|:i:1*(2 2)$1 0 0 1)&|.M
0 0 1 0
0 1 2 1
0 0 1 0
0 0 0 0
which is fine because I'll be weighting the initial 1's anyway (and the actual numbers aren't really that important for my application anyway). But I feel like this could be more compact and I've just hit a wall. And the compactness of the expression actually is important to my application.
Building on #Eelvex comment solution, if you are willing to make the verb dyadic it becomes pretty simple. The left argument can be the rotation matrix and then the result is composed with +./ which is a logical or and can be weighted however you want.
] M0=. 4 4$0 0 0 0 0 0 1 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
] m =.2,\5$0,i:1
0 _1
_1 0
0 1
1 0
m +./#:|. M0
0 0 1 0
0 1 0 1
0 0 1 0
0 0 0 0
There is still an issue with the edges (which wrap) around, but that also occurs with your original solution, so I am hoping that you are not concerned with that.
] M1=. 4 4$1 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 0 0 0
m +./#:|. M1
0 1 0 1
1 0 0 0
0 0 0 0
1 0 0 0
If you did want to clean that up, you can use the slightly longer m +./#:(|.!.0), which fills the rotation with 0's.
] M2=. 4 4$ 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
0 0 0 1
m +./#:(|.!.0) M2
0 0 0 0
0 0 0 0
0 0 0 1
0 0 1 0
m +./#:(|.!.0) M1
0 1 0 0
1 0 0 0
0 0 0 0
0 0 0 0

Reverse SHA-256 sigma0 function within complexity of O(n)?

Introduction
As a part of SHA-256 hashing algorithm, there's a function that is often being referred as σ1, or sigma0 for convenience. Basically, it takes X as input, where X is 32-bit unsigned value. Then converts it like this:
ROTATE_RIGHT(X, 7) ^ ROTATE_RIGHT(X, 18) ^ SHIFT_RIGHT(X, 3)
A bit of explanation, if you need one:
ROTATE_RIGHT(X, Y) - rotates X's bits to the right by Y
SHIFT_RIGHT(X, Y) - shifts X's bits to the right by Y, so the first Y bits of the result are always 0
Also, if you need the code, here's the full version in Python:
def rotate_right(x, y):
return (((x & 0xffffffff) >> (y & 31)) | (x << (32 - (y & 31)))) & 0xffffffff
def shift_right(x, n):
return (x & 0xffffffff) >> n
def sigma0(x):
return rotate_right(x, 7) ^ rotate_right(x, 18) ^ shift_right(x, 3)
Reverse function
I started wondering if that thing is reversible, and, to my surprise, it didn't take long to write a function which, by given sigma0's output, returns input of that function, or, simply put, reverses sigma0 function. I won't put the code here, because it was written in Node.js and modified a lot by more complex needs of searching particular sigma0 inputs by masks, but I'd like to give you a basic idea of how I solved it, so maybe you could enlighten me with some fresh ideas on how to achieve what I need.
My solution is simple, but it is also recursive. We know that every output's bit is the result of XOR operation of two or three input's bits. So I made a dependence table so that I can see how are output's bits are being affected by input ones:
I: 00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
R7 25,26,27,28,29,30,31,00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24
R18 14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,00,01,02,03,04,05,06,07,08,09,10,11,12,13
S3 zz,zz,zz,00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28
---------------------------------------------------------------------------------------------------
O: 00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
What is this thing about? Say, in the output's 1st bit we have 1. For convenience, I'll write it as O[0], O[1], ... O[31], so O[x] is (x+1)th bit of the output. The same for input, marked as I.
So, O[0] == 1. In the table above we see that O[0] is the result of XOR operation of I[25] and I[14]. Which implies that one and only one of those input's bits must be 1. So at this point we could say that we can create two suitable masks for the input:
##############0#########1#######
##############1#########0#######
Those masks are key to the solution, at least, to mine. # means any value (0 or 1). When we create masks, we call the recursive function for the next bit, but preserving the mask. If we are out of possible masks that would suit previous mask, the previous mask has no solution, and if we reach 32nd bit, we're guaranteed to have no sharps in the masks, and this will be the answer.
First, I need to tell you that this thing works. But on Node.js it calculates every value for about 100ms and I have no idea what is the worst complexity of my recursion algorithm, because it's quite hard to measure. It doesn't satisfy me, and I broke my brains trying to solve this O(n).
Problem
I'm wondering if it's possible to write a function that reverses sigma0 within complexity of O(n), where n is amount of bits in the input/output and it equals to 32, without recursion, masks or trees, simply and fast.
I haven't concluded any mathematical proof for my statement, but I tested lots of different values and I can confidently claim that the amount of input values is equal to the amount of output values of this function, and both are equal to 2^32 - 1. In other words, for every output, there is one and only one possible input of sigma0 function.
Which gives me a thought that the fact sigma0 original function produces result with complexity of O(n) implies that the reverse function must have a solution that also works O(n).
If you mathematically prove me that this is impossible, I'd also accept this answer, but I haven't found anything that would indicate the impossibility of this task.
Resource-devouring workaround
In case I had free 16gb of ram, I'd be able to pre-calculate all the possible values into the file, and then load it into ram as a huge array. But it's not a solution since there are other 3 similar functions, and to do that for all of them I'd need 64gb of ram which is too expensive and excessive for this simple task.
UPD: Gaussian Elimination
Thanks to Artjom B.'s comment, I found a great way to solve XOR equations via Gaussian Elimination. Currently I'm trying to solve a matrix like this:
Input: 00000000100110101000111011101001
Output: 01110001101010000010010011100110
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 1 0 0 0 0 0 0 | 0
1: 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 1 0 0 0 0 0 | 1
2: 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 1 0 0 0 0 | 1
3: 1 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 1 0 0 0 | 1
4: 0 1 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 1 0 0 | 0
5: 0 0 1 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 1 0 | 0
6: 0 0 0 1 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 1 | 0
7: 1 0 0 0 1 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 | 1
8: 0 1 0 0 0 1 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 | 1
9: 0 0 1 0 0 0 1 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
10: 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 | 1
11: 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 | 0
12: 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 | 1
13: 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 | 0
14: 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 | 0
15: 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 | 0
16: 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 | 0
17: 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 | 0
18: 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | 1
19: 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | 0
20: 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | 0
21: 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 | 1
22: 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 | 0
23: 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 | 0
24: 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 | 1
25: 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 | 1
26: 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 | 1
27: 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 | 0
28: 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 | 0
29: 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 | 1
30: 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 | 1
31: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 | 0
Published the matrix so you could see how it looks and not waste your time on creating it by yourself. I'll update my question once I solved it or not.
If we view sigma0 as a function over a GF(2)32 vector, you will note that it's linear. Addition in GF(2)32 is just the binary XOR:
>>> sigma0(235 ^ 352124)
2045075788
>>> sigma0(235) ^ sigma0(352124)
2045075788
This means that if we can find sigma0(x0) = 0b1, sigma0(x1) = 0b10, etc we can easily invert anything bit-by-bit. We can easily find these inverses with z3:
import z3
def z3_sigma0(x):
return z3.RotateRight(x, 7) ^ z3.RotateRight(x, 18) ^ z3.LShR(x, 3)
s = z3.Solver()
xs = [z3.BitVec(f"x{i}", 32) for i in range(32)]
for i in range(32):
s.add(z3_sigma0(xs[i]) == (1 << i))
print(s.check())
m = s.model()
for i in range(32):
print("x{:02} = 0x{:08x}".format(i, m[xs[i]].as_long()))
This instantly outputs:
sat
x00 = 0x185744e9
x01 = 0x30ae89d2
x02 = 0x615d13a4
x03 = 0xdaed63a1
x04 = 0x9cd03a8e
x05 = 0x08fdcc39
x06 = 0x11fb9872
x07 = 0x23f730e4
x08 = 0x5fb92521
x09 = 0xbf724a42
x10 = 0x57ee6948
x11 = 0xafdcd290
x12 = 0x76b358ec
x13 = 0xf531f531
x14 = 0xc36917ae
x15 = 0xb78f9679
x16 = 0x4615d13e
x17 = 0x947ce695
x18 = 0x19a4740f
x19 = 0x2b1facf7
x20 = 0x4e681d07
x21 = 0x84877ee7
x22 = 0x385344eb
x23 = 0x70a689d6
x24 = 0xf91a5745
x25 = 0xc36917af
x26 = 0xb78f967b
x27 = 0x4615d13a
x28 = 0x8c2ba274
x29 = 0x290afdcd
x30 = 0x4a42bf73
x31 = 0x94857ee6
Thus we can use this to make our inversion function:
sigma0_singleton_inverses = [
0x185744e9, 0x30ae89d2, 0x615d13a4, 0xdaed63a1, 0x9cd03a8e, 0x08fdcc39,
0x11fb9872, 0x23f730e4, 0x5fb92521, 0xbf724a42, 0x57ee6948, 0xafdcd290,
0x76b358ec, 0xf531f531, 0xc36917ae, 0xb78f9679, 0x4615d13e, 0x947ce695,
0x19a4740f, 0x2b1facf7, 0x4e681d07, 0x84877ee7, 0x385344eb, 0x70a689d6,
0xf91a5745, 0xc36917af, 0xb78f967b, 0x4615d13a, 0x8c2ba274, 0x290afdcd,
0x4a42bf73, 0x94857ee6
]
def inv_sigma0(x):
r = 0
for i in range(32):
if x & (1 << i):
r ^= sigma0_singleton_inverses[i]
return r
And indeed:
>>> def test_inv_once():
... r = random.randrange(2**32)
... return inv_sigma0(sigma0(r)) == r
>>> all(test_inv_once() for _ in range(10**6))
True
The above can be written completely loopless and branchless:
def inv_sigma0(x):
xn = ~x
r = (((xn >> 0) & 1) - 1) & 0x185744e9
r ^= (((xn >> 1) & 1) - 1) & 0x30ae89d2
r ^= (((xn >> 2) & 1) - 1) & 0x615d13a4
r ^= (((xn >> 3) & 1) - 1) & 0xdaed63a1
r ^= (((xn >> 4) & 1) - 1) & 0x9cd03a8e
r ^= (((xn >> 5) & 1) - 1) & 0x08fdcc39
r ^= (((xn >> 6) & 1) - 1) & 0x11fb9872
r ^= (((xn >> 7) & 1) - 1) & 0x23f730e4
r ^= (((xn >> 8) & 1) - 1) & 0x5fb92521
r ^= (((xn >> 9) & 1) - 1) & 0xbf724a42
r ^= (((xn >> 10) & 1) - 1) & 0x57ee6948
r ^= (((xn >> 11) & 1) - 1) & 0xafdcd290
r ^= (((xn >> 12) & 1) - 1) & 0x76b358ec
r ^= (((xn >> 13) & 1) - 1) & 0xf531f531
r ^= (((xn >> 14) & 1) - 1) & 0xc36917ae
r ^= (((xn >> 15) & 1) - 1) & 0xb78f9679
r ^= (((xn >> 16) & 1) - 1) & 0x4615d13e
r ^= (((xn >> 17) & 1) - 1) & 0x947ce695
r ^= (((xn >> 18) & 1) - 1) & 0x19a4740f
r ^= (((xn >> 19) & 1) - 1) & 0x2b1facf7
r ^= (((xn >> 20) & 1) - 1) & 0x4e681d07
r ^= (((xn >> 21) & 1) - 1) & 0x84877ee7
r ^= (((xn >> 22) & 1) - 1) & 0x385344eb
r ^= (((xn >> 23) & 1) - 1) & 0x70a689d6
r ^= (((xn >> 24) & 1) - 1) & 0xf91a5745
r ^= (((xn >> 25) & 1) - 1) & 0xc36917af
r ^= (((xn >> 26) & 1) - 1) & 0xb78f967b
r ^= (((xn >> 27) & 1) - 1) & 0x4615d13a
r ^= (((xn >> 28) & 1) - 1) & 0x8c2ba274
r ^= (((xn >> 29) & 1) - 1) & 0x290afdcd
r ^= (((xn >> 30) & 1) - 1) & 0x4a42bf73
r ^= (((xn >> 31) & 1) - 1) & 0x94857ee6
return r
The fastest version probably probably is this one, grouping by 16 bits at a time using a 2 × 216 size lookup table (or similarly four lookups into a 4 × 28 sized table).
sigma0_16bit_inverse_lo = [inv_sigma0(x) for x in range(2**16)]
sigma0_16bit_inverse_hi = [inv_sigma0(x << 16) for x in range(2**16)]
def fast_inv_sigma0(x):
return (sigma0_16bit_inverse_lo[x & 0xffff] ^
sigma0_16bit_inverse_hi[(x >> 16) & 0xffff])

Is there a way to show the index of atoms in rdkit.Chem.rdmolops.GetAdjacencyMatrix?

I'm trying to convert a compound from mol to adjacency matrix. However, i encountered a problem that rdkit.Chem.rdmolops.GetAdjacencyMatrix() doesn't provide the index of the atoms for the adjacency matrix. Is there any way to include the index data for the adjacency matrix in rdkit?
rdkit.Chem.rdmolops.GetAdjacencyMatrix((Mol)mol)
As the RDKit AdjacencyMatrix is ordered from zero upwards, you can convert it to a Pandas dataframe.
from rdkit import Chem
import pandas as pd
s = 'CCC(C(O)C)CN'
mol = Chem.MolFromSmiles(s)
am = Chem.GetAdjacencyMatrix(mol)
print(am)
[[0 1 0 0 0 0 0 0]
[1 0 1 0 0 0 0 0]
[0 1 0 1 0 0 1 0]
[0 0 1 0 1 1 0 0]
[0 0 0 1 0 0 0 0]
[0 0 0 1 0 0 0 0]
[0 0 1 0 0 0 0 1]
[0 0 0 0 0 0 1 0]]
df = pd.DataFrame(am)
print(df)
0 1 2 3 4 5 6 7
0 0 1 0 0 0 0 0 0
1 1 0 1 0 0 0 0 0
2 0 1 0 1 0 0 1 0
3 0 0 1 0 1 1 0 0
4 0 0 0 1 0 0 0 0
5 0 0 0 1 0 0 0 0
6 0 0 1 0 0 0 0 1
7 0 0 0 0 0 0 1 0
If you want elements instead of indices
element = [atom.GetSymbol() for atom in mol.GetAtoms()]
print(element)
['C', 'C', 'C', 'C', 'O', 'C', 'C', 'N']
df_e = pd.DataFrame(am, index=element, columns=element)
print(df_e)
C C C C O C C N
C 0 1 0 0 0 0 0 0
C 1 0 1 0 0 0 0 0
C 0 1 0 1 0 0 1 0
C 0 0 1 0 1 1 0 0
O 0 0 0 1 0 0 0 0
C 0 0 0 1 0 0 0 0
C 0 0 1 0 0 0 0 1
N 0 0 0 0 0 0 1 0

C/C++ wavelet library that return also the NxN wavelet matrix

I am looking for a C++ library for Discrete Wavelet Transform (DWT) which can also return
the NxN DWT matrix of the transform.
There was a similar question opened here
Looking for a good C/C++ wavelet library for signal processing
but I am looking for something more specific as you can see.
It would be more helpful if the library is under some non-GNU license that lets me use it in proprietary software (LGPL, MPL, BSD etc.)
Thanks in advance
The reason why this matrix is never computed is that it is very inefficient to compute the DWT using it. The FWT approach is much faster.
For a signal of length 16 and a 3-level haar transform, I found that this matrix in matlab
>> h=[1 1];
>> g=[1 -1];
>> m1=[[ones(1,8) zeros(1,8); ...
zeros(1,8) ones(1,8); ...
1 1 1 1 -1 -1 -1 -1 zeros(1,8); ...
zeros(1,8) 1 1 1 1 -1 -1 -1 -1]/sqrt(8); ...
[1 1 -1 -1 zeros(1,12); ...
zeros(1,4) 1 1 -1 -1 zeros(1,8); ...
zeros(1,8) 1 1 -1 -1 zeros(1,4); ...
zeros(1,12) 1 1 -1 -1]/sqrt(4); ...
[g zeros(1,14); ...
zeros(1,2) g zeros(1,12); ...
zeros(1,4) g zeros(1,10); ...
zeros(1,6) g zeros(1,8); ...
zeros(1,8) g zeros(1,6); ...
zeros(1,10) g zeros(1,4); ...
zeros(1,12) g zeros(1,2); ...
zeros(1,14) g]/sqrt(2)]
m1 =
A A A A A A A A 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 A A A A A A A A
A A A A -A -A -A -A 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 A A A A -A -A -A -A
B B -B -B 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 B B -B -B 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 B B -B -B 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 B B -B -B
C -C 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 C -C 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 C -C 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 C -C 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 C -C 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 C -C 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 C -C 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 C -C
where A=1/sqrt(8), B=1/sqrt(4) and C=1/sqrt(2).
corresponds to the FWT. That shows you how you build your matrix from the filters. You start with the bottom half of the matrix --a matrix of zeroes, putting filter g 2 steps further every row. then make the filter twice as wide and repeat, only now shift 4 steps at a time. repeat this until you are at the highest level of decomposition, the finally put the approximation filter in at the same width (here, 8).
just as a check
>> signal=1:16; % ramp
>> [h g]=daubcqf(2); % Haar coefficients from the Rice wavelet toolbox
>> fwt(h,signal,3) % fwt code by Jeffrey Kantor
>> m1*signal' % should produce the same vector
Hope that helps you writing it in C++. It is not difficult (a bit of bookkeeping) but as said, noone uses it because efficient algorithms do not need it.

Diag Function to create a matrix

How would I go about creating the matrix
[1 2 0 0 0;
-1 1 2 0 0;
0 -1 1 2 0;
0 0 -1 1 2;
0 0 0 -1 1]
using the diag command in MatLab?
Here is one way:
> diag(ones(1,5),0)+diag(ones(1,4),1)*2+diag(ones(1,4),-1)*-1
ans =
1 2 0 0 0
-1 1 2 0 0
0 -1 1 2 0
0 0 -1 1 2
0 0 0 -1 1
>
This just creates three diagonals at 0, +1 and -1, scales them as needed, then adds them.

Resources