コード例 #1
0
ファイル: test_util.py プロジェクト: Lenqth/sympy
def test_quantity_simplify():
    from sympy.physics.units.util import quantity_simplify
    from sympy.physics.units import kilo, foot
    from sympy.core.symbol import symbols

    x, y = symbols('x y')

    assert quantity_simplify(x*(8*kilo*newton*meter + y)) == x*(8000*meter*newton + y)
    assert quantity_simplify(foot*inch*(foot + inch)) == foot**2*(foot + foot/12)/12
    assert quantity_simplify(foot*inch*(foot*foot + inch*(foot + inch))) == foot**2*(foot**2 + foot/12*(foot + foot/12))/12
    assert quantity_simplify(2**(foot/inch*kilo/1000)*inch) == 4096*foot/12
    assert quantity_simplify(foot**2*inch + inch**2*foot) == 13*foot**3/144
コード例 #2
0
ファイル: test_util.py プロジェクト: vikash-sharma-190/sympy
def test_quantity_simplify():
    from sympy.physics.units.util import quantity_simplify
    from sympy.physics.units import kilo, foot
    from sympy.core.symbol import symbols

    x, y = symbols('x y')

    assert quantity_simplify(x*(8*kilo*newton*meter + y)) == x*(8000*meter*newton + y)
    assert quantity_simplify(foot*inch*(foot + inch)) == foot**2*(foot + foot/12)/12
    assert quantity_simplify(foot*inch*(foot*foot + inch*(foot + inch))) == foot**2*(foot**2 + foot/12*(foot + foot/12))/12
    assert quantity_simplify(2**(foot/inch*kilo/1000)*inch) == 4096*foot/12
    assert quantity_simplify(foot**2*inch + inch**2*foot) == 13*foot**3/144
コード例 #3
0
def parseUnits(text, dimension=None):
    """Parse a string with units possibly included.
    See parseExpr for pre-processing steps.

    Raises ExpressionError same as parseExpr.
    Raises UnitMisMatchError if the expression has incompatible units.

    :param text: str
    :return: sympy.Expr or None
    """
    logger.log(logging.DEBUG - 1, f'parseUnits({text})')

    if text == '':
        return None
    text = text.replace('^', '**')
    err = _notSafeError(text) or _keywordError(text)

    try:
        expr = parse_expr(text, evaluate=False, local_dict=unitSubs)
        str(expr)  # catch some problems
    except AttributeError as e:
        raise ExpressionError("Unknown function call")
    except (TokenError, SyntaxError, TypeError) as e:
        raise ExpressionError("Syntax error")
    except Exception as e:
        raise ExpressionError((type(e).__name__, repr(e)))
    if isinstance(expr, Function):
        raise ExpressionError('Function is not a valid expression')

    try:
        expr = quantity_simplify(expr)
    except TypeError:
        pass

    try:
        unitsAreConsistent(expr, dimension)
    except UnitMisMatchError as e:
        raise e
    return expr
コード例 #4
0
def getDimension(expr):
    """Get the units.Dimension expression of `expr`.
    If the dimension cannot be determined, returns None.

    :param expr: sympy.Expr
    :return: units.Dimension or None
    """
    logger.log(logging.DEBUG - 1, f'getDimension({expr})')
    if expr is not None:
        try:
            result = units.systems.SI._collect_factor_and_dimension(expr)[1]
        except ValueError as e:
            logger.log(logging.DEBUG - 1, f'getDimension() -> {repr(e)}')
            result = None
        except AttributeError as e:
            logger.log(logging.DEBUG - 1, f'getDimension() -> {repr(e)}')
            ev = quantity_simplify(expr).evalf()
            result = units.systems.SI._collect_factor_and_dimension(ev)[1]
    else:
        result = None
    logger.log(logging.DEBUG - 1, f'getDimension({expr}) -> {result}')
    return result
