
    MZdPo                         d Z ddlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZmZ ddlmZ dd	lmZ dd
lmZmZ  G d d      Zy)zB
This module can be used to solve problems related
to 2D Trusses.
    )inf)Add)Mul)Symbol)sympify)Matrixpi)sqrt)zeros)sincosc                       e Zd ZdZd Zed        Zed        Zed        Zed        Z	ed        Z
ed        Zed	        Zed
        Zed        Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zy)Trussa  
    A Truss is an assembly of members such as beams,
    connected by nodes, that create a rigid structure.
    In engineering, a truss is a structure that
    consists of two-force members only.

    Trusses are extremely important in engineering applications
    and can be seen in numerous real-world applications like bridges.

    Examples
    ========

    There is a Truss consisting of four nodes and five
    members connecting the nodes. A force P acts
    downward on the node D and there also exist pinned
    and roller joints on the nodes A and B respectively.

    .. image:: truss_example.png

    >>> from sympy.physics.continuum_mechanics.truss import Truss
    >>> t = Truss()
    >>> t.add_node("node_1", 0, 0)
    >>> t.add_node("node_2", 6, 0)
    >>> t.add_node("node_3", 2, 2)
    >>> t.add_node("node_4", 2, 0)
    >>> t.add_member("member_1", "node_1", "node_4")
    >>> t.add_member("member_2", "node_2", "node_4")
    >>> t.add_member("member_3", "node_1", "node_3")
    >>> t.add_member("member_4", "node_2", "node_3")
    >>> t.add_member("member_5", "node_3", "node_4")
    >>> t.apply_load("node_4", magnitude=10, direction=270)
    >>> t.apply_support("node_1", type="fixed")
    >>> t.apply_support("node_2", type="roller")
    c                     g | _         i | _        i | _        i | _        g | _        g | _        g | _        g | _        i | _        i | _	        i | _
        i | _        y)z'
        Initializes the class
        N)_nodes_members_loads	_supports_node_labels_node_positions_node_position_x_node_position_y_nodes_occupied_reaction_loads_internal_forces_node_coordinatesselfs    I/usr/lib/python3/dist-packages/sympy/physics/continuum_mechanics/truss.py__init__zTruss.__init__6   s`     ! " "!! "!#    c                     | j                   S )zL
        Returns the nodes of the truss along with their positions.
        )r   r   s    r   nodeszTruss.nodesG       
 {{r!   c                     | j                   S )z7
        Returns the node labels of the truss.
        )r   r   s    r   node_labelszTruss.node_labelsN   s    
    r!   c                     | j                   S )zB
        Returns the positions of the nodes of the truss.
        )r   r   s    r   node_positionszTruss.node_positionsU       
 ###r!   c                     | j                   S zW
        Returns the members of the truss along with the start and end points.
        )r   r   s    r   memberszTruss.members\   s    
 }}r!   c                     | j                   S r+   )_member_labelsr   s    r   member_labelszTruss.member_labelsc   s    
 """r!   c                     | j                   S )z
        Returns the nodes with provided supports along with the kind of support provided i.e.
        pinned or roller.
        )r   r   s    r   supportszTruss.supportsj   s     ~~r!   c                     | j                   S )z8
        Returns the loads acting on the truss.
        )r   r   s    r   loadszTruss.loadsr   r$   r!   c                     | j                   S )z^
        Returns the reaction forces for all supports which are all initialized to 0.
        )r   r   s    r   reaction_loadszTruss.reaction_loadsy   r)   r!   c                     | j                   S )z]
        Returns the internal forces for all members which are all initialized to 0.
        )r   r   s    r   internal_forceszTruss.internal_forces   s    
 $$$r!   c                 X   t        |      }t        |      }|| j                  v rt        d      || j                  v rP|| j                  v rB| j                  j                  |      | j                  j                  |      k(  rt        d      | j                  j                  |||f       | j                  j                  |       | j                  j                  ||f       | j                  j                  |       | j                  j                  |       ||g| j                  |<   y)a  
        This method adds a node to the truss along with its name/label and its location.

        Parameters
        ==========
        label:  String or a Symbol
            The label for a node. It is the only way to identify a particular node.

        x: Sympifyable
            The x-coordinate of the position of the node.

        y: Sympifyable
            The y-coordinate of the position of the node.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.nodes
        [('A', 0, 0)]
        >>> t.add_node('B', 3, 0)
        >>> t.nodes
        [('A', 0, 0), ('B', 3, 0)]
        z!Node needs to have a unique labelz+A node already exists at the given positionN)
r   r   
ValueErrorr   r   indexr   appendr   r   )r   labelxys       r   add_nodezTruss.add_node   s!   6 AJAJD%%%@AA$'''A1F1F,F4K`K`KfKfghKiko  lA  lA  lG  lG  HI  lJ  LJJKK KKq!}-$$U+  ''A/!!((+!!((+-.FD""5)r!   c                    t        t        | j                              D ]3  }| j                  |   |k(  s| j                  |   }| j
                  |   }5 || j                  vrt        d      | j                  j                         }|D ]7  }|| j                  |   d   k(  s|| j                  |   d   k(  s.t        d       | j                  j                  |f       | j                  j                  |       | j                  j                  ||f       | j                  j                  |       | j
                  j                  |       |t        | j                        v r| j                  j                  |       |t        | j                        v r| j                  j                  |       | j                   j                  |       y)a%  
        This method removes a node from the truss.

        Parameters
        ==========
        label:  String or Symbol
            The label of the node to be removed.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.nodes
        [('A', 0, 0)]
        >>> t.add_node('B', 3, 0)
        >>> t.nodes
        [('A', 0, 0), ('B', 3, 0)]
        >>> t.remove_node('A')
        >>> t.nodes
        [('B', 3, 0)]
        z No such node exists in the trussr      z1The node given has members already attached to itN)rangelenr#   r   r   r   r9   r   copyr   remover   listr   popr   r   )r   r<   ir=   r>   members_duplicatemembers          r   remove_nodezTruss.remove_node   s   0 s4::' 	-A  #u,))!,))!,	-
 )))?@@ !% 2 2 4+ ZDMM&1!44vAVWXAY8Y$%XYYZ KKq!}-$$U+  ''A/!!((+!!((+T[[))&T^^,,""5)""&&u-r!   c                 t   || j                   vs|| j                   vs||k(  rt        d      |t        | j                        v rt        d      | j                  j                  ||f      rt        d      ||g| j                  |<   d| j                  ||f<   d| j                  ||f<   d| j                  |<   y)a  
        This method adds a member between any two nodes in the given truss.

        Parameters
        ==========
        label: String or Symbol
            The label for a member. It is the only way to identify a particular member.

        start: String or Symbol
            The label of the starting point/node of the member.

        end: String or Symbol
            The label of the ending point/node of the member.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.add_node('C', 2, 2)
        >>> t.add_member('AB', 'A', 'B')
        >>> t.members
        {'AB': ['A', 'B']}
        z;The start and end points of the member must be unique nodesz9A member with the same label already exists for the trussz-A member already exists between the two nodesTr   N)r   r9   rF   r   r   getr   )r   r<   startends       r   
add_memberzTruss.add_member   s    8 )))S8I8I-IUTWZZ[[d4==))XYY!!%%ucl3LMM %*3<DMM% /3D  ,/3D  e,+,D!!%(r!   c                    |t        | j                        vrt        d      | j                  j	                  | j                  |   d   | j                  |   d   f       | j                  j	                  | j                  |   d   | j                  |   d   f       | j                  j	                  |       | j
                  j	                  |       y)a  
        This method removes a member from the given truss.

        Parameters
        ==========
        label: String or Symbol
            The label for the member to be removed.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.add_node('C', 2, 2)
        >>> t.add_member('AB', 'A', 'B')
        >>> t.add_member('AC', 'A', 'C')
        >>> t.add_member('BC', 'B', 'C')
        >>> t.members
        {'AB': ['A', 'B'], 'AC': ['A', 'C'], 'BC': ['B', 'C']}
        >>> t.remove_member('AC')
        >>> t.members
        {'AB': ['A', 'B'], 'BC': ['B', 'C']}
        z"No such member exists in the Trussr   rA   N)rF   r   r9   r   rG   r   )r   r<   s     r   remove_memberzTruss.remove_member  s    4 T]]++ABB   $$dmmE&:1&=t}}U?STU?V%WX  $$dmmE&:1&=t}}U?STU?V%WXMMe$!!%%e,r!   c                 t   || j                   vrt        d      || j                   v rt        d      | j                  D ]v  }|d   |k(  s||d   |d   f| j                  | j                  j                  ||d   |d   f      <   || j                   | j                   j                  |d         <   | j                  |   | j                  |<   | j                  j                  |       |d   t        | j                        v r=| j                  |d      | j                  |<   | j                  j                  |d          |t        | j                        v rg| j                  |   dk(  rudt        |      z   dz   t        | j                        v rdt        |      z   d	z   t        | j                        v r| j                  dt        |      z   dz      | j                  dt        |      z   dz   <   | j                  dt        |      z   d	z      | j                  dt        |      z   d	z   <   | j                  j                  dt        |      z   dz          | j                  j                  dt        |      z   d	z          | j                  |   | j                  |<   | j                  |   D ]W  }|d   d
k(  s|dxx   t        dt        |      z   d	z         z  cc<   |d   dk(  r| j                  |   j                  |        n | j                  |   D ]W  }|d   dk(  s|dxx   t        dt        |      z   dz         z  cc<   |d   dk(  r| j                  |   j                  |        n | j                  |t        dt        |      z   dz         d       | j                  |t        dt        |      z   d	z         d
       | j                  j                  |       n-| j                  |   dk(  r| j                  |   | j                  |<   | j                  |   D ]W  }|d   d
k(  s|dxx   t        dt        |      z   d	z         z  cc<   |d   dk(  r| j                  |   j                  |        n | j                  |t        dt        |      z   d	z         d
       | j                  j                  |       nN|t        | j                        v r7| j                  |   | j                  |<   | j                  j                  |       t        | j                        D ]  }| j                  |   d   |d   k(  r|| j                  |   d<   d| j                  || j                  |   d   f<   d| j                  | j                  |   d   |f<   | j                  j                  || j                  |   d   f       | j                  j                  | j                  |   d   |f       | j                  |   d   |d   k(  s|| j                  |   d<   d| j                  | j                  |   d   |f<   d| j                  || j                  |   d   f<   | j                  j                  | j                  |   d   |f       | j                  j                  || j                  |   d   f        y y)a  
        This method changes the label of a node.

        Parameters
        ==========
        label: String or Symbol
            The label of the node for which the label has
            to be changed.

        new_label: String or Symbol
            The new label of the node.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.nodes
        [('A', 0, 0), ('B', 3, 0)]
        >>> t.change_node_label('A', 'C')
        >>> t.nodes
        [('C', 0, 0), ('B', 3, 0)]
        z!No such node exists for the Trussz*A node with the given label already existsr   rA      pinnedR__x_yZ   rollerTN)r   r9   r   r:   r   rG   rF   r   strr   r   r   rE   
apply_loadr   r   )r   r<   	new_labelnodeloadrJ   s         r   change_node_labelzTruss.change_node_label1  sN   4 )))@AA$+++IJJ :X7e#QZ\`ab\ceijkelPmDKK 1 15$q'472K LMJSD%%d&7&7&=&=d1g&FG8<8N8Nu8UD**95**..u5Aw$t~~"6648NN474Ky1**473 D$88>>)4@#CJt3tD<P<P7QQVZ[^_d[eVefjVjnrsw  tH  tH  oI  WIQUQeQefjknotkufuvzfzQ{ 4 4T#i.5H5M NQUQeQefjknotkufuvzfzQ{ 4 4T#i.5H5M N $ 4 4 8 8c%j9M N $ 4 4 8 8c%j9M N59[[5GDKK	2(,I(> *#'7b=$(Gvd3u:od6J/K$KG'+Aw!|(,E(:(A(A$(G$)* )-I(> *#'7a<$(Gvd3u:od6J/K$KG'+Aw!|(,E(:(A(A$(G$)* !OOIvd3y>>QRV>V7WYZ[ OOIvd3y>>QRV>V7WY[\ KKOOE2!^^I6(B59[[5GDKK	2(,E(: *#'7b=$(Gvd3u:od6J/K$KG'+Aw!|(,E(:(A(A$(G$)* !OOIvd3y>>QRV>V7WY[\ KKOOE2 D$5559[[5GDKK	2 KKOOE2"&t}}"5 X==03tAw>7@DMM&1!4Z^D00)T]]6=RST=U1VWZ^D00$--2G2JI1VW 0044eT]]6=RST=U5VW 0044dmmF6KA6NPU5VW!]]6215a@7@DMM&1!4Z^D00$--2G2JI1VWZ^D00)T]]6=RST=U1VW 0044dmmF6KA6NPU5VW 0044eT]]6=RST=U5VWX]:Xr!   c                    |t        | j                        vrt        d      t        | j                        j                         }|D ]  }||k(  s	| j                  |   d   | j                  |   d   g| j                  |<   | j                  j	                  |       | j
                  |   | j
                  |<   | j
                  j	                  |        y)aG  
        This method changes the label of a member.

        Parameters
        ==========
        label: String or Symbol
            The label of the member for which the label has
            to be changed.

        new_label: String or Symbol
            The new label of the member.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.nodes
        [('A', 0, 0), ('B', 3, 0)]
        >>> t.change_node_label('A', 'C')
        >>> t.nodes
        [('C', 0, 0), ('B', 3, 0)]
        >>> t.add_member('BC', 'B', 'C')
        >>> t.members
        {'BC': ['B', 'C']}
        >>> t.change_member_label('BC', 'BC_new')
        >>> t.members
        {'BC_new': ['B', 'C']}
        z#No such member exists for the Trussr   rA   N)rF   r   r9   rD   rG   r   )r   r<   r]   rI   rJ   s        r   change_member_labelzTruss.change_member_label  s    @ T]]++BCC !%T]] 3 8 8 :+ 5U?04f0Ea0H$--X^J_`aJb/cDMM),MM%%e,7;7L7LU7SD)))4))--e45r!   c                     t        |      }t        |      }|| j                  vrt        d      |t        | j                        v r!| j                  |   j                  ||g       y||gg| j                  |<   y)a  
        This method applies an external load at a particular node

        Parameters
        ==========
        location: String or Symbol
            Label of the Node at which load is applied.

        magnitude: Sympifyable
            Magnitude of the load applied. It must always be positive and any changes in
            the direction of the load are not reflected here.

        direction: Sympifyable
            The angle, in degrees, that the load vector makes with the horizontal
            in the counter-clockwise direction. It takes the values 0 to 360,
            inclusive.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> from sympy import symbols
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> P = symbols('P')
        >>> t.apply_load('A', P, 90)
        >>> t.apply_load('A', P/2, 45)
        >>> t.apply_load('A', P/4, 90)
        >>> t.loads
        {'A': [[P, 90], [P/2, 45], [P/4, 90]]}
        z$Load must be applied at a known nodeN)r   r&   r9   rF   r   r;   r   location	magnitude	directions       r   r\   zTruss.apply_load  sx    B I&	I&	4+++CDD 4,,H%,,i-CD*3Y)?(@H%r!   c                 :   t        |      }t        |      }|| j                  vrt        d      ||g| j                  |   vrt        d      | j                  |   j	                  ||g       | j                  |   g k(  r| j                  j                  |       yy)a;  
        This method removes an already
        present external load at a particular node

        Parameters
        ==========
        location: String or Symbol
            Label of the Node at which load is applied and is to be removed.

        magnitude: Sympifyable
            Magnitude of the load applied.

        direction: Sympifyable
            The angle, in degrees, that the load vector makes with the horizontal
            in the counter-clockwise direction. It takes the values 0 to 360,
            inclusive.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> from sympy import symbols
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> P = symbols('P')
        >>> t.apply_load('A', P, 90)
        >>> t.apply_load('A', P/2, 45)
        >>> t.apply_load('A', P/4, 90)
        >>> t.loads
        {'A': [[P, 90], [P/2, 45], [P/4, 90]]}
        >>> t.remove_load('A', P/4, 90)
        >>> t.loads
        {'A': [[P, 90], [P/2, 45]]}
        z&Load must be removed from a known nodezENo load of this magnitude and direction has been applied at this nodeN)r   r&   r9   r   rE   rG   rd   s       r   remove_loadzTruss.remove_load  s    H I&	I&	4+++EFF 9%T[[-BB !hiiH%,,i-CD;;x B&KKOOH% 'r!   c           	         || j                   vrt        d      |t        | j                        vr|dk(  rW| j	                  |t        dt        |      z   dz         d       | j	                  |t        dt        |      z   dz         d       n|dk(  r| j	                  |t        dt        |      z   dz         d       n| j                  |   dk(  r1|dk(  rn| j                  |t        dt        |      z   dz         d       nB| j                  |   dk(  r0|dk(  r+| j	                  |t        dt        |      z   dz         d       || j                  |<   y	)
aH  
        This method adds a pinned or roller support at a particular node

        Parameters
        ==========

        location: String or Symbol
            Label of the Node at which support is added.

        type: String
            Type of the support being provided at the node.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.apply_support('A', 'pinned')
        >>> t.supports
        {'A': 'pinned'}
        z%Support must be added on a known noderU   rV   rW   r   rX   rY   rZ   N)r   r9   rF   r   r\   r   r[   ri   )r   re   types      r   apply_supportzTruss.apply_support  s3   0 4,,,DEE tDNN338#OOHfT#h-5G5L.MqQOOHfT#h-5G5L.MrRX%OOHfT#h-5G5L.MrR)X58#$$Xvd3x=6H6M/NPQR)X58#OOHfT#h-5G5L.MqQ'+DNN8$r!   c           	         || j                   vrt        d      |t        | j                        vrt        d      | j                  |   dk(  rW| j	                  |t        dt        |      z   dz         d       | j	                  |t        dt        |      z   dz         d       n=| j                  |   d	k(  r+| j	                  |t        dt        |      z   dz         d       | j                  j                  |       y
)a4  
        This method removes support from a particular node

        Parameters
        ==========

        location: String or Symbol
            Label of the Node at which support is to be removed.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node('A', 0, 0)
        >>> t.add_node('B', 3, 0)
        >>> t.apply_support('A', 'pinned')
        >>> t.supports
        {'A': 'pinned'}
        >>> t.remove_support('A')
        >>> t.supports
        {}
        z No such node exists in the Trussz+No support has been added to the given noderU   rV   rW   r   rX   rY   rZ   N)r   r9   rF   r   ri   r   r[   rG   )r   re   s     r   remove_supportzTruss.remove_supportA  s    0 4,,,?@@T$..11JKK ~~h'83  6$s8}2DT2I+JAN  6$s8}2DT2I+JBO)X5  6$s8}2DT2I+JBONNx(r!   c                    d}| j                   D ]S  }|d   t        | j                        v s| j                  |d      dk(  r|dz  }9| j                  |d      dk(  sO|dz  }U dt        | j                         z  t        | j                        |z   k7  rt        d      t        dt        | j                         z        D cg c]1  }t        dt        | j                         z        D cg c]  }d c}3 }}}t        dt        | j                        z  d      }d}| j                   D ]  }|d   t        | j                        v r| j                  |d      D ]  }|d   t        dt        |d         z   dz         k7  s'|d   t        dt        |d         z   d	z         k7  sK||xx   |d   t        t        |d   z  d
