
    \hN                         S SK JrJrJrJrJr  S SKJr  S SKJ	r	J
r
  S SKJr  S SKJrJrJrJr  S SKJr  S SKJr  S/r " S	 S\5      rg
)    )diffzerosMatrixeyesympify)default_sort_key)dynamicsymbolsReferenceFrame)_Methods)find_dynamicsymbolsmsubs_f_list_parser_validate_coordinates)
Linearizer)iterableLagrangesMethodc                       \ rS rSrSr  SS jrS rS r\S 5       r	\S 5       r
\S	 5       r\S
 5       r  SS jr  SS jrSS jrSS jr\S 5       r\S 5       r\S 5       r\S 5       r\S 5       rSrg)r      as  Lagrange's method object.

Explanation
===========

This object generates the equations of motion in a two step procedure. The
first step involves the initialization of LagrangesMethod by supplying the
Lagrangian and the generalized coordinates, at the bare minimum. If there
are any constraint equations, they can be supplied as keyword arguments.
The Lagrange multipliers are automatically generated and are equal in
number to the constraint equations. Similarly any non-conservative forces
can be supplied in an iterable (as described below and also shown in the
example) along with a ReferenceFrame. This is also discussed further in the
__init__ method.

Attributes
==========

q, u : Matrix
    Matrices of the generalized coordinates and speeds
loads : iterable
    Iterable of (Point, vector) or (ReferenceFrame, vector) tuples
    describing the forces on the system.
bodies : iterable
    Iterable containing the rigid bodies and particles of the system.
mass_matrix : Matrix
    The system's mass matrix
forcing : Matrix
    The system's forcing vector
mass_matrix_full : Matrix
    The "mass matrix" for the qdot's, qdoubledot's, and the
    lagrange multipliers (lam)
forcing_full : Matrix
    The forcing vector for the qdot's, qdoubledot's and
    lagrange multipliers (lam)

Examples
========

This is a simple example for a one degree of freedom translational
spring-mass-damper.

In this example, we first need to do the kinematics.
This involves creating generalized coordinates and their derivatives.
Then we create a point and set its velocity in a frame.

    >>> from sympy.physics.mechanics import LagrangesMethod, Lagrangian
    >>> from sympy.physics.mechanics import ReferenceFrame, Particle, Point
    >>> from sympy.physics.mechanics import dynamicsymbols
    >>> from sympy import symbols
    >>> q = dynamicsymbols('q')
    >>> qd = dynamicsymbols('q', 1)
    >>> m, k, b = symbols('m k b')
    >>> N = ReferenceFrame('N')
    >>> P = Point('P')
    >>> P.set_vel(N, qd * N.x)

We need to then prepare the information as required by LagrangesMethod to
generate equations of motion.
First we create the Particle, which has a point attached to it.
Following this the lagrangian is created from the kinetic and potential
energies.
Then, an iterable of nonconservative forces/torques must be constructed,
where each item is a (Point, Vector) or (ReferenceFrame, Vector) tuple,
with the Vectors representing the nonconservative forces or torques.

    >>> Pa = Particle('Pa', P, m)
    >>> Pa.potential_energy = k * q**2 / 2.0
    >>> L = Lagrangian(N, Pa)
    >>> fl = [(P, -b * qd * N.x)]

Finally we can generate the equations of motion.
First we create the LagrangesMethod object. To do this one must supply
the Lagrangian, and the generalized coordinates. The constraint equations,
the forcelist, and the inertial frame may also be provided, if relevant.
Next we generate Lagrange's equations of motion, such that:
Lagrange's equations of motion = 0.
We have the equations of motion at this point.

    >>> l = LagrangesMethod(L, [q], forcelist = fl, frame = N)
    >>> print(l.form_lagranges_equations())
    Matrix([[b*Derivative(q(t), t) + 1.0*k*q(t) + m*Derivative(q(t), (t, 2))]])

We can also solve for the states using the 'rhs' method.

    >>> print(l.rhs())
    Matrix([[Derivative(q(t), t)], [(-b*Derivative(q(t), t) - 1.0*k*q(t))/m]])