コード例 #5
0
    def __post_init__(self):
        e_o, e_i, e_m, R, l_o, l_i, l_m, d, a_1, a_2, a_3, b_1, b_2, b_3 = symbols('e_o e_i e_m R l_o l_i l_m d a_1 a_2 a_3 b_1 b_2 b_3')
        e_o = self.extracellular_permittivity * eps0 # S/m
        e_i = self.intracellular_permittivity * eps0 #S/m
        e_m = self.membrane_permittivity * eps0 #S/m
        R = self.cell_diameter / 2
        self.R = R

        l_o = self.extracellular_conductivity*Spm # S/m
        l_i = self.intracellular_conductivity*Spm #S/m
        l_m = self.membrane_conductivity*Spm #S/m

        d = self.membrane_thickness
        # epsilon_0

        sub1, sub2 = symbols('sub1 sub2')
        sub1 = (3 * (R**2) - 3 * d * R + d**2)
        sub2 = (3 * d * R - d**2)

        a_1 = 3 * d * l_o * ((l_i * (sub1)) + l_m*(sub2)) #eq.9a
        a_2 = 3 * d * ((l_i * e_o + l_o * e_i) * sub1 + (l_m * e_o + l_o * e_m) * sub2)
        a_3 = 3 * d * e_o * (e_i * (sub1) + e_m * sub2)

        b_1 = 2 * R**3 * (l_m +     2*l_o) * (l_m + (1/2) * l_i) + 2 * (R-d)**3 * (l_m - l_o) * (l_i - l_m)

        b_2 = 2 * R**3 * (l_i * ((1/2) * e_m + e_o) + l_m * ((1/2)*e_i + 2*e_m + 2*e_o) + l_o * (e_i + 2 * e_m)) + (2 * (R - d)**3\
        * (l_i * (e_m - e_o) + l_m * (e_i - 2*e_m + e_o) - l_o * (e_i - e_m))) # is this truly a multiply, or a cross?


        b_3 = 2 * R**3 * (e_m + 2*e_o) * (e_m + (1/2) * e_i) + 2 * (R-d)**3 * (e_m - e_o) * (e_i - e_m)

        sympy.pprint(powsimp(util.quantity_simplify(refine(a_1.simplify()))).as_coeff_Mul()[1])
        print()
        sympy.pprint(powsimp(util.quantity_simplify(refine(a_2.simplify()))).as_coeff_Mul()[1])
        print()
        sympy.pprint(powsimp(util.quantity_simplify(refine(a_3.simplify()))).as_coeff_Mul()[1])
        print()
        sympy.pprint(powsimp(util.quantity_simplify(refine(b_1.simplify()))).as_coeff_Mul()[1])
        print()
        sympy.pprint(powsimp(util.quantity_simplify(refine(b_2.simplify()))).as_coeff_Mul()[1])
        print()
        sympy.pprint(powsimp(util.quantity_simplify(refine(b_3.simplify()))).as_coeff_Mul()[1])
        print()
        print()
コード例 #6
0
    def errorCheck(self):
        """Checks if self.text() makes is a valid sympy.Expr.
        If expression contains units, checks they are compatible with self.dimension.
        Sets self._expr to None or the sympy.Expr version of self.text().
        Returns applicable error status.

        :return: ExpressionError when relevant
                 UnitMisMatchError when relevant
                 False if no error
                 None if resulting expression is None
        """
        self.logger.log(logging.DEBUG - 1, f'errorCheck()')
        try:
            expr = parseUnits(self.text(), self._dimension)
        except (ExpressionError, UnitMisMatchError) as e:
            self.logger.log(logging.DEBUG - 1, f'errorCheck() -> {repr(e)}')
            self._expr = None
            self.exprChanged[object].emit(None)
            self.valueChanged[object].emit(None)
            self.displayValue.emit('- - -')
            return e

        if expr is None:
            self.logger.log(logging.DEBUG - 1, 'errorCheck() -> None')
            self._expr = None
            self.exprChanged[object].emit(None)
            self.valueChanged[object].emit(None)
            self.displayValue.emit('- - -')
            return None
        # else:  # no problems
        self.logger.log(logging.DEBUG - 1, 'errorCheck() -> False')
        self._expr = quantity_simplify(expr)
        self.exprChanged[object].emit(self._expr)
        self.valueChanged[object].emit(self._expr.simplify().evalf())
        self.displayValue.emit(str(self._expr.evalf(4)))
        return False