z        z  z  cc<   ||dz   xx   |d   t        t        |d   z  d
z        z  z  cc<    |dz  } d}	d}
| j                   D ]  }|d   t        | j                        v rn| j                  |d      dk(  r,||
   |	xx   dz  cc<   ||
dz      |	dz   xx   dz  cc<   |	dz  }	n-| j                  |d      dk(  r||
dz      |	xx   dz  cc<   |	dz  }	|
dz  }
 t        | j                        D ]  }| j                  |   d   }| j                  |   d   }t        | j                   |   d   | j                   |   d   z
  dz  | j                   |   d   | j                   |   d   z
  dz  z         }| j"                  j%                  |      }| j"                  j%                  |      }| j                   |   d   | j                   |   d   z
  |z  }| j                   |   d   | j                   |   d   z
  |z  }| j                   |   d   | j                   |   d   z
  |z  }| j                   |   d   | j                   |   d   z
  |z  }||dz     |	xx   |z  cc<   ||dz  dz      |	xx   |z  cc<   ||dz     |	xx   |z  cc<   ||dz  dz      |	xx   |z  cc<   |	dz  }	 t'        |      dz  |z  }i | _        d}t*        }| j                   D ]c  }|d   t        | j                        v s| j                  |d      D ]1  }t-        |d         t        t.        t0        fvs#t3        ||d         }3 e t        t        |            D ]<  }t-        ||         t        t.        t0        fvs#t5        ||   |z        dk  s8d||<   > | j                   D ]  }|d   t        | j                        v s| j                  |d      dk(  rQ||   | j(                  dt        |d         z   dz   <   ||dz      | j(                  dt        |d         z   d	z   <   |dz  }| j                  |d      dk(  s||   | j(                  dt        |d         z   d	z   <   |dz  } t        | j                        D ]  }||   | j6                  |<   |dz  } yc c}w c c}}w )a	  
        This method solves for all reaction forces of all supports and all internal forces
        of all the members in the truss, provided the Truss is solvable.

        A Truss is solvable if the following condition is met,

        2n >= r + m

        Where n is the number of nodes, r is the number of reaction forces, where each pinned
        support has 2 reaction forces and each roller has 1, and m is the number of members.

        The given condition is derived from the fact that a system of equations is solvable
        only when the number of variables is lesser than or equal to the number of equations.
        Equilibrium Equations in x and y directions give two equations per node giving 2n number
        equations. However, the truss needs to be stable as well and may be unstable if 2n > r + m.
        The number of variables is simply the sum of the number of reaction forces and member
        forces.

        .. note::
           The sign convention for the internal forces present in a member revolves around whether each
           force is compressive or tensile. While forming equations for each node, internal force due
           to a member on the node is assumed to be away from the node i.e. each force is assumed to
           be compressive by default. Hence, a positive value for an internal force implies the
           presence of compressive force in the member and a negative value implies a tensile force.

        Examples
        ========

        >>> from sympy.physics.continuum_mechanics.truss import Truss
        >>> t = Truss()
        >>> t.add_node("node_1", 0, 0)
        >>> t.add_node("node_2", 6, 0)
        >>> t.add_node("node_3", 2, 2)
        >>> t.add_node("node_4", 2, 0)
        >>> t.add_member("member_1", "node_1", "node_4")
        >>> t.add_member("member_2", "node_2", "node_4")
        >>> t.add_member("member_3", "node_1", "node_3")
        >>> t.add_member("member_4", "node_2", "node_3")
        >>> t.add_member("member_5", "node_3", "node_4")
        >>> t.apply_load("node_4", magnitude=10, direction=270)
        >>> t.apply_support("node_1", type="pinned")
        >>> t.apply_support("node_2", type="roller")
        >>> t.solve()
        >>> t.reaction_loads
        {'R_node_1_x': 0, 'R_node_1_y': 20/3, 'R_node_2_y': 10/3}
        >>> t.internal_forces
        {'member_1': 20/3, 'member_2': 20/3, 'member_3': -20*sqrt(2)/3, 'member_4': -10*sqrt(5)/3, 'member_5': 10}
        r   rU   rT   rZ   rA   z The given truss cannot be solvedrV   rW   rX      g|=N)r   rF   r   rC   r   r9   rB   r   r#   r   r   r[   r   r	   r   r
   r   r   r:   r   r   r   rk   r   r   minabsr   )r   count_reaction_loadsr^   jrH   coefficients_matrixload_matrixload_matrix_rowr_   colsrowrJ   rN   rO   lengthstart_index	end_indexhorizontal_component_startvertical_component_starthorizontal_component_endvertical_component_endforces_matrixmin_loads                          r   solvezTruss.solveg  s3   b  !KK 	.DAw$t~~..>>$q'*H4(A-(^^DG,h6(A-(	. ST]]!36J!JJ?@@OTUVWZ[_[f[fWgUgOhi!53t{{3C1C+DEaEiiAc$**o-q1KK 	!DAw$t{{++ KKQ0 XDAwtCQL'8'= >>47FSWX[\`ab\cXdSdeiSiLjCj#O4QBtAwJsN@S8SS4#Oa$78DGC4PQ7
