{"action":"created","comment":{"url":"https://api.github.com/repos/sympy/sympy/pulls/comments/209799021","pull_request_review_id":145882830,"id":209799021,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwOTc5OTAyMQ==","diff_hunk":"@@ -0,0 +1,599 @@\n+.. _autolev_parser:\n+\n+==============\n+Autolev Parser\n+==============\n+\n+.. role:: input(strong)\n+\n+Introduction\n+============\n+Autolev (now superseded by MotionGenesis) is a domain specific language\n+used for symbolic multibody dynamics. The SymPy mechanics module now has\n+enough power and functionality to be a fully featured symbolic dynamics\n+module. This parser parses Autolev (version 4.1) code to SymPy code by making\n+use of SymPy's math libraries and the mechanics module.\n+\n+The parser has been built using the `ANTLR <http://www.antlr.org/>`_ framework and its main purpose\n+is to help former users of Autolev to get familiarized with multibody dynamics\n+in SymPy.\n+\n+The sections below shall discuss details of the parser like usage, gotchas,\n+issues and future improvements.\n+For a detailed comparison of Autolev and SymPy/PyDy you might want to look at\n+the PyDy for Autolev Users guide.\n+\n+.. _usage:\n+\n+Usage\n+=====\n+\n+We first start with an Autolev code file.\n+\n+Let us take this example\n+(Comments ``%`` have been included to show the Autolev responses):\n+\n+.. code-block:: none\n+\n+   % double_pendulum.al\n+   %-------------------\n+   MOTIONVARIABLES' Q{2}', U{2}'\n+   CONSTANTS L,M,G\n+   NEWTONIAN N\n+   FRAMES A,B\n+   SIMPROT(N, A, 3, Q1)\n+   % -> N_A = [COS(Q1), -SIN(Q1), 0; SIN(Q1), COS(Q1), 0; 0, 0, 1]\n+   SIMPROT(N, B, 3, Q2)\n+   % -> N_B = [COS(Q2), -SIN(Q2), 0; SIN(Q2), COS(Q2), 0; 0, 0, 1]\n+   W_A_N>=U1*N3>\n+   % -> W_A_N> = U1*N3>\n+   W_B_N>=U2*N3>\n+   % -> W_B_N> = U2*N3>\n+   POINT O\n+   PARTICLES P,R\n+   P_O_P> = L*A1>\n+   % -> P_O_P> = L*A1>\n+   P_P_R> = L*B1>\n+   % -> P_P_R> = L*B1>\n+   V_O_N> = 0>\n+   % -> V_O_N> = 0>\n+   V2PTS(N, A, O, P)\n+   % -> V_P_N> = L*U1*A2>\n+   V2PTS(N, B, P, R)\n+   % -> V_R_N> = L*U1*A2> + L*U2*B2>\n+   MASS P=M, R=M\n+   Q1' = U1\n+   Q2' = U2\n+   GRAVITY(G*N1>)\n+   % -> FORCE_P> = G*M*N1>\n+   % -> FORCE_R> = G*M*N1>\n+   ZERO = FR() + FRSTAR()\n+   % -> ZERO[1] = -L*M*(2*G*SIN(Q1)+L*(U2^2*SIN(Q1-Q2)+2*U1'+COS(Q1-Q2)*U2'))\n+   % -> ZERO[2] = -L*M*(G*SIN(Q2)-L*(U1^2*SIN(Q1-Q2)-U2'-COS(Q1-Q2)*U1'))\n+   KANE()\n+   INPUT M=1,G=9.81,L=1\n+   INPUT Q1=.1,Q2=.2,U1=0,U2=0\n+   INPUT TFINAL=10, INTEGSTP=.01\n+   CODE DYNAMICS() some_filename.c\n+\n+The parser can be used as follows::\n+\n+    >>> from sympy.parsing.autolev import parse_autolev\n+    >>> parse_autolev('double_pendulum.al', 'double_pendulum.py', include_pydy=True)\n+    # The second parameter (to specify the output file) is optional. The\n+    # default action is to print the output code to stdout.\n+    #\n+    # The include_pydy flag is False by default. Setting it to True will\n+    # allow the PyDy code to be outputed if applicable.\n+\n+This is the parsed code in ``double_pendulum.py``::\n+\n+    import sympy.physics.mechanics as me\n+    import sympy as sm\n+    import math as m\n+    import numpy as np\n+\n+    q1, q2, u1, u2 = me.dynamicsymbols('q1 q2 u1 u2')\n+    q1d, q2d, u1d, u2d = me.dynamicsymbols('q1 q2 u1 u2', 1)\n+    l, m, g=sm.symbols('l m g', real=True)\n+    frame_n=me.ReferenceFrame('n')\n+    frame_a=me.ReferenceFrame('a')\n+    frame_b=me.ReferenceFrame('b')\n+    frame_a.orient(frame_n, 'Axis', [q1, frame_n.z])\n+    # print(frame_n.dcm(frame_a))\n+    frame_b.orient(frame_n, 'Axis', [q2, frame_n.z])\n+    # print(frame_n.dcm(frame_b))\n+    frame_a.set_ang_vel(frame_n, u1*frame_n.z)\n+    # print(frame_a.ang_vel_in(frame_n))\n+    frame_b.set_ang_vel(frame_n, u2*frame_n.z)\n+    # print(frame_b.ang_vel_in(frame_n))\n+    point_o=me.Point('o')\n+    particle_p=me.Particle('p', me.Point('p_pt'), sm.Symbol('m'))\n+    particle_r=me.Particle('r', me.Point('r_pt'), sm.Symbol('m'))\n+    particle_p.point.set_pos(point_o, l*frame_a.x)\n+    # print(particle_p.point.pos_from(point_o))\n+    particle_r.point.set_pos(particle_p.point, l*frame_b.x)\n+    # print(particle_p.point.pos_from(particle_r.point))\n+    point_o.set_vel(frame_n, 0)\n+    # print(point_o.vel(frame_n))\n+    particle_p.point.v2pt_theory(point_o,frame_n,frame_a)\n+    # print(particle_p.point.vel(frame_n))\n+    particle_r.point.v2pt_theory(particle_p.point,frame_n,frame_b)\n+    # print(particle_r.point.vel(frame_n))\n+    particle_p.mass = m\n+    particle_r.mass = m\n+    force_p = particle_p.mass*(g*frame_n.x)\n+    # print(force_p)\n+    force_r = particle_r.mass*(g*frame_n.x)\n+    # print(force_r)\n+    kd_eqs = [q1d - u1, q2d - u2]\n+    forceList = [(particle_p.point,particle_p.mass*(g*frame_n.x)), (particle_r.point,particle_r.mass*(g*frame_n.x))]\n+    kane = me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u1, u2], kd_eqs = kd_eqs)\n+    fr, frstar = kane.kanes_equations([particle_p, particle_r], forceList)\n+    zero = fr+frstar\n+    # print(zero)\n+    #---------PyDy code for integration----------\n+    from pydy.system import System\n+    sys = System(kane, constants = {l:1, m:1, g:9.81},\n+    specifieds={},\n+    initial_conditions={q1:.1, q2:.2, u1:0, u2:0},\n+    times = np.linspace(0.0, 10, 10/.01))\n+\n+    y=sys.integrate()\n+\n+\n+The commented code is not part of the output code. The print\n+statements demonstrate how to get responses similar to the ones in the\n+Autolev file.\n+Note that we need to use SymPy functions like ``.ang_vel_in()``, ``.dcm()``\n+etc in many cases unlike directly printing out the variables like ``zero``.\n+If you are completely new to SymPy mechanics, the PyDy for Autolev Users\n+guide should help. You might also have to use basic SymPy simplifications\n+and manipulations like ``trigsimp()``, ``expand()``, ``evalf()`` etc for \n+getting outputs similar to Autolev.\n+Refer to the `SymPy Tutorial <http://docs.sympy.org/latest/tutorial/index.html>`_\n+to know more about these.\n+\n+.. _gotchas_autolev:\n+\n+Gotchas\n+=======\n+\n+- Don't use variable names that conflict with Python's reserved words.\n+  This is one example where this is violated:\n+\n+  .. code-block:: none\n+\n+     Autolev Code\n+     ------------\n+     LAMBDA = EIG(M)\n+\n+  .. code-block:: python\n+\n+     SymPy Code\n+     ----------\n+     lambda = sm.Matrix([i.evalf() for i in (m).eigenvals().keys()])\n+\n+------------------------------------------------------------------------\n+\n+- Make sure that the names of vectors and scalars are different.\n+  Autolev treats these differently but these will get overwritten in Python.\n+  The parser currently allows the names of bodies and scalars/vectors to\n+  coincide but doesn't do this between scalars and vectors.\n+  This should probably be changed in the future.\n+\n+  .. code-block:: none\n+\n+     Autolev Code\n+     ------------\n+     VARIABLES X,Y\n+     FRAMES A\n+     A> = X*A1> + Y*A2>\n+     A = X+Y\n+\n+  .. code-block:: python\n+\n+     SymPy Code\n+     ----------\n+     x, y = me.dynamicsymbols('x y')\n+     frame_a = me.ReferenceFrame('a')\n+     a = x*frame_a.x + y*frame_a.y\n+     a = x + y\n+     # Note how frame_a is named differently so it doesn't cause a problem.\n+     # On the other hand, 'a' gets rewritten from a scalar to a vector.\n+     # This should be changed in the future.\n+\n+\n+------------------------------------------------------------------------\n+\n+- When dealing with Matrices returned by functions, one must check the\n+  order of the values as they may not be the same as in Autolev. This is\n+  especially the case for eigenvalues and eigenvetors.\n+  \n+  .. code-block:: none\n+\n+     Autolev Code\n+     ------------\n+     EIG(M, E1, E2)\n+     % -> [5; 14; 13]\n+     E2ROW = ROWS(E2, 1)\n+     EIGVEC> = VECTOR(A, E2ROW)\n+\n+  .. code-block:: python\n+\n+     SymPy Code\n+     ---------- \n+     e1 = sm.Matrix([i.evalf() for i in m.eigenvals().keys()])\n+     # sm.Matrix([5;13;14]) different order\n+     e2 = sm.Matrix([i[2][0].evalf() for i in m.eigenvects()]).reshape(m.shape[0], m.shape[1])\n+     e2row = e2.row(0)\n+     # This result depends on the order of the vectors in the eigenvecs.\n+     eigenvec = e2row[0]*a.x + e2row[1]*a.y + e2row[2]*a.y\n+\n+------------------------------------------------------------------------\n+\n+- When using ``EVALUATE``, use something like ``90*UNITS(deg,rad)`` for \n+  angle substitutions as radians are the default in SymPy.\n+  You could also add ``np.deg2rad()`` directly in the SymPy code.\n+  \n+  This need not be done for the output code (generated on parsing the\n+  ``CODE`` commands) as the parser takes care of this when ``deg`` units\n+  are given in the ``INPUT`` declarations. \n+  \n+  The ``DEGREES`` setting, on the other hand, works only in some cases like \n+  in ``SIMPROT`` where an angle is expected.\n+\n+  .. code-block:: none\n+\n+     Autolev Code\n+     ------------\n+     A> = Q1*A1> + Q2*A2>\n+     B> = EVALUATE(A>, Q1:30*UNITS(DEG,RAD))\n+\n+  .. code-block:: python\n+  \n+     SymPy Code\n+     ----------\n+     a = q1*a.frame_a.x + q2*frame_a.y\n+     b = a.subs({q1:30*0.0174533})\n+     # b = a.subs({q1:np.deg2rad(30)}\n+\n+------------------------------------------------------------------------\n+\n+- Most of the Autolev settings have not been parsed and have no effect on the parser.\n+  The only ones that work somewhat are ``COMPLEX`` and ``DEGREES``.\n+  It is advised to look into alternatives to these in SymPy and Python.\n+\n+------------------------------------------------------------------------\n+\n+- The ``REPRESENT`` command is not supported.\n+  Use the ``MATRIX``, ``VECTOR`` or ``DYADIC`` commands instead.\n+  Autolev 4.1 suggests these over ``REPRESENT`` as well while still allowing\n+  it but the parser doesn't parse it.\n+\n+------------------------------------------------------------------------\n+\n+- Do not use variables declarations of the type ``WO{3}RD{2,4}``.\n+  The parser can only handle one variable name followed by one pair\n+  of curly braces and any number of ``'`` s.\n+  You would have to declare all the cases manually if you want to achieve\n+  something like ``WO{3}RD{2,4}``.\n+\n+------------------------------------------------------------------------\n+\n+- The parser can handle normal versions of most commands but it may not\n+  parse functions with Matrix arguments properly in most cases.\n+  Eg:\n+\n+  ``M=COEF([E1;E2],[U1,U2,U3])``\n+\n+  This would compute the coefficients of ``U1``, ``U2`` and ``U3`` in ``E1``\n+  and ``E2``. It is preferable to manually construct a Matrix using the \n+  regular versions of these commands.\n+\n+  .. code-block:: none\n+\n+     Autolev Code\n+     ------------\n+     % COEF([E1;E2],[U1,U2,U3])\n+     M = [COEF(E1,U1),COEF(E1,U2),COEF(E1,U3) &\n+         ;COEF(E2,U1),COEF(E2,U2),COEF(E2,U3)]    \n+\n+------------------------------------------------------------------------\n+\n+- ``MOTIONVARIABLE`` declarations must be used for the generalized coordinates\n+  and speeds and all other variables must be declared in regular\n+  ``VARIABLE`` declarations.\n+  The parser requires this to distinguish between them to pass the correct\n+  parameters to the Kane's method object.\n+  \n+  It is also preferred to always declare the speeds corresponding to the\n+  coordinates and to pass in the kinematic differential equations.\n+  The parser is able to handle some cases where this isn't the case by\n+  introducing some dummy variables of its own but SymPy on its own\n+  does require them.\n+  \n+  Also note that older Autolev declarations like ``VARIABLES U{3}'`` are not\n+  supported either.\n+\n+  .. code-block:: none\n+\n+     Autolev Code\n+     ------------\n+     MOTIONVARIABLES' Q{2}', U{2}'\n+     % ----- OTHER LINES ----\n+     Q1' = U1\n+     Q2' = U2\n+     ----- OTHER LINES ----\n+     ZERO = FR() + FRSTAR()\n+\n+  .. code-block:: python\n+\n+     SymPy Code\n+     ----------\n+     q1, q2, u1, u2 = me.dynamicsymbols('q1 q2 u1 u2')\n+     q1d, q2d, u1d, u2d = me.dynamicsymbols('q1 q2 u1 u2', 1)\n+     \n+     # ------- other lines -------\n+     \n+     kd_eqs = [q1d - u1, q2d - u2]\n+     kane = me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u1, u2], kd_eqs = kd_eqs)\n+     fr, frstar = kane.kanes_equations([particle_p, particle_r], forceList)\n+     zero = fr+frstar\n+\n+------------------------------------------------------------------------\n+\n+- Need to change ``me.dynamicsymbols._t`` to ``me.dynamicsymbols('t')`` for\n+  all occurences of it in the Kane's equations. For example have a look at\n+  line 10 of this `spring damper example <https://github.com/sympy/sympy/blob/master/sympy/parsing/autolev/test_examples/mass_spring_damper.py>`_.\n+  This equation is used in forming the Kane's equations so we need to\n+  change ``me.dynamicsymbols._t`` to ``me.dynamicsymbols('t')`` in this case.\n+  \n+  The main reason that this needs to be done is because PyDy\n+  requires time dependent specifieds to be explicitly laid out while\n+  Autolev simply takes care of the stray time variables in the equations\n+  by itself.\n+  \n+  The problem is that PyDy's System class does not accept\n+  ``dynamicsymbols._t`` as a specified. \n+  This change is not actually ideal so a better solution should be figured\n+  out in the future.\n+\n+------------------------------------------------------------------------\n+\n+- The parser creates SymPy ``symbols`` and ``dynamicsymbols`` by parsing\n+  variable declarations in the Autolev Code.\n+  \n+  For intermediate expressions which are directly initialized the parser\n+  does not create SymPy symbols. It just assigns them to the expression.\n+  \n+  On the other hand, when a declared variable is assigned to an expression,\n+  the parser stores the expression against the variable in a dictionary so \n+  as to not reassign it to a completely different entity. This constraint \n+  is due to the inherent nature of Python and how it differs from a language\n+  like Autolev.\n+  \n+  Also, Autolev seems to be able to assume whether to use a variable or the\n+  rhs expression that variable has been assigned to in equations even\n+  without an explicit ``RHS()`` call in some cases.\n+  For the parser to work correctly however, it is better to use ``RHS()``\n+  wherever a variable's rhs expression is meant to be used.\n+\n+  .. code-block:: none\n+\n+     Autolev Code\n+     ------------\n+     VARIABLES X, Y\n+     E = X + Y\n+     X = 2*Y\n+     \n+     RHS_X = RHS(X)\n+     \n+     I1 = X\n+     I2 = Y\n+     I3 = X + Y\n+     \n+     INERTIA B,I1,I2,I3\n+     % -> I_B_BO>> = I1*B1>*B1> + I2*B2>*B2> + I3*B3>*B3>\n+\n+  .. code-block:: python\n+\n+     SymPy Code\n+     ----------\n+     x,y = me.dynamicsymbols('x y')\n+     e = x + y  # No symbol is made out of 'e'\n+     \n+     # an entry like {x:2*y} is stored in an rhs dictionary\n+     \n+     rhs_x = 2*y\n+     \n+     i1 = x  # again these are not made into SymPy symbols\n+     i2 = y\n+     i3 = x + y\n+     \n+     body_b.inertia = (me.inertia(body_b_f, i1, i2, i3), b_cm)\n+     # This prints as:\n+     # x*b_f.x*b_f.x + y*b_f.y*b_f.y + (x+y)*b_f.z*b_f.z\n+     # while Autolev's output has I1,I2 and I3 in it.\n+     # Autolev however seems to know when to use the RHS of I1,I2 and I3\n+     # based on the context.\n+  \n+------------------------------------------------------------------------\n+\n+- This is how the ``SOLVE`` command is parsed:\n+\n+  .. code-block:: none\n+\n+     Autolev Code\n+     ------------\n+     SOLVE(ZERO,X,Y)\n+     A = RHS(X)*2 + RHS(Y)\n+\n+  .. code-block:: python\n+\n+     SymPy Code\n+     ----------","path":"doc/src/modules/physics/mechanics/autolev_parser.rst","position":174,"original_position":435,"commit_id":"e99ae94bb0002dbedbeb8663c43cac121b3023fe","original_commit_id":"e99ae94bb0002dbedbeb8663c43cac121b3023fe","user":{"login":"moorepants","id":276007,"node_id":"MDQ6VXNlcjI3NjAwNw==","avatar_url":"https://avatars0.githubusercontent.com/u/276007?v=4","gravatar_id":"","url":"https://api.github.com/users/moorepants","html_url":"https://github.com/moorepants","followers_url":"https://api.github.com/users/moorepants/followers","following_url":"https://api.github.com/users/moorepants/following{/other_user}","gists_url":"https://api.github.com/users/moorepants/gists{/gist_id}","starred_url":"https://api.github.com/users/moorepants/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/moorepants/subscriptions","organizations_url":"https://api.github.com/users/moorepants/orgs","repos_url":"https://api.github.com/users/moorepants/repos","events_url":"https://api.github.com/users/moorepants/events{/privacy}","received_events_url":"https://api.github.com/users/moorepants/received_events","type":"User","site_admin":false},"body":"These should be made comments with `#`.","created_at":"2018-08-14T00:27:55Z","updated_at":"2018-08-14T00:27:55Z","html_url":"https://github.com/sympy/sympy/pull/15067#discussion_r209799021","pull_request_url":"https://api.github.com/repos/sympy/sympy/pulls/15067","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/sympy/sympy/pulls/comments/209799021"},"html":{"href":"https://github.com/sympy/sympy/pull/15067#discussion_r209799021"},"pull_request":{"href":"https://api.github.com/repos/sympy/sympy/pulls/15067"}}},"pull_request":{"url":"https://api.github.com/repos/sympy/sympy/pulls/15067","id":207450143,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA3NDUwMTQz","html_url":"https://github.com/sympy/sympy/pull/15067","diff_url":"https://github.com/sympy/sympy/pull/15067.diff","patch_url":"https://github.com/sympy/sympy/pull/15067.patch","issue_url":"https://api.github.com/repos/sympy/sympy/issues/15067","number":15067,"state":"closed","locked":false,"title":"Autolev parser docs 3","user":{"login":"NikhilPappu","id":5346855,"node_id":"MDQ6VXNlcjUzNDY4NTU=","avatar_url":"https://avatars1.githubusercontent.com/u/5346855?v=4","gravatar_id":"","url":"https://api.github.com/users/NikhilPappu","html_url":"https://github.com/NikhilPappu","followers_url":"https://api.github.com/users/NikhilPappu/followers","following_url":"https://api.github.com/users/NikhilPappu/following{/other_user}","gists_url":"https://api.github.com/users/NikhilPappu/gists{/gist_id}","starred_url":"https://api.github.com/users/NikhilPappu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/NikhilPappu/subscriptions","organizations_url":"https://api.github.com/users/NikhilPappu/orgs","repos_url":"https://api.github.com/users/NikhilPappu/repos","events_url":"https://api.github.com/users/NikhilPappu/events{/privacy}","received_events_url":"https://api.github.com/users/NikhilPappu/received_events","type":"User","site_admin":false},"body":"<!-- BEGIN RELEASE NOTES -->\r\n- other\r\n  - Added the issues and future improvements sections to autolev_parser.rst in the mechanics part of the documentation.\r\n<!-- END RELEASE NOTES -->\r\n","created_at":"2018-08-09T21:32:35Z","updated_at":"2018-08-14T00:27:55Z","closed_at":"2018-08-13T21:51:36Z","merged_at":"2018-08-13T21:51:36Z","merge_commit_sha":"2961d8f076b742919d4a6fbe99a94d3cf5e46f9c","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":75863299,"node_id":"MDU6TGFiZWw3NTg2MzI5OQ==","url":"https://api.github.com/repos/sympy/sympy/labels/Documentation","name":"Documentation","color":"c7def8","default":false},{"id":97640110,"node_id":"MDU6TGFiZWw5NzY0MDExMA==","url":"https://api.github.com/repos/sympy/sympy/labels/GSoC","name":"GSoC","color":"009800","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/sympy/sympy/pulls/15067/commits","review_comments_url":"https://api.github.com/repos/sympy/sympy/pulls/15067/comments","review_comment_url":"https://api.github.com/repos/sympy/sympy/pulls/comments{/number}","comments_url":"https://api.github.com/repos/sympy/sympy/issues/15067/comments","statuses_url":"https://api.github.com/repos/sympy/sympy/statuses/e99ae94bb0002dbedbeb8663c43cac121b3023fe","head":{"label":"NikhilPappu:autolev_parser_docs_3","ref":"autolev_parser_docs_3","sha":"e99ae94bb0002dbedbeb8663c43cac121b3023fe","user":{"login":"NikhilPappu","id":5346855,"node_id":"MDQ6VXNlcjUzNDY4NTU=","avatar_url":"https://avatars1.githubusercontent.com/u/5346855?v=4","gravatar_id":"","url":"https://api.github.com/users/NikhilPappu","html_url":"https://github.com/NikhilPappu","followers_url":"https://api.github.com/users/NikhilPappu/followers","following_url":"https://api.github.com/users/NikhilPappu/following{/other_user}","gists_url":"https://api.github.com/users/NikhilPappu/gists{/gist_id}","starred_url":"https://api.github.com/users/NikhilPappu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/NikhilPappu/subscriptions","organizations_url":"https://api.github.com/users/NikhilPappu/orgs","repos_url":"https://api.github.com/users/NikhilPappu/repos","events_url":"https://api.github.com/users/NikhilPappu/events{/privacy}","received_events_url":"https://api.github.com/users/NikhilPappu/received_events","type":"User","site_admin":false},"repo":{"id":102941053,"node_id":"MDEwOlJlcG9zaXRvcnkxMDI5NDEwNTM=","name":"sympy","full_name":"NikhilPappu/sympy","owner":{"login":"NikhilPappu","id":5346855,"node_id":"MDQ6VXNlcjUzNDY4NTU=","avatar_url":"https://avatars1.githubusercontent.com/u/5346855?v=4","gravatar_id":"","url":"https://api.github.com/users/NikhilPappu","html_url":"https://github.com/NikhilPappu","followers_url":"https://api.github.com/users/NikhilPappu/followers","following_url":"https://api.github.com/users/NikhilPappu/following{/other_user}","gists_url":"https://api.github.com/users/NikhilPappu/gists{/gist_id}","starred_url":"https://api.github.com/users/NikhilPappu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/NikhilPappu/subscriptions","organizations_url":"https://api.github.com/users/NikhilPappu/orgs","repos_url":"https://api.github.com/users/NikhilPappu/repos","events_url":"https://api.github.com/users/NikhilPappu/events{/privacy}","received_events_url":"https://api.github.com/users/NikhilPappu/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/NikhilPappu/sympy","description":"A computer algebra system written in pure Python","fork":true,"url":"https://api.github.com/repos/NikhilPappu/sympy","forks_url":"https://api.github.com/repos/NikhilPappu/sympy/forks","keys_url":"https://api.github.com/repos/NikhilPappu/sympy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/NikhilPappu/sympy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/NikhilPappu/sympy/teams","hooks_url":"https://api.github.com/repos/NikhilPappu/sympy/hooks","issue_events_url":"https://api.github.com/repos/NikhilPappu/sympy/issues/events{/number}","events_url":"https://api.github.com/repos/NikhilPappu/sympy/events","assignees_url":"https://api.github.com/repos/NikhilPappu/sympy/assignees{/user}","branches_url":"https://api.github.com/repos/NikhilPappu/sympy/branches{/branch}","tags_url":"https://api.github.com/repos/NikhilPappu/sympy/tags","blobs_url":"https://api.github.com/repos/NikhilPappu/sympy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/NikhilPappu/sympy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/NikhilPappu/sympy/git/refs{/sha}","trees_url":"https://api.github.com/repos/NikhilPappu/sympy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/NikhilPappu/sympy/statuses/{sha}","languages_url":"https://api.github.com/repos/NikhilPappu/sympy/languages","stargazers_url":"https://api.github.com/repos/NikhilPappu/sympy/stargazers","contributors_url":"https://api.github.com/repos/NikhilPappu/sympy/contributors","subscribers_url":"https://api.github.com/repos/NikhilPappu/sympy/subscribers","subscription_url":"https://api.github.com/repos/NikhilPappu/sympy/subscription","commits_url":"https://api.github.com/repos/NikhilPappu/sympy/commits{/sha}","git_commits_url":"https://api.github.com/repos/NikhilPappu/sympy/git/commits{/sha}","comments_url":"https://api.github.com/repos/NikhilPappu/sympy/comments{/number}","issue_comment_url":"https://api.github.com/repos/NikhilPappu/sympy/issues/comments{/number}","contents_url":"https://api.github.com/repos/NikhilPappu/sympy/contents/{+path}","compare_url":"https://api.github.com/repos/NikhilPappu/sympy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/NikhilPappu/sympy/merges","archive_url":"https://api.github.com/repos/NikhilPappu/sympy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/NikhilPappu/sympy/downloads","issues_url":"https://api.github.com/repos/NikhilPappu/sympy/issues{/number}","pulls_url":"https://api.github.com/repos/NikhilPappu/sympy/pulls{/number}","milestones_url":"https://api.github.com/repos/NikhilPappu/sympy/milestones{/number}","notifications_url":"https://api.github.com/repos/NikhilPappu/sympy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/NikhilPappu/sympy/labels{/name}","releases_url":"https://api.github.com/repos/NikhilPappu/sympy/releases{/id}","deployments_url":"https://api.github.com/repos/NikhilPappu/sympy/deployments","created_at":"2017-09-09T08:55:14Z","updated_at":"2017-09-12T06:03:32Z","pushed_at":"2018-08-13T22:24:04Z","git_url":"git://github.com/NikhilPappu/sympy.git","ssh_url":"git@github.com:NikhilPappu/sympy.git","clone_url":"https://github.com/NikhilPappu/sympy.git","svn_url":"https://github.com/NikhilPappu/sympy","homepage":"http://sympy.org/","size":94309,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"sympy:master","ref":"master","sha":"0b350a21abb4be018dc3f279307ee676c9888ba7","user":{"login":"sympy","id":260832,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI2MDgzMg==","avatar_url":"https://avatars1.githubusercontent.com/u/260832?v=4","gravatar_id":"","url":"https://api.github.com/users/sympy","html_url":"https://github.com/sympy","followers_url":"https://api.github.com/users/sympy/followers","following_url":"https://api.github.com/users/sympy/following{/other_user}","gists_url":"https://api.github.com/users/sympy/gists{/gist_id}","starred_url":"https://api.github.com/users/sympy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sympy/subscriptions","organizations_url":"https://api.github.com/users/sympy/orgs","repos_url":"https://api.github.com/users/sympy/repos","events_url":"https://api.github.com/users/sympy/events{/privacy}","received_events_url":"https://api.github.com/users/sympy/received_events","type":"Organization","site_admin":false},"repo":{"id":640534,"node_id":"MDEwOlJlcG9zaXRvcnk2NDA1MzQ=","name":"sympy","full_name":"sympy/sympy","owner":{"login":"sympy","id":260832,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI2MDgzMg==","avatar_url":"https://avatars1.githubusercontent.com/u/260832?v=4","gravatar_id":"","url":"https://api.github.com/users/sympy","html_url":"https://github.com/sympy","followers_url":"https://api.github.com/users/sympy/followers","following_url":"https://api.github.com/users/sympy/following{/other_user}","gists_url":"https://api.github.com/users/sympy/gists{/gist_id}","starred_url":"https://api.github.com/users/sympy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sympy/subscriptions","organizations_url":"https://api.github.com/users/sympy/orgs","repos_url":"https://api.github.com/users/sympy/repos","events_url":"https://api.github.com/users/sympy/events{/privacy}","received_events_url":"https://api.github.com/users/sympy/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/sympy/sympy","description":"A computer algebra system written in pure Python","fork":false,"url":"https://api.github.com/repos/sympy/sympy","forks_url":"https://api.github.com/repos/sympy/sympy/forks","keys_url":"https://api.github.com/repos/sympy/sympy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sympy/sympy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sympy/sympy/teams","hooks_url":"https://api.github.com/repos/sympy/sympy/hooks","issue_events_url":"https://api.github.com/repos/sympy/sympy/issues/events{/number}","events_url":"https://api.github.com/repos/sympy/sympy/events","assignees_url":"https://api.github.com/repos/sympy/sympy/assignees{/user}","branches_url":"https://api.github.com/repos/sympy/sympy/branches{/branch}","tags_url":"https://api.github.com/repos/sympy/sympy/tags","blobs_url":"https://api.github.com/repos/sympy/sympy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sympy/sympy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sympy/sympy/git/refs{/sha}","trees_url":"https://api.github.com/repos/sympy/sympy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sympy/sympy/statuses/{sha}","languages_url":"https://api.github.com/repos/sympy/sympy/languages","stargazers_url":"https://api.github.com/repos/sympy/sympy/stargazers","contributors_url":"https://api.github.com/repos/sympy/sympy/contributors","subscribers_url":"https://api.github.com/repos/sympy/sympy/subscribers","subscription_url":"https://api.github.com/repos/sympy/sympy/subscription","commits_url":"https://api.github.com/repos/sympy/sympy/commits{/sha}","git_commits_url":"https://api.github.com/repos/sympy/sympy/git/commits{/sha}","comments_url":"https://api.github.com/repos/sympy/sympy/comments{/number}","issue_comment_url":"https://api.github.com/repos/sympy/sympy/issues/comments{/number}","contents_url":"https://api.github.com/repos/sympy/sympy/contents/{+path}","compare_url":"https://api.github.com/repos/sympy/sympy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sympy/sympy/merges","archive_url":"https://api.github.com/repos/sympy/sympy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sympy/sympy/downloads","issues_url":"https://api.github.com/repos/sympy/sympy/issues{/number}","pulls_url":"https://api.github.com/repos/sympy/sympy/pulls{/number}","milestones_url":"https://api.github.com/repos/sympy/sympy/milestones{/number}","notifications_url":"https://api.github.com/repos/sympy/sympy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sympy/sympy/labels{/name}","releases_url":"https://api.github.com/repos/sympy/sympy/releases{/id}","deployments_url":"https://api.github.com/repos/sympy/sympy/deployments","created_at":"2010-04-30T20:37:14Z","updated_at":"2018-08-13T22:36:23Z","pushed_at":"2018-08-13T23:37:12Z","git_url":"git://github.com/sympy/sympy.git","ssh_url":"git@github.com:sympy/sympy.git","clone_url":"https://github.com/sympy/sympy.git","svn_url":"https://github.com/sympy/sympy","homepage":"http://sympy.org/","size":94379,"stargazers_count":5020,"watchers_count":5020,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2315,"mirror_url":null,"archived":false,"open_issues_count":3401,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":2315,"open_issues":3401,"watchers":5020,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/sympy/sympy/pulls/15067"},"html":{"href":"https://github.com/sympy/sympy/pull/15067"},"issue":{"href":"https://api.github.com/repos/sympy/sympy/issues/15067"},"comments":{"href":"https://api.github.com/repos/sympy/sympy/issues/15067/comments"},"review_comments":{"href":"https://api.github.com/repos/sympy/sympy/pulls/15067/comments"},"review_comment":{"href":"https://api.github.com/repos/sympy/sympy/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/sympy/sympy/pulls/15067/commits"},"statuses":{"href":"https://api.github.com/repos/sympy/sympy/statuses/e99ae94bb0002dbedbeb8663c43cac121b3023fe"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"moorepants"}}