コード例 #7
0
ファイル: simplify.py プロジェクト: carstimon/sympy
def simplify(expr, ratio=1.7, measure=count_ops, rational=False, inverse=False):
    """Simplifies the given expression.

    Simplification is not a well defined term and the exact strategies
    this function tries can change in the future versions of SymPy. If
    your algorithm relies on "simplification" (whatever it is), try to
    determine what you need exactly  -  is it powsimp()?, radsimp()?,
    together()?, logcombine()?, or something else? And use this particular
    function directly, because those are well defined and thus your algorithm
    will be robust.

    Nonetheless, especially for interactive use, or when you don't know
    anything about the structure of the expression, simplify() tries to apply
    intelligent heuristics to make the input expression "simpler".  For
    example:

    >>> from sympy import simplify, cos, sin
    >>> from sympy.abc import x, y
    >>> a = (x + x**2)/(x*sin(y)**2 + x*cos(y)**2)
    >>> a
    (x**2 + x)/(x*sin(y)**2 + x*cos(y)**2)
    >>> simplify(a)
    x + 1

    Note that we could have obtained the same result by using specific
    simplification functions:

    >>> from sympy import trigsimp, cancel
    >>> trigsimp(a)
    (x**2 + x)/x
    >>> cancel(_)
    x + 1

    In some cases, applying :func:`simplify` may actually result in some more
    complicated expression. The default ``ratio=1.7`` prevents more extreme
    cases: if (result length)/(input length) > ratio, then input is returned
    unmodified.  The ``measure`` parameter lets you specify the function used
    to determine how complex an expression is.  The function should take a
    single argument as an expression and return a number such that if
    expression ``a`` is more complex than expression ``b``, then
    ``measure(a) > measure(b)``.  The default measure function is
    :func:`count_ops`, which returns the total number of operations in the
    expression.

    For example, if ``ratio=1``, ``simplify`` output can't be longer
    than input.

    ::

        >>> from sympy import sqrt, simplify, count_ops, oo
        >>> root = 1/(sqrt(2)+3)

    Since ``simplify(root)`` would result in a slightly longer expression,
    root is returned unchanged instead::

       >>> simplify(root, ratio=1) == root
       True

    If ``ratio=oo``, simplify will be applied anyway::

        >>> count_ops(simplify(root, ratio=oo)) > count_ops(root)
        True

    Note that the shortest expression is not necessary the simplest, so
    setting ``ratio`` to 1 may not be a good idea.
    Heuristically, the default value ``ratio=1.7`` seems like a reasonable
    choice.

    You can easily define your own measure function based on what you feel
    should represent the "size" or "complexity" of the input expression.  Note
    that some choices, such as ``lambda expr: len(str(expr))`` may appear to be
    good metrics, but have other problems (in this case, the measure function
    may slow down simplify too much for very large expressions).  If you don't
    know what a good metric would be, the default, ``count_ops``, is a good
    one.

    For example:

    >>> from sympy import symbols, log
    >>> a, b = symbols('a b', positive=True)
    >>> g = log(a) + log(b) + log(a)*log(1/b)
    >>> h = simplify(g)
    >>> h
    log(a*b**(-log(a) + 1))
    >>> count_ops(g)
    8
    >>> count_ops(h)
    5

    So you can see that ``h`` is simpler than ``g`` using the count_ops metric.
    However, we may not like how ``simplify`` (in this case, using
    ``logcombine``) has created the ``b**(log(1/a) + 1)`` term.  A simple way
    to reduce this would be to give more weight to powers as operations in
    ``count_ops``.  We can do this by using the ``visual=True`` option:

    >>> print(count_ops(g, visual=True))
    2*ADD + DIV + 4*LOG + MUL
    >>> print(count_ops(h, visual=True))
    2*LOG + MUL + POW + SUB

    >>> from sympy import Symbol, S
    >>> def my_measure(expr):
    ...     POW = Symbol('POW')
    ...     # Discourage powers by giving POW a weight of 10
    ...     count = count_ops(expr, visual=True).subs(POW, 10)
    ...     # Every other operation gets a weight of 1 (the default)
    ...     count = count.replace(Symbol, type(S.One))
    ...     return count
    >>> my_measure(g)
    8
    >>> my_measure(h)
    14
    >>> 15./8 > 1.7 # 1.7 is the default ratio
    True
    >>> simplify(g, measure=my_measure)
    -log(a)*log(b) + log(a) + log(b)

    Note that because ``simplify()`` internally tries many different
    simplification strategies and then compares them using the measure
    function, we get a completely different result that is still different
    from the input expression by doing this.

    If rational=True, Floats will be recast as Rationals before simplification.
    If rational=None, Floats will be recast as Rationals but the result will
    be recast as Floats. If rational=False(default) then nothing will be done
    to the Floats.

    If inverse=True, it will be assumed that a composition of inverse
    functions, such as sin and asin, can be cancelled in any order.
    For example, ``asin(sin(x))`` will yield ``x`` without checking whether
    x belongs to the set where this relation is true. The default is
    False.
    """
    expr = sympify(expr)

    try:
        return expr._eval_simplify(ratio=ratio, measure=measure)
    except AttributeError:
        pass

    original_expr = expr = signsimp(expr)

    from sympy.simplify.hyperexpand import hyperexpand
    from sympy.functions.special.bessel import BesselBase
    from sympy import Sum, Product

    if not isinstance(expr, Basic) or not expr.args:  # XXX: temporary hack
        return expr

    if inverse and expr.has(Function):
        expr = inversecombine(expr)
        if not expr.args:  # simplified to atomic
            return expr

    if not isinstance(expr, (Add, Mul, Pow, ExpBase)):
        return expr.func(*[simplify(x, ratio=ratio, measure=measure, rational=rational)
                         for x in expr.args])

    # TODO: Apply different strategies, considering expression pattern:
    # is it a purely rational function? Is there any trigonometric function?...
    # See also https://github.com/sympy/sympy/pull/185.

    def shorter(*choices):
        '''Return the choice that has the fewest ops. In case of a tie,
        the expression listed first is selected.'''
        if not has_variety(choices):
            return choices[0]
        return min(choices, key=measure)

    # rationalize Floats
    floats = False
    if rational is not False and expr.has(Float):
        floats = True
        expr = nsimplify(expr, rational=True)

    expr = bottom_up(expr, lambda w: w.normal())
    expr = Mul(*powsimp(expr).as_content_primitive())
    _e = cancel(expr)
    expr1 = shorter(_e, _mexpand(_e).cancel())  # issue 6829
    expr2 = shorter(together(expr, deep=True), together(expr1, deep=True))

    if ratio is S.Infinity:
        expr = expr2
    else:
        expr = shorter(expr2, expr1, expr)
    if not isinstance(expr, Basic):  # XXX: temporary hack
        return expr

    expr = factor_terms(expr, sign=False)

    # hyperexpand automatically only works on hypergeometric terms
    expr = hyperexpand(expr)

    expr = piecewise_fold(expr)

    if expr.has(BesselBase):
        expr = besselsimp(expr)

    if expr.has(TrigonometricFunction, HyperbolicFunction):
        expr = trigsimp(expr, deep=True)

    if expr.has(log):
        expr = shorter(expand_log(expr, deep=True), logcombine(expr))

    if expr.has(CombinatorialFunction, gamma):
        # expression with gamma functions or non-integer arguments is
        # automatically passed to gammasimp
        expr = combsimp(expr)

    if expr.has(Sum):
        expr = sum_simplify(expr)

    if expr.has(Product):
        expr = product_simplify(expr)

    from sympy.physics.units import Quantity
    from sympy.physics.units.util import quantity_simplify

    if expr.has(Quantity):
        expr = quantity_simplify(expr)

    short = shorter(powsimp(expr, combine='exp', deep=True), powsimp(expr), expr)
    short = shorter(short, cancel(short))
    short = shorter(short, factor_terms(short), expand_power_exp(expand_mul(short)))
    if short.has(TrigonometricFunction, HyperbolicFunction, ExpBase):
        short = exptrigsimp(short)

    # get rid of hollow 2-arg Mul factorization
    hollow_mul = Transform(
        lambda x: Mul(*x.args),
        lambda x:
        x.is_Mul and
        len(x.args) == 2 and
        x.args[0].is_Number and
        x.args[1].is_Add and
        x.is_commutative)
    expr = short.xreplace(hollow_mul)

    numer, denom = expr.as_numer_denom()
    if denom.is_Add:
        n, d = fraction(radsimp(1/denom, symbolic=False, max_terms=1))
        if n is not S.One:
            expr = (numer*n).expand()/d

    if expr.could_extract_minus_sign():
        n, d = fraction(expr)
        if d != 0:
            expr = signsimp(-n/(-d))

    if measure(expr) > ratio*measure(original_expr):
        expr = original_expr

    # restore floats
    if floats and rational is None:
        expr = nfloat(expr, exponent=False)

    return expr
