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