Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further cleanup of solve() #426

Merged
merged 18 commits into from Feb 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions diofant/calculus/optimization.py
Expand Up @@ -4,7 +4,7 @@
from ..series import limit
from ..functions import Min
from ..matrices import Matrix, zeros, eye
from ..solvers import solve
from ..solvers import solve, reduce_inequalities
from ..calculus import singularities


Expand Down Expand Up @@ -78,7 +78,7 @@ def minimize(f, *v):

if dim == 1:
if constraints:
dom = solve(constraints, *v).as_set()
dom = reduce_inequalities(constraints, *v).as_set()
else:
dom = Interval(-oo, oo, True, True)**len(v)
return minimize_univariate(obj, v[0], dom)
Expand Down
49 changes: 48 additions & 1 deletion diofant/core/symbol.py
Expand Up @@ -16,7 +16,52 @@
class BaseSymbol(AtomicExpr, Boolean):
"""Abstract class for Symbols.

Do not instantiate this, use Symbol, Dummy or Wild.
Do not instantiate this, use derived classes.

Notes
=====

We introduce this class to prevent "flipping" of arguments
for "rich comparison" methods [1]_. There is no swapped-argument
versions of these methods, like :meth:`~object.__add__` vs
:meth:`~object.__radd__`, rather e.g. :meth:`~object.__lt__` and
:meth:`~object.__gt__` are each other's reflection.

According to the documentation [1]_, if the operands of such
method are of different types, and right operand’s type is a direct or
indirect subclass of the left operand’s type, the reflected method
of the right operand has priority, otherwise the left operand’s
method has priority.

Thus, simple class hierarhy, where :class:`Symbol` is a parent
class for both :class:`Dummy` and :class:`Wild` isn't possible,
if we want to avoid silent switching to the reflected methods
for rich comparisons of parent and child. See also sympy/sympy#7951.

Examples
========

We illustrate the "flipping" problem, by using here
BaseSymbol in place of ordinary Symbol:

>>> from diofant.core.symbol import Wild, BaseSymbol as Symbol

>>> p = Wild('p')
>>> x = Symbol('x')
>>> x < p
p_ > x

See Also
========

Symbol
Dummy
Wild

References
==========

.. [1] https://docs.python.org/3/reference/datamodel.html#object.__lt__
"""

is_comparable = False
Expand Down Expand Up @@ -197,6 +242,8 @@ class Symbol(BaseSymbol):
========

:mod:`diofant.core.assumptions`
Dummy
Wild
"""

pass
Expand Down
4 changes: 4 additions & 0 deletions diofant/functions/elementary/miscellaneous.py
Expand Up @@ -454,6 +454,10 @@ def evalf(self, prec=None, **options):
def is_extended_real(self):
return fuzzy_and(arg.is_extended_real for arg in self.args)

def _eval_rewrite_as_Piecewise(self, *args):
from .. import Heaviside, Piecewise
return self.rewrite(Heaviside).rewrite(Piecewise)


class Max(MinMaxBase, Application):
"""Return, if possible, the maximum value of the list.
Expand Down
20 changes: 11 additions & 9 deletions diofant/functions/elementary/tests/test_miscellaneous.py
@@ -1,14 +1,9 @@
import pytest

from diofant.core.function import Function
from diofant.core.numbers import I, oo, Rational
from diofant.core.singleton import S
from diofant.core.symbol import Symbol
from diofant.functions.elementary.miscellaneous import (sqrt, cbrt, root,
Min, Max, real_root)
from diofant.functions.elementary.trigonometric import cos, sin
from diofant.functions.elementary.integers import floor, ceiling
from diofant.functions.special.delta_functions import Heaviside
from diofant.core import Function, I, oo, Rational, S, Symbol, symbols, Eq
from diofant.logic import true, false
from diofant.functions import (sqrt, cbrt, root, Min, Max, real_root,
Piecewise, cos, sin, floor, ceiling, Heaviside)

__all__ = ()