コード例 #8
0
def test_quantity_simplify_across_dimensions():
    from sympy.physics.units.util import quantity_simplify
    from sympy.physics.units import ampere, ohm, volt, joule, pascal, farad, second, watt, siemens, henry, tesla, weber, hour, newton

    assert quantity_simplify(ampere * ohm,
                             across_dimensions=True,
                             unit_system="SI") == volt
    assert quantity_simplify(6 * ampere * ohm,
                             across_dimensions=True,
                             unit_system="SI") == 6 * volt
    assert quantity_simplify(volt / ampere,
                             across_dimensions=True,
                             unit_system="SI") == ohm
    assert quantity_simplify(volt / ohm,
                             across_dimensions=True,
                             unit_system="SI") == ampere
    assert quantity_simplify(joule / meter**3,
                             across_dimensions=True,
                             unit_system="SI") == pascal
    assert quantity_simplify(farad * ohm,
                             across_dimensions=True,
                             unit_system="SI") == second
    assert quantity_simplify(joule / second,
                             across_dimensions=True,
                             unit_system="SI") == watt
    assert quantity_simplify(meter**3 / second,
                             across_dimensions=True,
                             unit_system="SI") == meter**3 / second
    assert quantity_simplify(joule / second,
                             across_dimensions=True,
                             unit_system="SI") == watt

    assert quantity_simplify(joule / coulomb,
                             across_dimensions=True,
                             unit_system="SI") == volt
    assert quantity_simplify(volt / ampere,
                             across_dimensions=True,
                             unit_system="SI") == ohm
    assert quantity_simplify(ampere / volt,
                             across_dimensions=True,
                             unit_system="SI") == siemens
    assert quantity_simplify(coulomb / volt,
                             across_dimensions=True,
                             unit_system="SI") == farad
    assert quantity_simplify(volt * second / ampere,
                             across_dimensions=True,
                             unit_system="SI") == henry
    assert quantity_simplify(volt * second / meter**2,
                             across_dimensions=True,
                             unit_system="SI") == tesla
    assert quantity_simplify(joule / ampere,
                             across_dimensions=True,
                             unit_system="SI") == weber

    assert quantity_simplify(5 * kilometer / hour,
                             across_dimensions=True,
                             unit_system="SI") == 25 * meter / (18 * second)
    assert quantity_simplify(5 * kilogram * meter / second**2,
                             across_dimensions=True,
                             unit_system="SI") == 5 * newton