SVDW<WW8X q O	! KK 		DAw$t~~..>>$q'*H4',T2a72'A.tAv6!;6AID^^DG,h6'A.t494AID1HC		 4==) 	FMM&)!,E--'*C411%8;D<R<RSV<WXY<ZZ]^^bfbxbxy~b  AB  cC  DH  DZ  DZ  [^  D_  `a  Db  cb  ef  bf  f  gF++11%8K))//4I*.*@*@*Ea*HI_I_`eIfghIi*ikq)q&(,(>(>s(CA(FtG]G]^cGdefGg(gio'o$(,(>(>u(Ea(HI_I_`cIdefIg(gio'o$&*&<&<U&CA&FtG]G]^aGbcdGe&egm%m"A.t48RR4Aa06:RR6	!,T26NN2	!A.t48NN4AID	   34b8+E!KK 	:DAw$t{{++ KKQ0 :DDG}VS#,>>#&xa#9:	:
 s=)* 	)AM!$%fc3-??}Q'0158'(M!$	) KK 	DAw$t~~..>>$q'*H4CPQRCSD((c$q'l):4)?@CPQRSTQTCUD((c$q'l):4)?@FA^^DG,h6CPQRCSD((c$q'l):4)?@FA	 4==) 	F,9!,<D!!&)FA	 	}  Fis   (Y-	Y6YYN)__name__
__module____qualname____doc__r    propertyr#   r&   r(   r,   r/   r1   r3   r5   r7   r?   rK   rP   rR   r`   rb   r\   ri   rl   rn   r    r!   r   r   r      s   !F$"   ! ! $ $   # #     $ $ % %*3X..`)-V!-FYXv*5X+AZ0&d(,T$)Lxr!   r   N)r   cmathr   sympy.core.addr   sympy.core.mulr   sympy.core.symbolr   sympy.core.sympifyr   sympyr   r	   (sympy.functions.elementary.miscellaneousr
   sympy.matrices.denser   r   r   r   r   r!   r   <module>r      s3   
    $ &  9 & M Mr!   