B
    [                 @   s   d Z ddlmZ ddlmZ ddlmZmZmZm	Z	m
Z
mZmZ ddlmZmZmZ ddlmZmZ ddlmZ ddlmZ dd	lmZ d
d Zdd Zdd Zdd Zdd ZdS )zA
Several methods to simplify expressions involving unit objects.
    )division)SymPyDeprecationWarning)AddFunctionMulPowRationalTuplesympify)reduceIterableordered)	Dimensiondimsys_default)Quantity)Prefix)siftc             C   s&   t ddddd  t| \}} | S )a  
    NOTE: this function could be deprecated in the future.

    Simplify expression by recursively evaluating the dimension arguments.

    This function proceeds to a very rough dimensional analysis. It tries to
    simplify expression with dimensions, and it deletes all what multiplies a
    dimension without being a dimension. This is necessary to avoid strange
    behavior when Add(L, L) be transformed into Mul(2, L).
    z1.2z#dimensional simplification functioni4  z	don't use)Zdeprecated_since_versionZfeatureZissueZ
useinstead)r   warnr   Z_collect_factor_and_dimension)expr_ r   7lib/python3.7/site-packages/sympy/physics/units/util.pydim_simplify   s    r   c       	         s   ddl m} tt| }tj|dd dd |D dd D }d	d  D }||s`d S t|}|fd
d|D }| fdd|D }|j	|d d}|S )Nr   )MatrixT)mark_dimensionlessc             S   s   g | ]}t t|qS r   )r   r   get_dimensional_expr).0xr   r   r   
<listcomp>-   s    z3_get_conversion_matrix_for_expr.<locals>.<listcomp>c             S   s$   h | ]}t j|d dD ]}|qqS )T)r   )r   get_dimensional_dependencies)r   r   ir   r   r   	<setcomp>.   s    z2_get_conversion_matrix_for_expr.<locals>.<setcomp>c             S   s   h | ]}|qS r   r   )r   r    r   r   r   r!   /   s    c                s   g | ]  fd dD qS )c                s"   g | ]}t j|d d dqS )T)r   r   )r   r   get)r   r    )jr   r   r   6   s    z>_get_conversion_matrix_for_expr.<locals>.<listcomp>.<listcomp>r   )r   )target_dims)r#   r   r   6   s    c                s   g | ]}  |d qS )r   )r"   )r   k)dim_dependenciesr   r   r   7   s    )method)
sympyr   r   r   r   r   r   issubsetsortedZsolve_least_squares)	r   target_unitsr   Zexpr_dimZcanon_dim_unitsZcanon_expr_unitsZcamatZexprmatZres_exponentsr   )r&   r$   r   _get_conversion_matrix_for_expr(   s    
r,   c                s   t ttfsgt | tr8tfdd| jD S t| } t | tsl| trl| 	dd fdd}  fdd t
| }|dkr| S  | }|t fd	dt|D  S )
a  
    Convert ``expr`` to the same expression with all of its units and quantities
    represented as factors of ``target_units``, whenever the dimension is compatible.

    ``target_units`` may be a single unit/quantity, or a collection of
    units/quantities.

    Examples
    ========

    >>> from sympy.physics.units import speed_of_light, meter, gram, second, day
    >>> from sympy.physics.units import mile, newton, kilogram, atomic_mass_constant
    >>> from sympy.physics.units import kilometer, centimeter
    >>> from sympy.physics.units import convert_to
    >>> convert_to(mile, kilometer)
    25146*kilometer/15625
    >>> convert_to(mile, kilometer).n()
    1.609344*kilometer
    >>> convert_to(speed_of_light, meter/second)
    299792458*meter/second
    >>> convert_to(day, second)
    86400*second
    >>> 3*newton
    3*newton
    >>> convert_to(3*newton, kilogram*meter/second**2)
    3*kilogram*meter/second**2
    >>> convert_to(atomic_mass_constant, gram)
    1.66053904e-24*gram

    Conversion to multiple units:

    >>> convert_to(speed_of_light, [meter, second])
    299792458*meter/second
    >>> convert_to(3*newton, [centimeter, gram, second])
    300000*centimeter*gram/second**2

    Conversion to Planck units:

    >>> from sympy.physics.units import gravitational_constant, hbar
    >>> convert_to(atomic_mass_constant, [gravitational_constant, speed_of_light, hbar]).n()
    7.62950196312651e-20*gravitational_constant**(-0.5)*hbar**0.5*speed_of_light**0.5

    c             3   s   | ]}t | V  qd S )N)
convert_to)r   r    )r+   r   r   	<genexpr>m   s    zconvert_to.<locals>.<genexpr>c             S   s
   t | tS )N)
isinstancer   )r   r   r   r   <lambda>r   s    zconvert_to.<locals>.<lambda>c                s
   |   S )N)r-   )r   )r+   r   r   r0   r   s    c                sV   t | tr(tdd  fdd| jD S t | trB | j| j S t | trR| jS | S )Nc             S   s   | | S )Nr   )r   yr   r   r   r0   v   s    z<convert_to.<locals>.get_total_scale_factor.<locals>.<lambda>c                s   g | ]} |qS r   r   )r   r    )get_total_scale_factorr   r   r   v   s    z>convert_to.<locals>.get_total_scale_factor.<locals>.<listcomp>)	r/   r   r   argsr   baseZexpr   scale_factor)r   )r2   r   r   r2   t   s    


z*convert_to.<locals>.get_total_scale_factorNc             3   s&   | ]\}}d  | | | V  qdS )   Nr   )r   up)r2   r   r   r.      s    )r/   r   r	   r   Zfromiterr3   r
   r   hasreplacer,   r   zip)r   r+   ZdepmatZexpr_scale_factorr   )r2   r+   r   r-   =   s    ,
	
r-   c                s   | j s| tts| S | t}| dd |D } t| tdd }x`|D ]X}t|| dkrdqNtt	|| }|d |d j
  |  fdd|dd D } qNW | S )	a  Return an equivalent expression in which prefixes are replaced
    with numerical values and all units of a given dimension are the
    unified in a canonical manner.

    Examples
    ========

    >>> from sympy.physics.units.util import quantity_simplify
    >>> from sympy.physics.units.prefixes import kilo
    >>> from sympy.physics.units import foot, inch
    >>> quantity_simplify(kilo*foot*inch)
    250*foot**2/3
    >>> quantity_simplify(foot - 6*inch)
    foot/2
    c             S   s   i | ]}|j |qS r   )r5   )r   r8   r   r   r   