コード例 #9
0
def simplify(expr, ratio=1.7, measure=count_ops, rational=False):
    # type: (object, object, object, object) -> object
    """
    Simplifies the given expression.

    Simplification is not a well defined term and the exact strategies
    this function tries can change in the future versions of SymPy. If
    your algorithm relies on "simplification" (whatever it is), try to
    determine what you need exactly  -  is it powsimp()?, radsimp()?,
    together()?, logcombine()?, or something else? And use this particular
    function directly, because those are well defined and thus your algorithm
    will be robust.

    Nonetheless, especially for interactive use, or when you don't know
    anything about the structure of the expression, simplify() tries to apply
    intelligent heuristics to make the input expression "simpler".  For
    example:

    >>> from sympy import simplify, cos, sin
    >>> from sympy.abc import x, y
    >>> a = (x + x**2)/(x*sin(y)**2 + x*cos(y)**2)
    >>> a
    (x**2 + x)/(x*sin(y)**2 + x*cos(y)**2)
    >>> simplify(a)
    x + 1

    Note that we could have obtained the same result by using specific
    simplification functions:

    >>> from sympy import trigsimp, cancel
    >>> trigsimp(a)
    (x**2 + x)/x
    >>> cancel(_)
    x + 1

    In some cases, applying :func:`simplify` may actually result in some more
    complicated expression. The default ``ratio=1.7`` prevents more extreme
    cases: if (result length)/(input length) > ratio, then input is returned
    unmodified.  The ``measure`` parameter lets you specify the function used
    to determine how complex an expression is.  The function should take a
    single argument as an expression and return a number such that if
    expression ``a`` is more complex than expression ``b``, then
    ``measure(a) > measure(b)``.  The default measure function is
    :func:`count_ops`, which returns the total number of operations in the
    expression.

    For example, if ``ratio=1``, ``simplify`` output can't be longer
    than input.

    ::

        >>> from sympy import sqrt, simplify, count_ops, oo
        >>> root = 1/(sqrt(2)+3)

    Since ``simplify(root)`` would result in a slightly longer expression,
    root is returned unchanged instead::

       >>> simplify(root, ratio=1) == root
       True

    If ``ratio=oo``, simplify will be applied anyway::

        >>> count_ops(simplify(root, ratio=oo)) > count_ops(root)
        True

    Note that the shortest expression is not necessary the simplest, so
    setting ``ratio`` to 1 may not be a good idea.
    Heuristically, the default value ``ratio=1.7`` seems like a reasonable
    choice.

    You can easily define your own measure function based on what you feel
    should represent the "size" or "complexity" of the input expression.  Note
    that some choices, such as ``lambda expr: len(str(expr))`` may appear to be
    good metrics, but have other problems (in this case, the measure function
    may slow down simplify too much for very large expressions).  If you don't
    know what a good metric would be, the default, ``count_ops``, is a good
    one.

    For example:

    >>> from sympy import symbols, log
    >>> a, b = symbols('a b', positive=True)
    >>> g = log(a) + log(b) + log(a)*log(1/b)
    >>> h = simplify(g)
    >>> h
    log(a*b**(-log(a) + 1))
    >>> count_ops(g)
    8
    >>> count_ops(h)
    5

    So you can see that ``h`` is simpler than ``g`` using the count_ops metric.
    However, we may not like how ``simplify`` (in this case, using
    ``logcombine``) has created the ``b**(log(1/a) + 1)`` term.  A simple way
    to reduce this would be to give more weight to powers as operations in
    ``count_ops``.  We can do this by using the ``visual=True`` option:

    >>> print(count_ops(g, visual=True))
    2*ADD + DIV + 4*LOG + MUL
    >>> print(count_ops(h, visual=True))
    2*LOG + MUL + POW + SUB

    >>> from sympy import Symbol, S
    >>> def my_measure(expr):
    ...     POW = Symbol('POW')
    ...     # Discourage powers by giving POW a weight of 10
    ...     count = count_ops(expr, visual=True).subs(POW, 10)
    ...     # Every other operation gets a weight of 1 (the default)
    ...     count = count.replace(Symbol, type(S.One))
    ...     return count
    >>> my_measure(g)
    8
    >>> my_measure(h)
    14
    >>> 15./8 > 1.7 # 1.7 is the default ratio
    True
    >>> simplify(g, measure=my_measure)
    -log(a)*log(b) + log(a) + log(b)

    Note that because ``simplify()`` internally tries many different
    simplification strategies and then compares them using the measure
    function, we get a completely different result that is still different
    from the input expression by doing this.

    If rational=True, Floats will be recast as Rationals before simplification.
    If rational=None, Floats will be recast as Rationals but the result will
    be recast as Floats. If rational=False(default) then nothing will be done
    to the Floats.
    """
    expr = sympify(expr)

    try:
        return expr._eval_simplify(ratio=ratio, measure=measure)
    except AttributeError:
        pass

    original_expr = expr = signsimp(expr)

    from sympy.simplify.hyperexpand import hyperexpand
    from sympy.functions.special.bessel import BesselBase
    from sympy import Sum, Product

    if not isinstance(expr, Basic) or not expr.args:  # XXX: temporary hack
        return expr

    if not isinstance(expr, (Add, Mul, Pow, ExpBase)):
        if isinstance(expr, Function) and hasattr(expr, "inverse"):
            if len(expr.args) == 1 and len(expr.args[0].args) == 1 and \
               isinstance(expr.args[0], expr.inverse(argindex=1)):
                return simplify(expr.args[0].args[0], ratio=ratio,
                                measure=measure, rational=rational)
        return expr.func(*[simplify(x, ratio=ratio, measure=measure, rational=rational)
                         for x in expr.args])

    # TODO: Apply different strategies, considering expression pattern:
    # is it a purely rational function? Is there any trigonometric function?...
    # See also https://github.com/sympy/sympy/pull/185.

    def shorter(*choices):
        '''Return the choice that has the fewest ops. In case of a tie,
        the expression listed first is selected.'''
        if not has_variety(choices):
            return choices[0]
        return min(choices, key=measure)

    # rationalize Floats
    floats = False
    if rational is not False and expr.has(Float):
        floats = True
        expr = nsimplify(expr, rational=True)

    expr = bottom_up(expr, lambda w: w.normal())
    expr = Mul(*powsimp(expr).as_content_primitive())
    _e = cancel(expr)
    expr1 = shorter(_e, _mexpand(_e).cancel())  # issue 6829
    expr2 = shorter(together(expr, deep=True), together(expr1, deep=True))

    if ratio is S.Infinity:
        expr = expr2
    else:
        expr = shorter(expr2, expr1, expr)
    if not isinstance(expr, Basic):  # XXX: temporary hack
        return expr

    expr = factor_terms(expr, sign=False)

    # hyperexpand automatically only works on hypergeometric terms
    expr = hyperexpand(expr)

    expr = piecewise_fold(expr)

    if expr.has(BesselBase):
        expr = besselsimp(expr)

    if expr.has(TrigonometricFunction, HyperbolicFunction):
        expr = trigsimp(expr, deep=True)

    if expr.has(log):
        expr = shorter(expand_log(expr, deep=True), logcombine(expr))

    if expr.has(CombinatorialFunction, gamma):
        # expression with gamma functions or non-integer arguments is
        # automatically passed to gammasimp
        expr = combsimp(expr)

    if expr.has(Sum):
        expr = sum_simplify(expr)

    if expr.has(Product):
        expr = product_simplify(expr)

    from sympy.physics.units import Quantity
    from sympy.physics.units.util import quantity_simplify

    if expr.has(Quantity):
        expr = quantity_simplify(expr)

    short = shorter(powsimp(expr, combine='exp', deep=True), powsimp(expr), expr)
    short = shorter(short, cancel(short))
    short = shorter(short, factor_terms(short), expand_power_exp(expand_mul(short)))
    if short.has(TrigonometricFunction, HyperbolicFunction, ExpBase):
        short = exptrigsimp(short)

    # get rid of hollow 2-arg Mul factorization
    hollow_mul = Transform(
        lambda x: Mul(*x.args),
        lambda x:
        x.is_Mul and
        len(x.args) == 2 and
        x.args[0].is_Number and
        x.args[1].is_Add and
        x.is_commutative)
    expr = short.xreplace(hollow_mul)

    numer, denom = expr.as_numer_denom()
    if denom.is_Add:
        n, d = fraction(radsimp(1/denom, symbolic=False, max_terms=1))
        if n is not S.One:
            expr = (numer*n).expand()/d

    if expr.could_extract_minus_sign():
        n, d = fraction(expr)
        if d != 0:
            expr = signsimp(-n/(-d))

    if measure(expr) > ratio*measure(original_expr):
        expr = original_expr

    # restore floats
    if floats and rational is None:
        expr = nfloat(expr, exponent=False)

    return expr