Expand Down Expand Up @@ -252,3 +247,10 @@ def test_rewrite_MaxMin_as_Heaviside():
x*Heaviside(-2*x)*Heaviside(-x - 2) - \
x*Heaviside(2*x)*Heaviside(x - 2) \
- 2*Heaviside(-x + 2)*Heaviside(x + 2)


def test_rewrite_as_Piecewise():
x, y = symbols('x, y', real=True)
assert (Max(x, y).rewrite(Piecewise) ==
x*Piecewise((1, x - y > 0), (S.Half, Eq(x - y, 0)), (0, true)) +
y*Piecewise((1, -x + y > 0), (S.Half, Eq(-x + y, 0)), (0, true)))
6 changes: 2 additions & 4 deletions diofant/polys/numberfields.py
Expand Up @@ -607,10 +607,8 @@ def minimal_polynomial(ex, x=None, **args):
if ex.is_number:
# not sure if it's always needed but try it for numbers (issue sympy/sympy#8354)
ex = _mexpand(ex, recursive=True)
for expr in preorder_traversal(ex):
if expr.is_AlgebraicNumber:
compose = False
break
if any(e.is_AlgebraicNumber for e in preorder_traversal(ex)):
compose = False

if x is not None:
x, cls = sympify(x), Poly
Expand Down
1 change: 1 addition & 0 deletions diofant/printing/str.py
Expand Up @@ -596,6 +596,7 @@ def _xab_tostr(xab):

def _print_Symbol(self, expr):
return expr.name
_print_BaseSymbol = _print_Symbol
_print_MatrixSymbol = _print_Symbol
_print_RandomSymbol = _print_Symbol

Expand Down
12 changes: 9 additions & 3 deletions diofant/simplify/ratsimp.py
Expand Up @@ -58,7 +58,8 @@ def ratsimpmodprime(expr, G, *gens, **args):
http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.163.6984
(specifically, the second algorithm)
"""
from ..solvers import solve
from ..matrices import Matrix, zeros
from ..solvers.solvers import minsolve_linear_system

quick = args.pop('quick', True)
polynomial = args.pop('polynomial', False)
Expand Down Expand Up @@ -158,7 +159,10 @@ def _ratsimpmodprime(a, b, allsol, N=0, D=0):
order=opt.order, polys=True)[1]

S = Poly(r, gens=opt.gens).coeffs()
sol = solve(S, Cs + Ds, particular=True, quick=True)
Sv = Cs + Ds
Sm = zeros(len(S), len(Sv) + 1)
Sm[:, :-1] = Matrix([[a.diff(b) for b in Sv] for a in S])
sol = minsolve_linear_system(Sm, *Sv, quick=True)

if sol and not all(s == 0 for s in sol.values()):
c = c_hat.subs(sol)
Expand Down Expand Up @@ -205,7 +209,9 @@ def _ratsimpmodprime(a, b, allsol, N=0, D=0):
debug('Looking for best minimal solution. Got: %s' % len(allsol))
newsol = []
for c_hat, d_hat, S, ng in allsol:
sol = solve(S, ng, particular=True, quick=False)
Sm = zeros(len(S), len(ng) + 1)
Sm[:, :-1] = Matrix([[a.diff(b) for b in ng] for a in S])
sol = minsolve_linear_system(Sm, *ng)
newsol.append((c_hat.subs(sol), d_hat.subs(sol)))
c, d = min(newsol, key=lambda x: len(x[0].terms()) + len(x[1].terms()))

Expand Down
7 changes: 6 additions & 1 deletion diofant/solvers/inequalities.py
Expand Up @@ -485,7 +485,7 @@ def _reduce_inequalities(inequalities, symbols):

def reduce_inequalities(inequalities, symbols=[]):
"""
Reduce a system of inequalities with rational coefficients.
Reduces a system of inequalities or equations.

Examples
========
Expand All @@ -497,6 +497,11 @@ def reduce_inequalities(inequalities, symbols=[]):
-3 <= x
>>> reduce_inequalities(0 <= x + y*2 - 1, [x])
-2*y + 1 <= x

See Also
========

diofant.solvers.solvers.solve : solve algebraic equations
"""
if not iterable(inequalities):
inequalities = [inequalities]
Expand Down