{"id":140,"date":"2008-06-06T14:58:07","date_gmt":"2008-06-06T19:58:07","guid":{"rendered":"https:\/\/blogs.mathworks.com\/loren\/2008\/06\/06\/collinearity\/"},"modified":"2016-08-03T15:00:56","modified_gmt":"2016-08-03T20:00:56","slug":"collinearity","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/loren\/2008\/06\/06\/collinearity\/","title":{"rendered":"Collinearity"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <introduction>\r\n      <p>I recently heard Greg Wilson speak about a topic dear to him, <a href=\"http:\/\/www.oreilly.com\/catalog\/9780596510046\/\">Beautiful Code<\/a>. He and Andy Oran edited a book on this topic in which programmers explain their thought processes.  The essay <i>Writing Programs for \"The Book\"<\/i>, by Brian Hayes, really resonates for me, in part because of the actual problem he discusses, in part because of the eureka\r\n         moment he describes. Brian wrote his code in Lisp.  I will write similar code in MATLAB to illustrate the points.\r\n      <\/p>\r\n   <\/introduction>\r\n   <h3>Contents<\/h3>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"#1\">Problem Description<\/a><\/li>\r\n         <li><a href=\"#2\">Method 1 - See if Third Point Obeys Same Slope<\/a><\/li>\r\n         <li><a href=\"#4\">Method 2 - Method 1 Modified<\/a><\/li>\r\n         <li><a href=\"#7\">Methods 3 and 4 - Compare Two Slopes Only<\/a><\/li>\r\n         <li><a href=\"#12\">Method 5 and 6 - Summing Lengths of Sides of Triangle<\/a><\/li>\r\n         <li><a href=\"#18\">Method 7 - Eureka, Compute Triangle Area!<\/a><\/li>\r\n         <li><a href=\"#21\">Note: Added 9 June 2008<\/a><\/li>\r\n         <li><a href=\"#22\">What's Your Recent Aha Moment?<\/a><\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <h3>Problem Description<a name=\"1\"><\/a><\/h3>\r\n   <p>Given 3 points in a plane, find out if they lie on a single line, i.e., find out if the points are collinear.  Here are the\r\n      first set of points we'll use for trying out algorithms.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">p1 = [1 1];\r\np2 = [3.5 3.5];\r\np3 = [-7.2 -7.2];<\/pre><h3>Method 1 - See if Third Point Obeys Same Slope<a name=\"2\"><\/a><\/h3>\r\n   <p>In this variant, we compute the straight lines connected 2 pairs of points, and then check that the third point fits the same\r\n      line.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">collinear1(p1,p2,p3)<\/pre><pre style=\"font-style:oblique\">ans =\r\n     1\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">dbtype <span style=\"color: #A020F0\">collinear1<\/span><\/pre><pre style=\"font-style:oblique\">\r\n1     function tf = collinear1(p1,p2,p3)\r\n2     m = slope(p1,p2);\r\n3     b = intercept(p1,p2);\r\n4     tf = (m*p3(1)+b) == p3(2);\r\n5     end\r\n6     function m = slope(p1,p2)\r\n7     m = (p2(2)-p1(2))\/(p2(1)-p1(1));\r\n8     end\r\n9     function b = intercept(p1,p2)\r\n10    m = slope(p1,p2);\r\n11    b = -p1(2)+m*p1(1);\r\n12    end\r\n<\/pre><h3>Method 2 - Method 1 Modified<a name=\"4\"><\/a><\/h3>\r\n   <p>There's a flaw in method one in the case where the points are collinear and lie on a vertical line, i.e., where there are\r\n      repeated <tt>x<\/tt> values. Then the denominator we calculate will have the differences of two <tt>x<\/tt> values that are the same, resulting in division by 0 and a non-finite slope.  First, let's see what happens with the first\r\n      algorithm and vertically aligned points.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">q1 = [0 1];\r\nq2 = [0 3.5];\r\nq3 = [0 -7.2];\r\ncollinear1(q1,q2,q3)<\/pre><pre style=\"font-style:oblique\">ans =\r\n     0\r\n<\/pre><p>The first algorithm says these points are not collinear.  Time to patch the algorithm.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">collinear2(q1,q2,q3)<\/pre><pre style=\"font-style:oblique\">ans =\r\n     1\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">dbtype <span style=\"color: #A020F0\">collinear2<\/span><\/pre><pre style=\"font-style:oblique\">\r\n1     function tf = collinear2(p1,p2,p3)\r\n2     m = slope(p1,p2);\r\n3     b = intercept(p1,p2);\r\n4     % put in check for m being finite in case\r\n5     % points are all on y axis\r\n6     if ~isfinite(m)\r\n7         if (p3(1)==p1(1))\r\n8             tf = true;\r\n9         else\r\n10            tf = false;\r\n11        end\r\n12    else\r\n13        tf = (m*p3(1)+b) == p3(2);\r\n14    end\r\n15    end\r\n16    function m = slope(p1,p2)\r\n17    m = (p2(2)-p1(2))\/(p2(1)-p1(1));\r\n18    end\r\n19    function b = intercept(p1,p2)\r\n20    m = slope(p1,p2);\r\n21    b = -p1(2)+m*p1(1);\r\n22    end\r\n<\/pre><h3>Methods 3 and 4 - Compare Two Slopes Only<a name=\"7\"><\/a><\/h3>\r\n   <p>The next thing Brian noticed was he really didn't need to see if the 3rd point fit the same line.  What he really needed to\r\n      determine is if two lines had the same slope. If so, all three lines have the same slope (convince yourself that this is true,\r\n      at least for Euclidean geometry).\r\n   <\/p>\r\n   <p>Let's try this algorithm on our two sets of collinear points.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">collinear3(p1,p2,p3)\r\ncollinear3(q1,q2,q3)<\/pre><pre style=\"font-style:oblique\">ans =\r\n     1\r\nans =\r\n     0\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">dbtype <span style=\"color: #A020F0\">collinear3<\/span><\/pre><pre style=\"font-style:oblique\">\r\n1     function tf = collinear3(p1,p2,p3)\r\n2     m1 = slope(p1,p2);\r\n3     m2 = slope(p1,p3);\r\n4     tf = isequal(m1,m2);\r\n5     end\r\n6     function m = slope(p1,p2)\r\n7     q = p2-p1;\r\n8     m = q(2)\/q(1);\r\n9     end\r\n\r\n<\/pre><p>Once again we need to modify the code for infinite slopes.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">collinear4(q1,q2,q3)<\/pre><pre style=\"font-style:oblique\">ans =\r\n     1\r\n<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">dbtype <span style=\"color: #A020F0\">collinear4<\/span><\/pre><pre style=\"font-style:oblique\">\r\n1     function tf = collinear3(p1,p2,p3)\r\n2     m1 = slope(p1,p2);\r\n3     m2 = slope(p1,p3);\r\n4     if isfinite(m1)\r\n5         tf = isequal(m1,m2);\r\n6     else\r\n7        if ~isfinite(m2)\r\n8            tf = true;\r\n9        else\r\n10           tf = false;\r\n11       end\r\n12    end\r\n13    end\r\n14    function m = slope(p1,p2)\r\n15    q = p2-p1;\r\n16    m = q(2)\/q(1);\r\n17    end\r\n\r\n<\/pre><h3>Method 5 and 6 - Summing Lengths of Sides of Triangle<a name=\"12\"><\/a><\/h3>\r\n   <p>The next idea that Brian explores is exploiting the relationship between the sides of the triangle that 3 points define. \r\n      The longest leg is shorter than the sum of the lengths of the other 2 sides, except when the points are collinear.  Then the\r\n      length of the longest side is equal to the sum of the 2 other lengths.  Let's try it out.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">collinear5(p1,p2,p3)\r\ncollinear5(q1,q2,q3)<\/pre><pre style=\"font-style:oblique\">ans =\r\n     0\r\nans =\r\n     1\r\n<\/pre><p>Let's use the point values that Brian uses.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bh1 = [0 1];\r\nbh2 = [14 5];\r\nbh3 = [8 4];\r\ncollinear5(bh1,bh2,bh3);<\/pre><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">dbtype <span style=\"color: #A020F0\">collinear5<\/span><\/pre><pre style=\"font-style:oblique\">\r\n1     function tf = collinear5(p1,p2,p3)\r\n2     side(3) = norm(p2-p1);\r\n3     side(2) = norm(p3-p1);\r\n4     side(1) = norm(p3-p2);\r\n5     lengths = sort(side,'descend');\r\n6     tf = isequal(lengths(1), ...\r\n7         (lengths(2)+lengths(3)));\r\n8     end\r\n<\/pre><p>So far, so good.  Points that are not collinear don't claim to be.  But the first set was and the answer came out negative.\r\n       Let's try another batch of points to be sure.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">bh4 = [0 0];\r\nbh5 = [3 3];\r\nbh6 = [5 5];\r\ncollinear5(bh1,bh2,bh3)\r\ncollinear5(bh1*1e5,bh2*1e5,bh3*1e5)<\/pre><pre style=\"font-style:oblique\">ans =\r\n     0\r\nans =\r\n     0\r\n<\/pre><p>Uh-oh!  What's happened?  Looking back at <tt>collinear5<\/tt>, we see we are no longer doing just addition, subtraction, multiplication, and division. Now we're computing the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/norm.html\"><tt>norm<\/tt><\/a> which involves computing a <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/sqrt.html\"><tt>sqrt<\/tt><\/a>. As a result, we have more opportunity for numerical roundoff issues, even if the points are confined to be rational numbers\r\n      (including integers).\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">collinear6(bh1,bh2,bh3)\r\ncollinear6(bh1*1e5,bh2*1e5,bh3*1e5)<\/pre><pre style=\"font-style:oblique\">ans =\r\n     0\r\nans =\r\n     0\r\n<\/pre><p>Version <tt>collinear6<\/tt> no longer does an exact equality comparison but looks for differences on the order of <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/eps.html\"><tt>eps<\/tt><\/a> for the appropriate lengths.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">dbtype <span style=\"color: #A020F0\">collinear6<\/span><\/pre><pre style=\"font-style:oblique\">\r\n1     function tf = collinear6(p1,p2,p3)\r\n2     side(3) = norm(p2-p1);\r\n3     side(2) = norm(p3-p1);\r\n4     side(1) = norm(p3-p2);\r\n5     lengths = sort(side,'descend');\r\n6     tf = ...\r\n7         abs(lengths(1)-(lengths(2)+lengths(3))) ...\r\n8                              &lt;= eps(lengths(1));\r\n9     end\r\n<\/pre><h3>Method 7 - Eureka, Compute Triangle Area!<a name=\"18\"><\/a><\/h3>\r\n   <p>Finally, as Brian describes it, he realized there was a completely different way to see if 3 points were collinear, and that\r\n      was to compute the <i>area<\/i> of the triangle they define.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">collinear7(bh1,bh2,bh3)\r\ncollinear7(bh1*1e5,bh2*1e5,bh3*1e5)<\/pre><pre style=\"font-style:oblique\">ans =\r\n     0\r\nans =\r\n     0\r\n<\/pre><p>To compute the area, you could compute <i>base * height \/ 2<\/i>, but again this would involve square roots.  The trig approach would involve transcendental functions.  Another way to think\r\n      of this is to view any 2 pairs of the points as defining a parallelogram, and the triangle area is half that area.  To compute\r\n      the area, treat the sides as vectors which you translate to the origin.  Then the area computation is straight-forward, boiling\r\n      down to something proportional to the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/det.html\">determinant<\/a> If the result is 0, the points are collinear.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">dbtype <span style=\"color: #A020F0\">collinear7<\/span><\/pre><pre style=\"font-style:oblique\">\r\n1     function tf = collinear7(p1,p2,p3)\r\n2     mat = [p1(1)-p3(1) p1(2)-p3(2); ...\r\n3            p2(1)-p3(1) p2(2)-p3(2)];\r\n4     tf = det(mat) == 0;\r\n<\/pre><p>This algorithm requires an equality test following 6 arithmetic operations.  Pretty simple, <i>very<\/i> elegant, much less prone to numerical issues than other algorithms.  Much nicer than all of the other code above, no accounting\r\n      for singular behavior necessary.\r\n   <\/p>\r\n   <h3>Note: Added 9 June 2008<a name=\"21\"><\/a><\/h3>\r\n   <p>If you read the comments for this blog, you will find an even more satisfactory solution relying on svd. <tt>svd<\/tt> (and the related <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/rank.html\">rank<\/a> function) have better numerical attributes than <tt>det<\/tt>.\r\n   <\/p>\r\n   <h3>What's Your Recent Aha Moment?<a name=\"22\"><\/a><\/h3>\r\n   <p>Have you had a similar epiphany recently?  We'd love to hear about it <a href=\"https:\/\/blogs.mathworks.com\/loren\/?p=140#respond\">here<\/a>.\r\n   <\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_81f9d6dd035140afafe3a5d762c99897() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='81f9d6dd035140afafe3a5d762c99897 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 81f9d6dd035140afafe3a5d762c99897';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        author = 'Loren Shure';\r\n        copyright = 'Copyright 2008 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n      \r\n      d.title = title + ' (MATLAB code)';\r\n      d.close();\r\n      }   \r\n      \r\n-->\r\n<\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_81f9d6dd035140afafe3a5d762c99897()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n            the MATLAB code \r\n            <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; 7.6<br><\/p>\r\n<\/div>\r\n<!--\r\n81f9d6dd035140afafe3a5d762c99897 ##### SOURCE BEGIN #####\r\n%% Collinearity\r\n% I recently heard Greg Wilson speak about a topic dear to him,\r\n% <http:\/\/www.oreilly.com\/catalog\/9780596510046\/ Beautiful Code>.\r\n% He and Andy Oran edited a book on this topic in which programmers explain\r\n% their thought processes.  The essay _Writing Programs for \"The Book\"_, by\r\n% Brian Hayes, really resonates for me, in part because of the actual\r\n% problem he discusses, in part because of the eureka moment he describes.\r\n% Brian wrote his code in Lisp.  I will write similar code in MATLAB to\r\n% illustrate the points.\r\n%% Problem Description\r\n% Given 3 points in a plane, find out if they lie on a single line, i.e., \r\n% find out if the points are collinear.  Here are the first set of points\r\n% we'll use for trying out algorithms.\r\np1 = [1 1];\r\np2 = [3.5 3.5];\r\np3 = [-7.2 -7.2];\r\n%% Method 1 - See if Third Point Obeys Same Slope\r\n% In this variant, we compute the straight lines connected 2 pairs of\r\n% points, and then check that the third point fits the same line.\r\ncollinear1(p1,p2,p3)\r\n%%\r\ndbtype collinear1\r\n%% Method 2 - Method 1 Modified\r\n% There's a flaw in method one in the case where the points are collinear\r\n% and lie on a vertical line, i.e., where there are repeated |x| values.\r\n% Then the denominator we calculate will have the differences of two |x|\r\n% values that are the same, resulting in division by 0 and a non-finite\r\n% slope.  First, let's see what happens with the first algorithm and\r\n% vertically aligned points.\r\nq1 = [0 1];\r\nq2 = [0 3.5];\r\nq3 = [0 -7.2];\r\ncollinear1(q1,q2,q3)\r\n%%\r\n% The first algorithm says these points are not collinear.  Time to patch the\r\n% algorithm.\r\ncollinear2(q1,q2,q3)\r\n%%\r\ndbtype collinear2\r\n%% Methods 3 and 4 - Compare Two Slopes Only\r\n% The next thing Brian noticed was he really didn't need to see if the\r\n% 3rd point fit the same line.  What he really needed to determine is if\r\n% two lines had the same slope. If so, all three lines have the same slope\r\n% (convince yourself that this is true, at least for Euclidean geometry).\r\n%% \r\n% Let's try this algorithm on our two sets of collinear points.\r\ncollinear3(p1,p2,p3)\r\ncollinear3(q1,q2,q3)\r\n%%\r\ndbtype collinear3\r\n%%\r\n% Once again we need to modify the code for infinite slopes.\r\ncollinear4(q1,q2,q3)\r\n%%\r\ndbtype collinear4\r\n%% Method 5 and 6 - Summing Lengths of Sides of Triangle\r\n% The next idea that Brian explores is exploiting the relationship between\r\n% the sides of the triangle that 3 points define.  The longest leg is\r\n% shorter than the sum of the lengths of the other 2 sides, except when the\r\n% points are collinear.  Then the length of the longest side is equal to\r\n% the sum of the 2 other lengths.  Let's try it out.\r\ncollinear5(p1,p2,p3)\r\ncollinear5(q1,q2,q3)\r\n%%\r\n% Let's use the point values that Brian uses.\r\nbh1 = [0 1];\r\nbh2 = [14 5];\r\nbh3 = [8 4];\r\ncollinear5(bh1,bh2,bh3);\r\n%% \r\ndbtype collinear5\r\n%%\r\n% So far, so good.  Points that are not collinear don't claim to be.  But\r\n% the first set was and the answer came out negative.  Let's\r\n% try another batch of points to be sure.\r\nbh4 = [0 0];\r\nbh5 = [3 3];\r\nbh6 = [5 5];\r\ncollinear5(bh1,bh2,bh3)\r\ncollinear5(bh1*1e5,bh2*1e5,bh3*1e5)\r\n%%\r\n% Uh-oh!  What's happened?  Looking back at |collinear5|, we see we are no\r\n% longer doing just addition, subtraction, multiplication, and division.\r\n% Now we're computing the \r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/norm.html |norm|>\r\n% which involves computing a <https:\/\/www.mathworks.com\/help\/matlab\/ref\/sqrt.html |sqrt|>.\r\n% As a result, we have more opportunity for numerical roundoff issues, even\r\n% if the points are confined to be rational numbers (including integers).  \r\ncollinear6(bh1,bh2,bh3)\r\ncollinear6(bh1*1e5,bh2*1e5,bh3*1e5)\r\n%%\r\n% Version |collinear6| no longer does an exact equality comparison but\r\n% looks for differences on the order of <https:\/\/www.mathworks.com\/help\/matlab\/ref\/eps.html |eps|> \r\n% for the appropriate lengths. \r\ndbtype collinear6\r\n%% Method 7 - Eureka, Compute Triangle Area!\r\n% Finally, as Brian describes it, he realized there was a completely\r\n% different way to see if 3 points were collinear, and that was to compute\r\n% the _area_ of the triangle they define.\r\ncollinear7(bh1,bh2,bh3)\r\ncollinear7(bh1*1e5,bh2*1e5,bh3*1e5)\r\n%%\r\n% To compute the area, you could compute _base * height \/ 2_, but again\r\n% this would involve square roots.  The trig approach would involve\r\n% transcendental functions.  Another way to think of this is to view any 2\r\n% pairs of the points as defining a parallelogram, and the triangle area is\r\n% half that area.  To compute the area, treat the sides as vectors which\r\n% you translate to the origin.  Then the area computation is\r\n% straight-forward, boiling down to something proportional to the \r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/det.html determinant>\r\n% If the result is 0, the points are collinear.  \r\ndbtype collinear7\r\n%%\r\n% This algorithm requires an equality test following 6 arithmetic\r\n% operations.  Pretty simple, _very_ elegant, much less prone to numerical\r\n% issues than other algorithms.  Much nicer than all of the other code\r\n% above, no accounting for singular behavior necessary.\r\n%% Note: Added 9 June 2008\r\n% If you read the comments for this blog, you will find an even more\r\n% satisfactory solution relying on\r\n% <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/ref\/svd.html svd>.\r\n% |svd| (and the related\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/rank.html rank>\r\n% function) have better numerical attributes than |det|.\r\n%% What's Your Recent Aha Moment?\r\n% Have you had a similar epiphany recently?  We'd love to hear about it\r\n% <https:\/\/blogs.mathworks.com\/loren\/?p=140#respond here>.\r\n##### SOURCE END ##### 81f9d6dd035140afafe3a5d762c99897\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   \r\n      I recently heard Greg Wilson speak about a topic dear to him, Beautiful Code. He and Andy Oran edited a book on this topic in which programmers explain their thought processes.  The... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/loren\/2008\/06\/06\/collinearity\/\">read more >><\/a><\/p>","protected":false},"author":39,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[14,11],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/140"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/comments?post=140"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/140\/revisions"}],"predecessor-version":[{"id":1927,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/140\/revisions\/1927"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/media?parent=140"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/categories?post=140"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/tags?post=140"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}