コード例 #10
0
    def errorCheck(self):
        """Checks if self.text() makes is a valid sympy.Expr.
        If expression contains units, checks their compatibility,
            and their convertibility to comboBox's selected units.
        Sets self._expr to None or the sympy.Expr version of self.text().
        Calculates and stores widget's evaluated value.
        Returns applicable error status.

        :return: ExpressionError when relevant
                 UnitMisMatchError when relevant
                 False if no error
                 None if resulting expression is None
        """
        self.logger.log(logging.DEBUG - 1, f'errorCheck() all')
        self._value = None
        self.lineEdit._expr = None

        def emit_error(err):
            self.logger.log(logging.DEBUG - 1, f'errorCheck() -> {repr(err)}')
            self.exprChanged[object].emit(None)
            self.valueChanged[object].emit(None)
            self.displayValue.emit('- - -')
            return err

        def emit_none(reason):
            self.logger.log(logging.DEBUG - 1,
                            f'errorCheck() -> {repr(reason)}')
            self.exprChanged[object].emit(None)
            self.valueChanged[object].emit(None)
            self.displayValue.emit('- - -')
            return None

        text = self.lineEdit.text()
        if text == '':
            return emit_none('empty text')

        text = text.replace('^', '**')
        try:
            err = _notSafeError(text) or _keywordError(text)
        except ExpressionError as e:
            return emit_error(e)

        try:
            expr = parse_expr(text, evaluate=False, local_dict=unitSubs)
            str(expr)  # catch some problems
        except AttributeError as e:
            err = ExpressionError("Unknown function call")
        except (TokenError, SyntaxError) as e:
            err = ExpressionError("Syntax error")
        except Exception as e:
            err = ExpressionError((type(e).__name__, repr(e)))
        if err is False and isinstance(expr, Function):
            err = ExpressionError('Function is not a valid expression')

        if err:
            return emit_error(err)

        try:
            expr = quantity_simplify(expr)
        except TypeError:
            pass

        u = getDimension(self.getUnits())

        try:
            unitsAreConsistent(expr, u)
        except UnitMisMatchError as e:
            return emit_error(e)

        self.logger.log(logging.DEBUG - 1, 'errorCheck() -> False')
        expr = convertTo(expr, self.getUnits())
        self.lineEdit._expr = expr
        self._value = expr.evalf()
        self.exprChanged[object].emit(expr)
        self.valueChanged[object].emit(self._value)
        self.displayValue.emit(str(expr.evalf(4)))
        # finish errorCheck, all good
        return False