<dictcomp>   s    z%quantity_simplify.<locals>.<dictcomp>c             S   s   | j S )N)Z	dimension)r    r   r   r   r0      s    z#quantity_simplify.<locals>.<lambda>r6   r   c                s   i | ]} |j  |qS r   )r5   )r   Zvi)refr   r   r<      s    N)Zis_Atomr9   r   r   atomsxreplacer   lenlistr   r5   )r   r8   dr%   vr   )r=   r   quantity_simplify   s    

$rD   c             C   s*  ddl m} | t}tj}x|D ]}t }x|jD ]}|jrJ|	d q4g }d}xTt
|D ]F}	|	trztt|	}	|	tr|||	  q^|	jr^d}P q^W |s4|	tt| t|dkr4tdq4W q"W i }
x@| t
D ]2}tdd	 |jD r|jd
d |jD  |
|< qW | |
S )zjReturn expr if there are not unitless values added to
    dimensional quantities, else raise a ValueError.r   )_term_factorsr   FTr6   z$addends have incompatible dimensionsc             s   s   | ]}t |tV  qd S )N)r/   r   )r   r    r   r   r   r.      s    z#check_dimensions.<locals>.<genexpr>c             S   s   g | ]}|j s|qS r   )	is_number)r   r    r   r   r   r      s    z$check_dimensions.<locals>.<listcomp>)Zsympy.solvers.solvesetrE   r>   r   r   r   setr3   rF   addr   Z	make_argsr9   r   r   r   extenditemsZfree_symbolstupler*   r@   
ValueErroranyfuncr?   )r   rE   ZaddsZDIM_OFaZdesetZaiZdimsskipr    Zrepsmr   r   r   check_dimensions   s<    




rR   N)__doc__Z
__future__r   Zsympy.utilities.exceptionsr   r(   r   r   r   r   r   r	   r
   Zsympy.core.compatibilityr   r   r   Zsympy.physics.units.dimensionsr   r   Zsympy.physics.units.quantitiesr   Zsympy.physics.units.prefixesr   Zsympy.utilities.iterablesr   r   r,   r-   rD   rR   r   r   r   r   <module>   s   $H%