Please refer to the docstrings on each method for more details.
Nc                    [        [        U5      /5      U l        SU l        [        5       U l        [        5       U l        [        5       U l        [        5       U l        [        5       U l        U(       a  UO/ n[        U5      (       d  [        S5      eX0l        U(       a   [        U[        5      (       d  [        S5      eX@l        XPl        [        5       U l        [        5       U l        [        5       U l        [        5       U l        [        5       U l        [        U5      (       d  [        S5      e[        U5      U l        U R,                  R/                  [0        R2                  5      U l        U R4                  R/                  [0        R2                  5      U l        [9        U R,                  5        S nU" U5      nU" U5      n[        UR/                  [0        R2                  5      U/5      U l        X`l        g)a2  Supply the following for the initialization of LagrangesMethod.

Lagrangian : Sympifyable

qs : array_like
    The generalized coordinates

hol_coneqs : array_like, optional
    The holonomic constraint equations

nonhol_coneqs : array_like, optional
    The nonholonomic constraint equations

forcelist : iterable, optional
    Takes an iterable of (Point, Vector) or (ReferenceFrame, Vector)
    tuples which represent the force at a point or torque on a frame.
    This feature is primarily to account for the nonconservative forces
    and/or moments.

bodies : iterable, optional
    Takes an iterable containing the rigid bodies and particles of the
    system.

frame : ReferenceFrame, optional
    Supply the inertial frame. This is used to determine the
    generalized forces due to non-conservative forces.
Nz,Force pairs must be supplied in an iterable.z$frame must be a valid ReferenceFramez+Generalized coordinates must be an iterablec                 :    U (       a  [        U 5      $ [        5       $ Nr   xs    X/var/www/auris/envauris/lib/python3.13/site-packages/sympy/physics/mechanics/lagrange.py<lambda>*LagrangesMethod.__init__.<locals>.<lambda>       1fQi:&(:    )r   r   _Leom_m_cd_m_d_f_cd_f_d
lam_coeffsr   	TypeError
_forcelist
isinstancer
   _bodiesinertiallam_vec_term1_term2_term3_term4_qqr   r	   _t_qdots_qdoubledotsr   coneqs_hol_coneqs)	self
Lagrangianqs	forcelistbodiesframe
hol_coneqsnonhol_coneqs	mat_builds	            r   __init__LagrangesMethod.__init__i   sl   < '*-./X
H	X
H	 (!*I		""JKK#E>::BCCxhhhh ||IJJ*ffkk."3"34 KK,,^->->?dff%:	z*
!-0joon.?.?@  %r   c           	        ^
^ U R                   n[        R                  U R                  S5      n[	        U R
                  5      nU R                  R                  U5      U l        U R                  R                  [        R                  5      R                  U l        U R                  R                  U R
                  5      R                  U l        U R                  (       a  U R                  n[	        U5      n[        [        S[!        US-   5      -   5      5      U l        UR                  U5      * U l        U R$                  R                  U R"                  -  U l        UR                  [        R                  5      nUR                  U R                  5      U l        UR+                  U5      * U l        O[/        US5      U l        U R0                  (       ar  U R2                  m
[/        US5      U l        [7        U5       HE  u  nm[9        [;        U R0                  T
5      6 n[=        U
U4S jU 5       5      U R4                  U'   MG     O[/        US5      U l        U R                  U R                  -
  U R4                  -
  n	U	R                  U R                  5      U l        U	R+                  U5      * U l         XR&                  -
  U l!        U RB                  $ )zMethod to form Lagrange's equations of motion.

Returns a vector of equations of motion using Lagrange's equations of
the second kind.
r   zlam1:   c              3   j   >#    U  H(  u  pUR                  TT5      R                  U5      v   M*     g 7fr   )r   dot).0vfNqds      r   	<genexpr>;LagrangesMethod.form_lagranges_equations.<locals>.<genexpr>   s+     $NfqQVVB]%6%6q%9%9s   03)"r4   dictfromkeysr5   lenr2   r    jacobianr-   r   r	   r3   Tr.   r6   r   strr,   r&   r/   r"   subsr$   r   r;   r+   r0   	enumeratezipr   sumr#   r%   r!   )r8   qdsqdd_zeronr6   m
diffconeqsiflistwithout_lamrJ   rK   s             @@r   form_lagranges_equations(LagrangesMethod.form_lagranges_equations   s    kk==!2!2A6K gg&&s+kk&&~'8'89;; gg&&tvv.00 ;;[[FFA!.3q1u:1E"FGDL%s33DO//++dll:DK^%6%67J#,,T->->?DJ$//(33DJ1+DK >>A1+DK"32^DNNA>?!$$N$N!NA (  1+DK kkDKK/$++=(():):;	 %%h//	 ,xxr   c                 "    U R                  5       $ r   )r`   r8   s    r   
_form_eomsLagrangesMethod._form_eoms   s    ,,..r   c                     U R                   c  [        S5      eU R                  (       a/  U R                  R	                  U R
                  R                  5      $ U R                  $ )a  Returns the mass matrix, which is augmented by the Lagrange
multipliers, if necessary.

Explanation
===========

If the system is described by 'n' generalized coordinates and there are
no constraint equations then an n X n matrix is returned.

If there are 'n' generalized coordinates and 'm' constraint equations
have been supplied during initialization then an n X (n+m) matrix is
returned. The (n + m - 1)th and (n + m)th columns contain the
coefficients of the Lagrange multipliers.
-Need to compute the equations of motion first)r!   
ValueErrorr6   r#   row_joinr&   rR   rc   s    r   mass_matrixLagrangesMethod.mass_matrix   sJ    " 88LMM;;II''(9(9::99r   c                    U R                   c  [        S5      e[        U R                  5      n[        U R                  5      n[        U5      R                  [        XU-   5      5      n[        X5      R                  U R                  5      nU R                  (       a\  [        X!5      R                  U R                  5      R                  [        X"5      5      nUR                  U5      R                  U5      $ UR                  U5      $ )z6Augments the coefficients of qdots to the mass_matrix.rg   )r!   rh   rP   r2   r6   r   ri   r   rj   r"   col_join)r8   rZ   r[   row1row2row3s         r   mass_matrix_full LagrangesMethod.mass_matrix_full  s     88LMMK1vuQA/Q{##D$4$45;;;''

3<<U1[ID==&//55==&&r   c                 J    U R                   c  [        S5      eU R                  $ )z=Returns the forcing vector from 'lagranges_equations' method.rg   )r!   rh   r%   rc   s    r   forcingLagrangesMethod.forcing  s$     88LMMyyr   c                    U R                   c  [        S5      eU R                  (       a>  U R                  R	                  U R
                  5      R	                  U R                  5      $ U R                  R	                  U R
                  5      $ )z+Augments qdots to the forcing vector above.rg   )r!   rh   r6   r4   rm   rt   r$   rc   s    r   forcing_fullLagrangesMethod.forcing_full  sb     88LMM;;;;''5>>tzzJJ;;''55r   c                    [         R                  nU R                  nU R                  nUR	                  U5      n	U R
                  n
S nU" U5      nU" U5      nU" U5      nU" U5      nU R                  nU R                  nUR	                  U5      nUnU* nU R                  nU R                  U R                  -   * nU R                  * n[        U5      [        U5      :w  d  [        U5      [        U5      :w  a-  [        SR                  [        U5      [        U5      5      5      e[        [!        X/5      5      [        U5      :w  a  [        S5      e[        [!        X/5      5      [        U5      :w  a  [        S5      e[        [!        XxX/5      5      n[#        [%        UU5      5      nUR'                  [(        S9  U H,  n[	        U[         R                  5      U;   d  M#  [        S5      e   [+        UUUUUUUUXxUXUUXS9$ )a  Returns an instance of the Linearizer class, initiated from the data
in the LagrangesMethod class. This may be more desirable than using the
linearize class method, as the Linearizer object will allow more
efficient recalculation (i.e. about varying operating points).

Parameters
==========

q_ind, qd_ind : array_like, optional
    The independent generalized coordinates and speeds.
q_dep, qd_dep : array_like, optional
    The dependent generalized coordinates and speeds.
linear_solver : str, callable
    Method used to solve the several symbolic linear systems of the
    form ``A*x=b`` in the linearization process. If a string is
    supplied, it should be a valid method that can be used with the
    :meth:`sympy.matrices.matrixbase.MatrixBase.solve`. If a callable is
    supplied, it should have the format ``x = f(A, b)``, where it
    solves the equations and returns the solution. The default is
    ``'LU'`` which corresponds to SymPy's ``A.LUsolve(b)``.
    ``LUsolve()`` is fast to compute but will often result in
    divide-by-zero and thus ``nan`` results.

Returns
=======
Linearizer
    An instantiated
    :class:`sympy.physics.mechanics.linearize.Linearizer`.

c                 :    U (       a  [        U 5      $ [        5       $ r   r   r   s    r   r   /LagrangesMethod.to_linearizer.<locals>.<lambda>M  r   r   z?Must supply {:} dependent coordinates, and {:} dependent speedszHMust partition q into q_ind and q_dep, with no extra or missing symbols.zKMust partition qd into qd_ind and qd_dep, with no extra or missing symbols.)keyzpCannot have derivatives of specified                                  quantities when linearizing forcing terms.linear_solver)r	   r3   r2   r4   r   r,   r7   r6   r-   r.   r0   r/   rP   rh   formatsetr   listr   sortr   r   )r8   q_indqd_indq_depqd_depr~   tr2   uudlamsr@   q_iq_du_iu_df_cf_vf_af_0f_1f_2f_3f_4insymsrr]   s                              r   to_linearizerLagrangesMethod.to_linearizer$  s   D FFKKVVAY||:	 kkhhqkbkkdkk)*{{l s8s3x3s8s3x#7 +,2F3s8SX,FH Hvsj!"c!f, 3 4 4vsj!"c!f, 8 9 9
 VQ2,-.$S&12	#$AA~(()Q.  "M N N 
 #sCc3S!CDO 	Or   c                 f    U R                  XX4US9nUR                  " S0 UD6nXR                  4-   $ )ag  Linearize the equations of motion about a symbolic operating point.

Parameters
==========
linear_solver : str, callable
    Method used to solve the several symbolic linear systems of the
    form ``A*x=b`` in the linearization process. If a string is
    supplied, it should be a valid method that can be used with the
    :meth:`sympy.matrices.matrixbase.MatrixBase.solve`. If a callable is
    supplied, it should have the format ``x = f(A, b)``, where it
    solves the equations and returns the solution. The default is
    ``'LU'`` which corresponds to SymPy's ``A.LUsolve(b)``.
    ``LUsolve()`` is fast to compute but will often result in
    divide-by-zero and thus ``nan`` results.
**kwargs
    Extra keyword arguments are passed to
    :meth:`sympy.physics.mechanics.linearize.Linearizer.linearize`.

Explanation
===========

If kwarg A_and_B is False (default), returns M, A, B, r for the
linearized form, M*[q', u']^T = A*[q_ind, u_ind]^T + B*r.

If kwarg A_and_B is True, returns A, B, r for the linearized form
dx = A*x + B*r, where x = [q_ind, u_ind]^T. Note that this is
computationally intensive if there are many symbolic parameters. For
this reason, it may be more desirable to use the default A_and_B=False,
returning M, A, and B. Values may then be substituted in to these
matrices, and the state space form found as
A = P.T*M.inv()*A, B = P.T*M.inv()*B, where P = Linearizer.perm_mat.

In both cases, r is found as all dynamicsymbols in the equations of
motion that are not part of q, u, q', or u'. They are sorted in
canonical form.

The operating points may be also entered using the ``op_point`` kwarg.
This takes a dictionary of {symbol: value}, or a an iterable of such
dictionaries. The values may be numeric or symbolic. The more values
you can specify beforehand, the faster this computation will run.

For more documentation, please see the ``Linearizer`` class.r}    )r   	linearizer   )	r8   r   r   r   r   r~   kwargs
linearizerresults	            r   r   LagrangesMethod.linearizew  sD    Z ''u6C ( E
%%//''r   c                    [        U R                  5      nUS:X  a  [        S5      e[        U[        5      (       a  UnO>[        U5      (       a  0 nU H  nUR                  U5        M     OUc  0 nO[        S5      eU R                  R                  U R                  R                  [        X35      5      * 5      nU R                  R                  U R                  5      n[        Xd5      n[        Xt5      nUR!                  U* 5      U* S nUS:X  a  [	        [#        U R                  U5      5      $ US:X  a  [%        U5      $ [        SR'                  U5      5      e)a  Solves for the values of the lagrange multipliers symbolically at
the specified operating point.

Parameters
==========

op_point : dict or iterable of dicts, optional
    Point at which to solve at. The operating point is specified as
    a dictionary or iterable of dictionaries of {symbol: value}. The
    value may be numeric or symbolic itself.

sol_type : str, optional
    Solution return type. Valid options are:
    - 'dict': A dict of {symbol : value} (default)
    - 'Matrix': An ordered column matrix of the solution
r   z0System has no lagrange multipliers to solve for.NzDop_point must be either a dictionary or an iterable of dictionaries.rN   r   zUnknown sol_type {:}.)rP   r,   rh   r)   rN   r   updater'   rj   rm   r&   ri   r   rt   r$   r   LUsolverV   r   r   )	r8   op_pointsol_typekop_point_dictoprj   force_matrixsol_lists	            r   solve_multipliers!LagrangesMethod.solve_multipliers  s@   & 6OPPh%%$MhM$$R( M 8 9 9 &&//1I1Ia2 1 ||,,TZZ8K7\9&&}5qbc:vDLL(344!(##4;;HEFFr   c                     Uc6  U R                   R                  U R                  5      U l        U R                  $ U R                   R	                  USS9U R                  -  U l        U R                  $ )zReturns equations that can be solved numerically.

Parameters
==========

inv_method : str
    The specific sympy inverse matrix calculation method to use. For a
    list of valid methods, see
    :meth:`~sympy.matrices.matrixbase.MatrixBase.inv`
T)try_block_diag)rq   r   rw   _rhsinv)r8   
inv_methodr   s      r   rhsLagrangesMethod.rhs  sq     --55d6G6GHDI yy ..22:(, 3 .040A0ABDIyyr   c                     U R                   $ r   )r1   rc   s    r   r2   LagrangesMethod.q  s    wwr   c                     U R                   $ r   )r4   rc   s    r   r   LagrangesMethod.u  s    {{r   c                     U R                   $ r   )r*   rc   s    r   r<   LagrangesMethod.bodies  s    ||r   c                     U R                   $ r   r(   rc   s    r   r;   LagrangesMethod.forcelist      r   c                     U R                   $ r   r   rc   s    r   loadsLagrangesMethod.loads  r   r   )r    r*   r$   r%   r(   r7   r"   r#   r1   r4   r5   r   r-   r.   r/   r0   r6   r!   r+   r&   r,   )NNNNN)NNNNLU)NrN   r   )__name__
__module____qualname____firstlineno____doc__rA   r`   rd   propertyrj   rq   rt   rw   r   r   r   r   r2   r   r<   r;   r   __static_attributes__r   r   r   r   r      s   Yv KO04C&J6p/  . ' '   6 6 IM$(QOf EI $0(d0Gd&          r   N)sympyr   r   r   r   r   sympy.core.sortingr   sympy.physics.vectorr	   r
   sympy.physics.mechanics.methodr   !sympy.physics.mechanics.functionsr   r   r   r   !sympy.physics.mechanics.linearizer   sympy.utilities.iterablesr   __all__r   r   r   r   <module>r      s<    3 3 / ? 3G G 8 .
sh sr   