APL: Matrix manipulation trick?

I am trying to find a way (idiomatic or otherwise) to transform a matrix that looks like

0 1 0 1 0 1 

into 3 separate matrices

 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 

so when I OR all together, I get the original. Each of these “submatrices” should have only one nonzero element and should have the same shape as the original.

+4
source share
3 answers

One solution:

Any Boolean matrix:

  m←4 3⍴?12⍴2 m 0 0 1 0 0 0 1 1 0 0 1 0 

Pay attention to its form:

  d←⍴m d 4 3 

Ravel matrix in vector:

  v←,m v 0 0 1 0 0 0 1 1 0 0 1 0 

Create Indexes:

  i ←⍳⍴v i 0 1 2 3 4 5 6 7 8 9 10 11 

Build 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 

Check the result:

  ↑∨/a 0 0 1 0 0 0 1 1 0 0 1 0 

There is probably a good way to do this using indexing markup, first creating a three-dimensional matrix, and then specifying the location of 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 
+3
source

For 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 

Divide it into composite matrices as follows:

 +(⍴A)∘⍴¨⊂[2](,A)\BB⍴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 a number from 1 to B:

 B←+/,A ⍝ 5 

Create an identity matrix as described in this post: The most idiomatic way to create an identity matrix in the APL :

 BB⍴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 source matrix:

 ,A ⍝ 1 0 1 0 1 0 0 0 0 1 0 1 

Use a split matrix to expand the identity matrix. This creates a matrix in which each row is an uninhibited form of component matrices:

 +(,A)\BB⍴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 this matrix to a row vector:

 +⊂[2](,A)\BB⍴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 form A (⍴A) , create the final matrices:

 (⍴A)∘⍴¨⊂[2](,A)\BB⍴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 
+3
source

With Dyalog APL version 16.0, you can now write it very concisely with the silent function ⍸{ ~@ (⊂⍺)≠⍨⍵}⍤0 2⊢ . At the bottom of this post, you'll learn how to get a list of matrices.

Try it online!

How it works?

This is fork, so the results of and are left and right arguments for { ~@ (⊂⍺)≠⍨⍵}⍤0 2 .

gives a list of indices in which the argument <1>

only yield with unmodified argument

{ ... }⍤0 2 applies the following dfn with each rank-0 subarray of the left argument (that is, each index 1) as the left argument and each rank-2 subgroup of the right argument (that is, the whole matrix) as right argument

≠⍨⍵ unequal selfie argument on the right ; gives a matrix of the same shape, but filled with zeros

~@ (⊂⍺) this flips the (logical non ) bit to the position indicated by the argument to the left

So, for each 1, it creates a layer with a zero level, where the bit in its position is turned upside down.


How to get a list of matrices instead:

⍸{ ~@ (⊂⍺)≠⍨⍵}¨⊂ gives a list of matrices to ⍸{ ~@ (⊂⍺)≠⍨⍵}¨⊂ . Try it online!

This works identically, but instead of using the rank operator to work with the entire array, we use ¨⊂ to pair each index 1 with the entire matrix.

0
source

Source: https://habr.com/ru/post/1491738/


All Articles