That's basically it. The purpose was -- as you stated -- is to calculate "the unsigned angle in degrees between two vectors".
The dot product of two vectors is the cosine of the angle between them multiplied by the product of their magnitudes. So if we divide out the product of their magnitudes and take the arc cosine we get the (unsigned) angle. And, 0j_1 * ^. (j.-.&.*:) c finds the arc cosine of c. The discrepancies you noted are not significant in context - they're an artifact of how J handles epsilon (without regard to any input values), and rounding errors in that particular implementation of arc cosine. Note also that _2 o. c provides a better implementation of arc cosine. But, also, the real point here is that documentation artifacts -- and, especially statements of purpose (which might be in the form of use cases) are critical for efficient use of time when modifying (or even writing) programs. -- Raul On Wed, Aug 16, 2023 at 10:00 AM Jan-Pieter Jacobs <[email protected]> wrote: > > Caution, spoilers ahead! > > Interesting case! > Indeed some data might have helped. > > I recognized (+/ .*)&(% +/&.:*:) as the dot product between normalised > vectors, because I recently needed it as cosine similarity between > histograms of token frequencies between paragraphs of text for roughly > comparing their topics. > > It is clear from the code it's not meant to be applied on matrices (where > rows have instances and columns have variables) because then it would have > required a transpose around the matrix product to ensure the matrices are > normalised along the same axis). So I think it's meant for vectors. > > The rest I figured out from some tests: > mis=: 0j_180p_1*^.@(j.-.&.*:)@(+/ .*)&(% +/&.:*:) > 1 1 mis 0 1 > 45 > 2 2 mis 0 1 > 45 > 1 0 mis 0 1 > 90 > _1 0 mis 0 1 > 90 > > So I'd say it is the unsigned angle in degrees between two vectors. I have > to say the complex phrasing after the cosine distance, both in the > mathematical as in the common sense, baffled me a bit... > > I would simplify using arccos: > simp=: (180p_1 * _2 o. (+/ .*)&(% +/&.:*:)) > > It seems this would be off only by some rounding errors on my test: > > test=: 100 3?.@$0 > (mis"1/~ -: simp"1/~) test NB. equal? > 0 > > +/,(mis"1/~ = simp"1/~) test NB. # of correct > 9964 > > +/-.,(mis"1/~ = simp"1/~) test NB. # of wrong > 36 > w=: ($#:I.@,) (mis"1/~ ~:simp"1/~)test NB. coords of wrong pairs in test > $w{test > 36 2 3 > >./ | +. (mis/"2 - simp/"2) w{test NB. max deviation of real and > imaginary parts > 1.23179e_13 6.36111e_15 > > This can likely be simplified more if it's meant to work only on 2D vectors. > > I guess this one is a good reminder that having a concise language doesn't > mean one has to forgo writing sensible comments. > > Jan-Pieter > > On Wed, 16 Aug 2023, 13:34 Raul Miller, <[email protected]> wrote: > > > Given a J expression: > > 0j_180p_1*^.@(j.-.&.*:)@(+/ .*)&(% +/&.:*:) > > > > (1) Describe its purpose, and > > > > (2) Use that to simplify the expression. > > > > Here, the biggest hurdle is extracting the purpose from even a short > > bit of code. I'm not sure that extracting purpose from code is > > particularly viable in the general case. (Though having example > > arguments would be a tremendous help.) Once that's done, the rest is > > much easier. > > > > -- > > Raul > > ---------------------------------------------------------------------- > > For information about J forums see http://www.jsoftware.com/forums.htm > > > ---------------------------------------------------------------------- > For information about J forums see http://www.jsoftware.com/forums.htm ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
