{"id":1854,"date":"2015-02-13T06:47:43","date_gmt":"2015-02-13T06:47:43","guid":{"rendered":"http:\/\/www.dyalog.com\/blog\/?p=1854"},"modified":"2015-02-13T07:47:22","modified_gmt":"2015-02-13T07:47:22","slug":"changes-of-heart","status":"publish","type":"post","link":"https:\/\/www.dyalog.com\/blog\/2015\/02\/changes-of-heart\/","title":{"rendered":"Changes of Heart"},"content":{"rendered":"<p>Karen Shaw started the ball rolling (hearts afluttering?) by asking Jay Foad to come up with a one-liner for St. Valentine&#8217;s Day; he then solicited contributions from the language development group. Nick Nickolov responded with the following, with no explanation other than that there is room for improvement:<\/p>\n<pre><code class=\"language-apl\">\u2395io\u21900 \u22c4 (\u22a2,\u233d)' X'[{(.5\u00d7n*2)&gt;+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a80\u2193n-\u2373(2\u00d7n),n\u219020]\r\n\r\n           XXXXX        XXXXX           \r\n         XXXXXXXXXX  XXXXXXXXXX         \r\n        XXXXXXXXXXXXXXXXXXXXXXXX        \r\n       XXXXXXXXXXXXXXXXXXXXXXXXXX       \r\n       XXXXXXXXXXXXXXXXXXXXXXXXXX       \r\n       XXXXXXXXXXXXXXXXXXXXXXXXXX       \r\n      XXXXXXXXXXXXXXXXXXXXXXXXXXXX      \r\n      XXXXXXXXXXXXXXXXXXXXXXXXXXXX      \r\n      XXXXXXXXXXXXXXXXXXXXXXXXXXXX      \r\n      XXXXXXXXXXXXXXXXXXXXXXXXXXXX      \r\n       XXXXXXXXXXXXXXXXXXXXXXXXXX       \r\n       XXXXXXXXXXXXXXXXXXXXXXXXXX       \r\n       XXXXXXXXXXXXXXXXXXXXXXXXXX       \r\n       XXXXXXXXXXXXXXXXXXXXXXXXXX       \r\n        XXXXXXXXXXXXXXXXXXXXXXXX        \r\n        XXXXXXXXXXXXXXXXXXXXXXXX        \r\n        XXXXXXXXXXXXXXXXXXXXXXXX        \r\n         XXXXXXXXXXXXXXXXXXXXXX         \r\n         XXXXXXXXXXXXXXXXXXXXXX         \r\n          XXXXXXXXXXXXXXXXXXXX          \r\n           XXXXXXXXXXXXXXXXXX           \r\n           XXXXXXXXXXXXXXXXXX           \r\n            XXXXXXXXXXXXXXXX            \r\n             XXXXXXXXXXXXXX             \r\n             XXXXXXXXXXXXXX             \r\n              XXXXXXXXXXXX              \r\n               XXXXXXXXXX               \r\n                XXXXXXXX                \r\n                 XXXXXX                 \r\n                   XX                   \r\n<\/code><\/pre>\n<p>Subsequently, Nick described how he derived the expression:<\/p>\n<div style=\"margin: 15px 30px 15px 30px;\">Between two meetings I saw Jay&#8217;s request for ideas. I sent him a <a href=\"http:\/\/mathworld.wolfram.com\/HeartCurve.html\">link<\/a> to the Heart Curve on MathWorld, but he thought we&#8217;d need graphics for that. To prove that ASCII art is good enough, I tried to plot the set of points (<i>x<\/i>,<i>y<\/i>) where (<i>x<\/i><sup>2<\/sup> + <i>y<\/i><sup>2<\/sup> \u2013 1)<sup>3<\/sup> \u2013 <i>x<\/i><sup>2<\/sup> <i>y<\/i><sup>3<\/sup> \u2248 0 but the interpreter crashed with a syserror for some reason. (I don&#8217;t recall what I last did and can&#8217;t reproduce it.) Since I had to type the whole thing again anyway and I hadn&#8217;t been too successful in visualising the solutions of the above equation, I decided to write it in a less beautiful but simpler way: draw half a circle, tilt it, and concatenate a mirror image to form a heart. The moment I got something that resembled a heart, I sent the email and went downstairs for coffee.<\/div>\n<p>Meanwhile, I changed Nick&#8217;s expression in steps in the process of trying to understand it. <code class=\"language-apl\">\u2395io\u21900<\/code> throughout.<\/p>\n<p><strong>a.<\/strong>\u00a0 <code class=\"language-apl\"> (\u22a2,\u233d)' X'[{(.5\u00d7n*2)&gt;+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a80\u2193n-\u2373(2\u00d7n),n\u219020]<\/code><br \/>\nNick&#8217;s original expression.<\/p>\n<p><strong>b.<\/strong> <code class=\"language-apl\"> ,\u2218\u233d\u2368' X'[{(.5\u00d7n*2)&gt;+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a80\u2193n-\u2373(2\u00d7n),n\u219020]<\/code><br \/>\nThe fork <code class=\"language-apl\">(\u22a2,\u233d)<\/code> computes <code class=\"language-apl\">x,\u233dx<\/code> without use of a temporary variable. It is equivalent to <code class=\"language-apl\">,\u2218\u233d\u2368<\/code>.<\/p>\n<p><strong>c.<\/strong> <code class=\"language-apl\"> ,\u2218\u233d\u2368' X'[{(.5\u00d7n*2)&gt;+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a8n-\u2373(2\u00d7n),n\u219020]<\/code><br \/>\nThe <code class=\"language-apl\">0\u2193<\/code> is a no-op and is likely scaffolding left from the development process.<\/p>\n<p><strong>d.<\/strong> <code class=\"language-apl\"> ,\u2218\u233d\u2368' X'[{(.5\u00d7n*2)&gt;+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a8n-\u23732 1\u00d7n\u219020]<\/code><br \/>\n<code class=\"language-apl\">(2\u00d7n),n\u219020<\/code> is equivalent to <code class=\"language-apl\">2 1\u00d7n\u219020<\/code>.<\/p>\n<p><strong>e.<\/strong> <code class=\"language-apl\"> ,\u2218\u233d\u2368' X'[(.5\u00d7n*2)&gt;{+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a8n-\u23732 1\u00d7n\u219020]<\/code><\/p>\n<p>The comparison with <code class=\"language-apl\">.5\u00d7n*2<\/code> is on the result of the <code class=\"language-apl\">{...}<\/code> and is likely more efficient &#8220;outside&#8221; rather than explicitly applied to each scalar &#8220;inside&#8221;. More importantly, moving it outside avoids the use of a lexical global, an aesthetic infelicity (your opinion may differ).<\/p>\n<p>At this step, it dawned on me that <code class=\"language-apl\">\u2373<\/code> is applied to a 2-element vector, resulting in a <code class=\"language-apl\">2\u00d7n<\/code> by <code class=\"language-apl\">n<\/code> matrix of 2-element integer vectors:<\/p>\n<pre><code class=\"language-apl\">   \u23732 1\u00d7n\u219020\r\n\u250c\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u252c\r\n\u25020 0\u25020 1\u25020 2\u25020 3\u25020 4\u2502\r\n\u251c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\r\n\u25021 0\u25021 1\u25021 2\u25021 3\u25021 4\u2502 ...\r\n\u251c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\r\n\u25022 0\u25022 1\u25022 2\u25022 3\u25022 4\u2502\r\n\u251c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\r\n\u25023 0\u25023 1\u25023 2\u25023 3\u25023 4\u2502\r\n\u251c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u253c\r\n     ...\r\n<\/code><\/pre>\n<p><strong>f.<\/strong> <code class=\"language-apl\"> ,\u2218\u233d\u2368' X'[(.5\u00d7n*2)&gt;\u2283\u2218.{+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/n-\u2373\u00a82 1\u00d7n\u219020]<\/code><br \/>\nThe reduction on each 2-element vector is equivalent to an outer product; that is, <code class=\"language-apl\">f\/\u00a8\u2373a,b<\/code> is equivalent to <code class=\"language-apl\">\u2283\u2218.f\/\u2373\u00a8a,b<\/code>. Not much of a step forward but facilitates what comes next.<\/p>\n<p><strong>g.<\/strong> <code class=\"language-apl\"> ,\u2218\u233d\u2368' X'[(.5\u00d7n*2)&gt;(n-\u23732\u00d7n)\u2218.{+\/(\u237a-.6\u00d7\u2375)\u2375*2}n-\u2373n\u219020]<\/code><br \/>\nApplying <code class=\"language-apl\">\u2373<\/code> twice removes the reduction and makes the outer product more straightforward.<\/p>\n<p><strong>h.<\/strong> <code class=\"language-apl\"> ,\u2218\u233d\u2368' X'[(n\u00d7*\u2368.5)&gt;(n-\u23732\u00d7n)\u2218.{|\u2375+0j1\u00d7\u237a-.6\u00d7\u2375}n-\u2373n\u219020]<\/code><br \/>\nThe function <code class=\"language-apl\">{+\/(\u237a-.6\u00d7\u2375)\u2375*2}<\/code> computes the sum-of-squares on <code class=\"language-apl\">\u237a-.6\u00d7\u2375<\/code> and <code class=\"language-apl\">\u2375<\/code>. It is equally the square of the magnitude of a complex number whose real and imaginary parts are the two expressions. The subsequent comparison to <code class=\"language-apl\">.5\u00d7n*2<\/code> has the same outcome if instead we compare the square root of both sides, that is, compare <code class=\"language-apl\">n\u00d7*\u2368.5<\/code> and the magitude (not the square of the magnitude) of the complex number.<\/p>\n<p><strong>i.<\/strong> <code class=\"language-apl\"> (\u2395ucs 32 9829)[(n\u00d7*\u2368.5)&gt;i\u2218.{|\u2375+0j1\u00d7\u237a-.6\u00d7\u2375}|i\u2190n-\u23732\u00d7n\u219020]<\/code><\/p>\n<p>A couple of ideas here: (0) Instead of using <code class=\"language-apl\">X<\/code> in the picture, use the heart symbol, Unicode codepoint 9829. (1) Instead of creating half a heart and then stitching the two halves together with <code class=\"language-apl\">,\u2218\u233d\u2368<\/code>, the whole heart can be created using an appropriate right argument to the outer product.<\/p>\n<p>This result differs slightly from the previous ones, but makes a prettier picture.<\/p>\n<p><strong>j.<\/strong> <code class=\"language-apl\"> ' \u2665'[(n\u00d7*\u2368.5)&gt;\u2218.(|1 \u00af.6j1+.\u00d7,)\u2218|\u2368n-\u23732\u00d7n\u219020]<\/code><\/p>\n<p>I remembered that Unicode codepoints can be included directly in an APL expression, so <code class=\"language-apl\">\u2395ucs 32 9829<\/code> can be replaced by <code class=\"language-apl\">' \u2665'<\/code>. (Much to my relief. Talk about lack of aesthetics!)<\/p>\n<p>The arguments to the outer product are <code class=\"language-apl\">i<\/code> and <code class=\"language-apl\">|i<\/code>, and <code class=\"language-apl\">i<\/code> can be eliminated altogether by doing <code class=\"language-apl\">f\u2218|\u2368<\/code> instead of <code class=\"language-apl\">i f |i<\/code>.<\/p>\n<p>The function <code class=\"language-apl\">{|\u2375+0j1\u00d7\u237a-.6\u00d7\u2375}<\/code>, which computes the magnitude of a complex number, remains the same if the real and imaginary parts are switched, and in this case it is advantageous to switch them for brevity. Moreover, the computation can be coded as a train involving an inner product.<\/p>\n<p><strong>k.<\/strong> <code class=\"language-apl\"> ' \u2665'[(n\u00d7*\u2368.5)&gt;|\u2218.{\u237a-\u2375\u00d7.6j1}\u2218|\u2368n-\u23732\u00d7n\u219020]<\/code><br \/>\nSometimes, trains are better coded as dfns. The magnitude <code class=\"language-apl\">|<\/code> is moved &#8220;outside&#8221;, and is unchanged if the complex coefficient is replaced by the negation of its conjugate and the operation changed from <code class=\"language-apl\">+<\/code> to <code class=\"language-apl\">-<\/code>.<\/p>\n<p><strong>l.<\/strong> <code class=\"language-apl\"> ' \u2665'[(n\u00f72*\u00f72)&gt;|i\u2218.-.6j1\u00d7|i\u2190n-\u23732\u00d7n\u219020]<\/code><br \/>\nThe expression can be shortened by using the variable <code class=\"language-apl\">i<\/code> after all (last seen in step <strong>i<\/strong>). Replace <code class=\"language-apl\">n\u00d7*\u2368.5<\/code> by <code class=\"language-apl\">n\u00f72*\u00f72<\/code> and <em>voil\u00e0<\/em>, a retro expression without dfns, trains, or any of them new-fangled operators.<\/p>\n<p><strong>In summary<\/strong><\/p>\n<pre><strong>a.<\/strong>  <code class=\"language-apl\">   (\u22a2,\u233d)' X'[{(.5\u00d7n*2)&gt;+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a80\u2193n-\u2373(2\u00d7n),n\u219020]<\/code>\r\n<strong>b.<\/strong>  <code class=\"language-apl\">   ,\u2218\u233d\u2368' X'[{(.5\u00d7n*2)&gt;+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a80\u2193n-\u2373(2\u00d7n),n\u219020]<\/code>\r\n<strong>c.<\/strong>  <code class=\"language-apl\">   ,\u2218\u233d\u2368' X'[{(.5\u00d7n*2)&gt;+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a8n-\u2373(2\u00d7n),n\u219020]<\/code>\r\n<strong>d.<\/strong>  <code class=\"language-apl\">   ,\u2218\u233d\u2368' X'[{(.5\u00d7n*2)&gt;+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a8n-\u23732 1\u00d7n\u219020]<\/code>\r\n<strong>e.<\/strong>  <code class=\"language-apl\">   ,\u2218\u233d\u2368' X'[(.5\u00d7n*2)&gt;{+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/\u00a8n-\u23732 1\u00d7n\u219020]<\/code>\r\n<strong>f.<\/strong>  <code class=\"language-apl\">   ,\u2218\u233d\u2368' X'[(.5\u00d7n*2)&gt;\u2283\u2218.{+\/(\u237a-.6\u00d7\u2375)\u2375*2}\/n-\u2373\u00a82 1\u00d7n\u219020]<\/code>\r\n<strong>g.<\/strong>  <code class=\"language-apl\">   ,\u2218\u233d\u2368' X'[(.5\u00d7n*2)&gt;(n-\u23732\u00d7n)\u2218.{+\/(\u237a-.6\u00d7\u2375)\u2375*2}n-\u2373n\u219020]<\/code>\r\n<strong>h.<\/strong>  <code class=\"language-apl\">   ,\u2218\u233d\u2368' X'[(n\u00d7*\u2368.5)&gt;(n-\u23732\u00d7n)\u2218.{|\u2375+0j1\u00d7\u237a-.6\u00d7\u2375}n-\u2373n\u219020]<\/code>\r\n<strong>i.<\/strong>  <code class=\"language-apl\">   (\u2395ucs 32 9829)[(n\u00d7*\u2368.5)&gt;i\u2218.{|\u2375+0j1\u00d7\u237a-.6\u00d7\u2375}|i\u2190n-\u23732\u00d7n\u219020]<\/code>\r\n<strong>j.<\/strong>  <code class=\"language-apl\">   ' \u2665'[(n\u00d7*\u2368.5)&gt;\u2218.(|1 \u00af.6j1+.\u00d7,)\u2218|\u2368n-\u23732\u00d7n\u219020]<\/code>\r\n<strong>k.<\/strong>  <code class=\"language-apl\">   ' \u2665'[(n\u00d7*\u2368.5)&gt;|\u2218.{\u237a-\u2375\u00d7.6j1}\u2218|\u2368n-\u23732\u00d7n\u219020]<\/code>\r\n<strong>l.<\/strong>  <code class=\"language-apl\">   ' \u2665'[(n\u00f72*\u00f72)&gt;|i\u2218.-.6j1\u00d7|i\u2190n-\u23732\u00d7n\u219020]<\/code>\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Karen Shaw started the ball rolling (hearts afluttering?) by asking Jay Foad to come up with a one-liner for St. Valentine&#8217;s Day; he then solicited contributions from the language development group. Nick Nickolov responded with the following, with no explanation &hellip; <a href=\"https:\/\/www.dyalog.com\/blog\/2015\/02\/changes-of-heart\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":13,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,8],"tags":[],"class_list":["post-1854","post","type-post","status-publish","format-standard","hentry","category-algorithms","category-apl-language"],"_links":{"self":[{"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/posts\/1854","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/comments?post=1854"}],"version-history":[{"count":11,"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/posts\/1854\/revisions"}],"predecessor-version":[{"id":2120,"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/posts\/1854\/revisions\/2120"}],"wp:attachment":[{"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/media?parent=1854"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/categories?post=1854"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dyalog.com\/blog\/wp-json\/wp\/v2\/tags?post=1854"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}