{"id":107,"date":"2012-09-08T11:23:03","date_gmt":"2012-09-08T15:23:03","guid":{"rendered":"https:\/\/peterabeles.com\/blog\/?p=107"},"modified":"2012-09-09T22:47:57","modified_gmt":"2012-09-10T02:47:57","slug":"code-from-symbolic-math-using-sage","status":"publish","type":"post","link":"https:\/\/peterabeles.com\/blog\/?p=107","title":{"rendered":"Code from symbolic math using Sage"},"content":{"rendered":"<h2>Abstract<\/h2>\n<p>The following article demonstrates how Sage\/Python can be used to solve, format, and output auto generated code for complex symbolic equations. \u00a0 The auto-generated code can be targeted for languages such as C\/C++ or Java.\u00a0 Sage is a computer algebra system (CAS) that uses the Python programming language.\u00a0 By using Python it is easy to write the code and to take full advantage of Python&#8217;s text processing capabilities.<\/p>\n<h2>Introduction<\/h2>\n<p>It is not uncommon for researchers and engineers to need to solve complex symbolic equations in languages like C\/C++ and Java.\u00a0 While computer algebra systems (CAS), such as Maple or Mathematica, are designed specifically to handle symbolic math with ease, C style languages are not.\u00a0 A common solution is to first solve the symbolic equations using Maple\/Mathematica, then expand out the closed form\u00a0 solution and convert into compilable code.<\/p>\n<p>This process is often easier said than done.\u00a0 What was a nice elegant and compact 3 line equation is expanded out into thousands of lines of code.\u00a0 Hand editing these monstrous equations is not an option.\u00a0 Another issue is that commercial packages such as Maple and Mathematica are both very expensive.<\/p>\n<p>Recently I needed solve an ugly problem in computer vision and having just learned Python, Sage was the obvious choice.\u00a0 Sage is CAS which uses\u00a0Python as its programming language.\u00a0 Besides being free, Sage is in many ways superior to Maple and Mathematica thanks to Python&#8217;s string processing capabilities. The remainder of this article will describe how Sage and Python was used to solve a complex math problem and convert the solution to usable Java code.<\/p>\n<p>The basic for how to use Sage can be found at the following websites:<\/p>\n<ul>\n<li><a href=\"http:\/\/www.sagemath.org\/doc\/tutorial\/tour.html\">http:\/\/www.sagemath.org\/doc\/tutorial\/tour.html<\/a><\/li>\n<li><a href=\"http:\/\/www.sagemath.org\/doc\/reference\/sage\/symbolic\/expression.htm\">http:\/\/www.sagemath.org\/doc\/reference\/sage\/symbolic\/expression.htm<\/a><\/li>\n<\/ul>\n<p>In this particular application Java code is the final output.\u00a0 However, it is trivial to convert this example to output C\/C++ code.<\/p>\n<h2>The Math<\/h2>\n<p>To demonstrate these techniques a complex real-world problem is used.\u00a0 This problem comes from geometric computer vision and understanding all the math involved is not necessary, but you can find the paper it is based on here [1].\u00a0 Having an understanding of linear algebra will help you understand all the math terminology.\u00a0 Briefly stated the problem is to solve for a 3&#215;3 Essential matrix given 5 point correspondences. \u00a0 If that means nothing to you, don&#8217;t worry.<\/p>\n<p>The first step in solving this problem is computing the null space of a 5 by 9 linear system.\u00a0 The null space is then stored in four column vectors <img src='https:\/\/s0.wp.com\/latex.php?latex=X+%2C+Y+%2C+Z+%2C&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='X , Y , Z ,' title='X , Y , Z ,' class='latex' \/> and <img src='https:\/\/s0.wp.com\/latex.php?latex=W&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='W' title='W' class='latex' \/>.\u00a0 The final solution is a linear combination of these four vectors:<\/p>\n<p style=\"text-align: center;\"><img src='https:\/\/s0.wp.com\/latex.php?latex=E+%3D+x+%5Ccdot+X+%2B+y+%5Ccdot+Y+%2B+z+%5Ccdot+Z+%2B+W&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='E = x \\cdot X + y \\cdot Y + z \\cdot Z + W' title='E = x \\cdot X + y \\cdot Y + z \\cdot Z + W' class='latex' \/><\/p>\n<p>where <img src='https:\/\/s0.wp.com\/latex.php?latex=E&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='E' title='E' class='latex' \/> is a 3 by 3 Essential matrix being computed, <img src='https:\/\/s0.wp.com\/latex.php?latex=%28x%2Cy%2Cz%29&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='(x,y,z)' title='(x,y,z)' class='latex' \/> are the scalar variables being solved for.\u00a0 Note that the column vectors are converted into a matrix as needed.\u00a0 Next a system, <strong><em>A<\/em><\/strong>, with 10 equations and 20 unknowns is constructed by apply the following constrains on E:<\/p>\n<p style=\"padding-left: 30px; text-align: center;\"><img src='https:\/\/s0.wp.com\/latex.php?latex=det%28E%29+%3D+0&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='det(E) = 0' title='det(E) = 0' class='latex' \/><\/p>\n<p style=\"padding-left: 30px; text-align: center;\"><img src='https:\/\/s0.wp.com\/latex.php?latex=E+%5Ccdot+E%5ET+%5Ccdot+E-%5Cfrac%7B1%7D%7B2%7Dtrace%28E+%5Ccdot+E%5ET%29+%5Ccdot+E%3D0&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='E \\cdot E^T \\cdot E-\\frac{1}{2}trace(E \\cdot E^T) \\cdot E=0' title='E \\cdot E^T \\cdot E-\\frac{1}{2}trace(E \\cdot E^T) \\cdot E=0' class='latex' \/><\/p>\n<p>Again if you don&#8217;t understand why we are doing the math, don&#8217;t panic.\u00a0 Just know that there are some ugly complex equations which need to be solved for in Java.\u00a0 In summary we need to do the following:<\/p>\n<ul>\n<li>In Java compute the null space and extract out X,Y,Z,W\u00a0\u00a0 (Not shown)<\/li>\n<li>In Sage construct a system of equation for the above constraints<\/li>\n<li>In Sage separate out the known and unknown portions of those equations and output Java code<\/li>\n<li>In Java solve for unknowns\u00a0 (Not shown)<\/li>\n<\/ul>\n<p>This is actually only 2\/3 of the solution.\u00a0 Since the focus of this article is on the process and not about the details of this particular problem we will skip the rest.<\/p>\n<h2>Solving with Sage<\/h2>\n<p>All code examples below are written in Python and need to be run inside of Sage&#8217;s interactive shell.\u00a0 Do not try to to run the scripts from Python directly, use Sage.\u00a0 All python files need the following imports:<\/p>\n<pre lang=\"Python\">from sage.all import *\r\nfrom numpy.core.fromnumeric import var<\/pre>\n<p>The first step in solving this problem is creating several 3&#215;3 symbolic matrices.\u00a0 Each element in the matrix is unique.\u00a0 I couldn&#8217;t find a function built into Sage, so I wrote my own:<\/p>\n<pre lang=\"Python\">def symMatrix( numRows , numCols , letter ):\r\n A = matrix(SR,numRows,numCols)\r\n for i in range(0,numRows):\r\n for j in range(0,numCols):\r\n A[i,j] = var('%s%d%d' % (letter,i,j) )\r\nreturn A<\/pre>\n<p>The &#8216;var&#8217; function is used by Sage to define symbolic variables.\u00a0 Inside of the Sage interactive shell you can do the following:<\/p>\n<pre lang=\"Python\">sage: A = symMatrix(3,3,'a')\r\nsage: A\r\n[a00 a01 a02]\r\n[a10 a11 a12]\r\n[a20 a21 a22]<\/pre>\n<p>Now that you can create a symbolic matrix you can solve rest of the problem as follows:<\/p>\n<pre lang=\"Python\">x,y,z = var('x','y','z')\r\n\r\nX = symMatrix( 3, 3 , 'X')\r\nY = symMatrix( 3, 3 , 'Y')\r\nZ = symMatrix( 3, 3 , 'Z')\r\nW = symMatrix( 3, 3 , 'W')\r\n\r\nE = x*X + y*Y + z*Z + 1*W\r\nEE = E*E.T\r\n\r\neq1=det(E)\r\neq2=EE*E-0.5*EE.trace()*E\r\n\r\neqs = (eq1,eq2[0,0],eq2[0,1],eq2[0,2],eq2[1,0],eq2[1,1],eq2[1,2],eq2[2,0],eq2[2,1],eq2[2,2])\r\n\r\nkeysA = ('x^3','y^3','x^2*y','x*y^2','x^2*z','x^2','y^2*z','y^2','x*y*z','x*y')\r\nkeysB = ('x*z^2','x*z','x','y*z^2','y*z','y','z^3','z^2','z','')\r\n\r\n# print out machine code for the linear system\r\nprintData('A',eqs,keysA)\r\nprintData('B',eqs,keysB)<\/pre>\n<p>The functions <strong>det<\/strong> and <strong>trace<\/strong> compute the determinant and trace of a matrix respectively,<strong> A.T<\/strong> is the transpose of <strong>A<\/strong>.\u00a0 Most of that is straight forward algebra, but what about that last bit? Well the printData() function massages those equations to produce usable Java output, which is the subject of the next section.<\/p>\n<h2>Generating Code<\/h2>\n<p>What the Java code is going to do is solve a linear system. To do that the equations above need to reformatted and converted into matrix format. The variable <strong>eqs<\/strong> in the above python code contains equations which have a similar appearance to the equation below on the left, but they need to be expanded out so that they look like the equation on the right.<\/p>\n<p style=\"text-align: center;\"><img src='https:\/\/s0.wp.com\/latex.php?latex=%281+%2B+5x%29%282+-+3x%29%288+%2B+4y%29+%5Crightarrow+-60x%5E2y+-+120x%5E2+%2B+28xy+%2B+56x+%2B+8y+%2B+16&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='(1 + 5x)(2 - 3x)(8 + 4y) \\rightarrow -60x^2y - 120x^2 + 28xy + 56x + 8y + 16' title='(1 + 5x)(2 - 3x)(8 + 4y) \\rightarrow -60x^2y - 120x^2 + 28xy + 56x + 8y + 16' class='latex' \/><\/p>\n<p>After the equations have been expanded, the knowns and unknowns are separated and put into matrix format. Consider the system of equations below:<\/p>\n<p style=\"text-align: center;\"><img src='https:\/\/s0.wp.com\/latex.php?latex=%5Cbegin%7Barray%7D%7Bc%7D++x+%2B+2xy+%2B+3x%5E2+%3D+4+%5C%5C++5x+%2B+6xy+%2B+7x%5E2+%3D+8+%5C%5C++9x+%2B+10xy+%2B11x%5E2+%3D+12+%5C%5C++%5Cend%7Barray%7D+&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='\\begin{array}{c}  x + 2xy + 3x^2 = 4 \\\\  5x + 6xy + 7x^2 = 8 \\\\  9x + 10xy +11x^2 = 12 \\\\  \\end{array} ' title='\\begin{array}{c}  x + 2xy + 3x^2 = 4 \\\\  5x + 6xy + 7x^2 = 8 \\\\  9x + 10xy +11x^2 = 12 \\\\  \\end{array} ' class='latex' \/><\/p>\n<p>After it has been converted into matrix format it will look like:<\/p>\n<p style=\"text-align: center;\"><img src='https:\/\/s0.wp.com\/latex.php?latex=A%3D%5Cleft%5B++%5Cbegin%7Barray%7D%7Bccc%7D++1+%26+2+%26+3+%5C%5C++5+%26+6+%26+7+%5C%5C++9+%26+10+%26+11+%5C%5C++%5Cend%7Barray%7D++%5Cright%5D++%5C%3B%5C%3B++B%3D%5Cleft%5B++%5Cbegin%7Barray%7D%7Bc%7D++4+%5C%5C++8+%5C%5C++12+%5C%5C++%5Cend%7Barray%7D++%5Cright%5D&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='A=\\left[  \\begin{array}{ccc}  1 &amp; 2 &amp; 3 \\\\  5 &amp; 6 &amp; 7 \\\\  9 &amp; 10 &amp; 11 \\\\  \\end{array}  \\right]  \\;\\;  B=\\left[  \\begin{array}{c}  4 \\\\  8 \\\\  12 \\\\  \\end{array}  \\right]' title='A=\\left[  \\begin{array}{ccc}  1 &amp; 2 &amp; 3 \\\\  5 &amp; 6 &amp; 7 \\\\  9 &amp; 10 &amp; 11 \\\\  \\end{array}  \\right]  \\;\\;  B=\\left[  \\begin{array}{c}  4 \\\\  8 \\\\  12 \\\\  \\end{array}  \\right]' class='latex' \/><\/p>\n<p>At this point the unknowns can be solved for using standard linear algebra tools, e.g. Ax=B.<\/p>\n<p>Part of this process is shown below.\u00a0 First <strong>eq1<\/strong> is expanded out and then the coefficients of <img src='https:\/\/s0.wp.com\/latex.php?latex=x%5E3&#038;bg=f7f3ee&#038;fg=333333&#038;s=0' alt='x^3' title='x^3' class='latex' \/> are extracted.<\/p>\n<pre lang=\"Python\">sage: len(str(eq1))         \r\n465\r\nsage: len(str(eq1.expand()))\r\n7065\r\nsage: extractVarEq(eq1.expand(),'x^3')\r\n'X00*X11*X22 - X00*X12*X21 - X01*X10*X22 + X01*X12*X20 + X02*X10*X21 - X02*X11*X20'<\/pre>\n<p>The first two statements are just there to show you how long and ugly these equations are.\u00a0 Below is the python code for <strong>extractVarEq<\/strong>:<\/p>\n<pre lang=\"Python\">def extractVarEq( expression , key ):\r\n  chars = set('xyz')\r\n  # expand out and convert into a string\r\n  expression = str(expression.expand())\r\n  # Make sure negative symbols are not stripped and split into multiplicative blocks\r\n  s = expression.replace('- ','-').split(' ')\r\n  # Find blocks multiplied by the key and remove the key from the string\r\n  if len(key) == 0:\r\n    var = [w for w in s if len(w) != 1 and not any( c in chars for c in w )]\r\n  else:\r\n    var = [w[:-(1+len(key))] for w in s if (w.endswith(key) and not any(c in chars for c in w[:-len(key)])) ]\r\n\r\n  # Expand out power\r\n  var = [expandPower(w) for w in var] \r\n\r\n  # construct a string which can be compiled\r\n  ret = var[0]\r\n  for w in var[1:]:\r\n    if w[0] == '-':\r\n      ret += ' - '+w[1:]\r\n    else:\r\n      ret += ' + '+w\r\n\r\n  return ret<\/pre>\n<p>The function <strong>expandPower<\/strong>(w) converts statements like a^3 into a*a*a which can be parsed by Java.\u00a0 After processing all 10 equations most of the hard work is done,\u00a0\u00a0 Addition processing is done to simplify the equations, but the code is a bit convoluted and isn&#8217;t discussed here.\u00a0 The final output it sent into a text file and then pasted into a Java application.<\/p>\n<p>Want to see what the final output looks like? Well here is a small sniplet:<\/p>\n<pre lang=\"Java\">A.data[0] = X20*( X01*X12 - X02*X11 ) + X10*( -X01*X22 + X02*X21 ) + X00*( X11*X22 - X12*X21 );\r\nA.data[1] = Y02*( Y10*Y21 - Y11*Y20 ) + Y00*( Y11*Y22 - Y12*Y21 ) + Y01*( -Y10*Y22 + Y12*Y20 );\r\nA.data[2] = X22*( X00*Y11 - X01*Y10 - X10*Y01 + X11*Y00 ) + X20*( X01*Y12 - X02*Y11 - X11*Y02 + X12*Y01 ) + X21*( -X00*Y12 + X02*Y10 + X10*Y02 - X12*Y00 ) + X01*( -X10*Y22 + X12*Y20 ) + Y21*( -X00*X12 + X02*X10 ) + X11*( X00*Y22 - X02*Y20 );<\/pre>\n<p>The full source code can be downloaded from:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/lessthanoptimal\/pypete\/blob\/master\/utilsym.py\">https:\/\/github.com\/lessthanoptimal\/pypete\/blob\/master\/utilsym.py<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/lessthanoptimal\/pypete\/blob\/master\/example_symbolic_expand.py\">https:\/\/github.com\/lessthanoptimal\/pypete\/blob\/master\/example_symbolic_expand.py<\/a><\/li>\n<\/ul>\n<p><em><strong>[1]<\/strong> David Nister &#8220;An Efficient Solution to the Five-Point Relative Pose Problem&#8221; Pattern Analysis and Machine Intelligence, 2004<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Abstract The following article demonstrates how Sage\/Python can be used to solve, format, and output auto generated code for complex symbolic equations. \u00a0 The auto-generated code can be targeted for languages such as C\/C++ or Java.\u00a0 Sage is a computer algebra system (CAS) that uses the Python programming language.\u00a0 By using Python it is easy [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[4],"tags":[16,19,14,15],"class_list":["post-107","post","type-post","status-publish","format-standard","hentry","category-programming","tag-math","tag-python","tag-sage","tag-symbolic"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/107","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=107"}],"version-history":[{"count":9,"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/107\/revisions"}],"predecessor-version":[{"id":155,"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/107\/revisions\/155"}],"wp:attachment":[{"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=107"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=107"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/peterabeles.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=107"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}