Yoel,

My solution wouldn't differ much from yours.  The first thing that occurs to me 
is to use multiple assignment, rather than picking indices from a matrix.  For 
example:

           'foo bar baz'=.'hello';12;i.2 2

           foo
        hello

           bar
        12

           baz
        0 1
        2 3

The next thing that occurs to me is a couple of extra features of dyad  {.  :

   (A)  The left rank is 1;  that is, we can change several dimensions 
simultaneously.   For example,  2 2 {. i. 4 4  is  0 1 ,: 2 3  .

   (B)  Infinite elements of  x  in  x{.y  select the entire corresponding 
dimension.  That is,  _ {. 1 2 3  is just  1 2 3  .  This feature is not 
documented.

So, I might rewrite your code like this:

           'a b c'=.dgesvd  ...
           a =. (_,M){.a
           b =. (M,M){.b
           c =. (M,_){.c
           approx =. a mp b mp c

In "real life", I might stop there.  The code is readable and maintainable.  
But, because you're new, we can take it a little further, to see the power of 
J.  

In the rewritten code, the first thing that sticks out at me is that one line 
of code is repeated 3 times (kinda).  What we have in each case is a  {.   ;  
the only thing that changes is its argument.  Similarly in the last line; we 
mention  mp  more than once, but the only thing that changed was its arguments.

That indicates to me that maybe we don't need to break the SVD matrix up in the 
first place.  Maybe we can use J's array processing power to treat it as a unit.

First, let's get rid of those three  {.  :

           ] SVD =.  i.&.>  5 5 ; 5 6 ; 6 6
        +--------------+-----------------+-----------------+
        | 0  1  2  3  4| 0  1  2  3  4  5| 0  1  2  3  4  5|
        | 5  6  7  8  9| 6  7  8  9 10 11| 6  7  8  9 10 11|
        |10 11 12 13 14|12 13 14 15 16 17|12 13 14 15 16 17|
        |15 16 17 18 19|18 19 20 21 22 23|18 19 20 21 22 23|
        |20 21 22 23 24|24 25 26 27 28 29|24 25 26 27 28 29|
        |              |                 |30 31 32 33 34 35|
        +--------------+-----------------+-----------------+
           
           M =. 3
           
           ] mSVD =: SVD {. L:0"_1~ (#:1 0 2) { M,_
        +--------------+--------+--------+
        | 0  1  2  3  4| 0  1  2| 0  1  2|
        | 5  6  7  8  9| 6  7  8| 6  7  8|
        |10 11 12 13 14|12 13 14|12 13 14|
        |              |        |18 19 20|
        |              |        |24 25 26|
        |              |        |30 31 32|
        +--------------+--------+--------+

To break that down:

           #:1 0 2

is just short way to write:

           0 1 , 0 0 ,: 1 0
  
we use those zeroes and ones to select from  M,_  , which results in
 
           3 _ , 3 3 ,: _ 3

Each pair of those numbers will become a left argument to  {.  .  We partner 
each pair with its corresponding matrix from SVD by using the rank conjunction:

           SVD (...)"_1~ 3 _ , 3 3 ,: _ 3

The  ~  just flips the arguments, so we're really dealing with:

           (3 _ , 3 3 ,: _ 3)  (...)"_1  SVD

The  "_1  uses the rank conjunction to pair of each set of numbers with its 
corresponding matrix from SVD.  Specicially, it pairs the items of the left 
with the items of the right.  The items on the right are the (boxed) SVD 
matrices, and the items on the left are those pairs of numbers.   So the 
function I elided  (...)  will be passed 3 sets of arguments, a pair of numbers 
on the left, and a boxed SVD matrix on the right.

The elided function is actually   {. L: 0  .  Because each SVD matrix is boxed, 
I couldn't use just  {.  .  Skipping the details,  in this case, you can think 
of  x {.L:0 y  as  < x {. > y  .  

That takes care of the repeated  {.  .  Now let's address that repeated  mp  :  

           ] approx =. > mp&.>/ |. mSVD
          525   624   723   822   921
         2595  3072  3549  4026  4503
         4665  5520  6375  7230  8085
         6735  7968  9201 10434 11667
         8805 10416 12027 13638 15249
        10875 12864 14853 16842 18831
           
To break down that line:

           |. mSVD

reverses the matricies in  mSVD and:

           mp&.>/

applies the matrix product between them, from right-to-left (that's why we had 
reverse the order).  

The final  >  merely opens the results.  Because  mSVD  is defined to have 3 
matricies, you could elide the  >  by writing  mp&:>/ |. mSVD  instead.  But  
>f&.>/y  is more general than  f&:>/y  and the latter only saves you one 
character.

So now we have no duplicate logic.  But did you notice something else?  With 
the duplicate logic, the variable names disappeared too.  The only variables 
mentioned are  SVD  , which is the input,  and  mSVD  , the output of the  {.  
logic.  But the output of the  {.  logic is just the input to the  mp  logic.  
I only gave it a name for the sake of this email; I wanted to break up the two 
steps.  

In fact, we could write the whole thing on one line:

           > mp&.>/ |. (dgesvd  ... ) {. L:0"_1~ (#:1 0 2) { M,_ 

Notice there are no variables, barring  M  .  This is pure function.  In fact, 
we could rewrite the whole thing as a single function; a dyad, whose left 
argument would be  M  and the right argument is the input to  dgesvd  :

           approxSVD =: [: mp&:>/ [: |. dgesvd@:] {. L:0"_1~ (#:1 0 2) { _ ,~ [

And that's why we use J.  Did this help?

-Dan


----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to