I'm trying to find a way (idiomatic or otherwise) to transform a matrix that looks like
0 1
0 1
0 1
into 3 individual matrices
0 1
0 0
0 0
0 0
0 1
0 0
0 0
0 0
0 1
so that when I OR all of them together, I get the original. Each of these "sub-matrices" have to have 1 non-zero element only and must have the same shape as the original.
One solution:
Any boolean matrix:
m←4 3⍴?12⍴2
m
0 0 1
0 0 0
1 1 0
0 1 0
Note its shape:
d←⍴m
d
4 3
Ravel the matrix into a vector:
v←,m
v
0 0 1 0 0 0 1 1 0 0 1 0
Generate indices:
i ←⍳⍴v
i
0 1 2 3 4 5 6 7 8 9 10 11
Construct a matrix for each 1 in the original matrix:
a←d∘⍴¨↓(v/i)∘.=i
a
0 0 1 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 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0
Verify result:
↑∨/a
0 0 1
0 0 0
1 1 0
0 1 0
There is probably a nice way to do this using scatter point indexing as well, by first generating a 3 dimensional matrix and then specifying the location of the 1s.
Yes there is, using v and d as above:
n←+/v
b←(n,d)⍴0
b[↓⍉(⍳n)⍪d⊤v/⍳⍴v]←1
b
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 0
0 1 0
0 0 0
0 0 0
0 0 0
0 0 0
0 1 0
∨⌿b
0 0 1
0 0 0
1 1 0
0 1 0
Given a vector A:
+A←3 4⍴1 0 1 0 1 0 0 0 0 1 0 1
1 0 1 0
1 0 0 0
0 1 0 1
Break it down into component matrices as follows:
+(⍴A)∘⍴¨⊂[2](,A)\B B⍴1,(B←+/,A)⍴0
1 0 0 0 0 0 1 0 0 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 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1
How it works
First assign the number of 1s to B:
B←+/,A ⍝ 5
Create an identity matrix as discussed in this post: The most idiomatic way of creating identity matrix in APL :
B B⍴1,(B←+/,A)⍴0
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
Ravel the original matrix:
,A ⍝ 1 0 1 0 1 0 0 0 0 1 0 1
Use the raveled matrix to expand the identity matrix. That creates a matrix wherein each row is the raveled form of the component matrices:
+(,A)\B B⍴1,(B←+/,A)⍴0
1 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 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 0 0 0 1
Convert that matrix into a vector of the rows:
+⊂[2](,A)\B B⍴1,(B←+/,A)⍴0
1 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 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 0 0 0 1
Using the original shape of A (⍴A)
, create the final matrices:
(⍴A)∘⍴¨⊂[2](,A)\B B⍴1,(B←+/,A)⍴0
1 0 0 0 0 0 1 0 0 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 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1
With Dyalog APL version 16.0 you can now write this very succinctly with the tacit function ⍸{~@(⊂⍺)≠⍨⍵}⍤0 2⊢
. See the bottom of this post for how to get a list of matrices instead.
How does it work?
It is a fork, where so the results of ⍸
and of ⊢
are the left and right arguments to {~@(⊂⍺)≠⍨⍵}⍤0 2
.
⍸
gives a list of indices where there are 1s in the argument
⊢
just yield s the unmodified argument
{
… }⍤0 2
applies the following dfn with each rank-0 subarray of the left argument (ie each index of a 1) as left argument and each rank-2 subarray of the right argument (ie the entire matrix) as right argument
≠⍨⍵
unequal selfie of the right argument ; gives a matrix of same shape but filled with zeros
~@(⊂⍺)
this flips (logical not ) the bit at the position indicated by the left argument
So, for each 1, it creates an all-zero layer where the bit in its position is flipped.
How to get a list of matrices instead:
⍸{~@(⊂⍺)≠⍨⍵}¨⊂
gives a list of the desired matrices. Try it online!
This works identically, but instead of using the rank operator to operate on the entire array, we use ¨⊂
to pair each index of a 1 with the entire matrix.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.