Skip to content

Commit

Permalink
Merge branch 'master' into default-extension2
Browse files Browse the repository at this point in the history
  • Loading branch information
skirpichev committed Oct 6, 2019
2 parents 421a560 + 52cb12a commit af951a2
Show file tree
Hide file tree
Showing 65 changed files with 566 additions and 427 deletions.
24 changes: 20 additions & 4 deletions .travis.yml
Expand Up @@ -5,7 +5,7 @@ python:
- 3.7
env:
global:
- PYTEST_ADDOPTS="-n auto --cov-config setup.cfg --cov-append --cov-report="
- PYTEST_ADDOPTS="-n auto --cov-append --cov-report="
- COVOPTS="--cov diofant -m \"not slow and not xfail\""
- PYTHONHASHSEED=0
- secure: "VNgpd/TFAkLGjWZzRBWxujDHktdvp2Fg9D8PbGmr/pbmLcJS3a5pf6po1T/\
Expand Down Expand Up @@ -40,6 +40,15 @@ stages:
- deploy
matrix:
include:
- stage: test
python: 3.8-dev
env: SPLIT=1/3
- stage: test
python: 3.8-dev
env: SPLIT=2/3
- stage: test
python: 3.8-dev
env: SPLIT=3/3
- stage: quality
python: 3.7
env: COVERAGE='on'
Expand All @@ -52,9 +61,11 @@ matrix:
python setup.py build_sphinx -W -b linkcheck
fi
- pip uninstall -y gmpy2
- pip uninstall -y numpy
- PYTEST_ADDOPTS="${PYTEST_ADDOPTS} ${COVOPTS}"
- DIOFANT_GROUND_TYPES='gmpy' py.test diofant/tests/domains
- travis_wait py.test diofant/tests/polys
- travis_wait py.test diofant/tests/external
- stage: deploy
env:
-
Expand Down Expand Up @@ -107,10 +118,15 @@ matrix:
tags: true
condition: "$TRAVIS_TAG =~ ^v[0-9]+\\.[0-9]+\\.[0-9]+.*$"
before_install:
- pip uninstall -y pytest
- pip uninstall -y pytest attrs
- pip install --pre -U gmpy2
install:
- travis_wait pip install .[exports,plot,interactive,develop,gmpy,docs]
- |
INSTALL_DEPS="interactive,develop,gmpy"
if [ ${TRAVIS_PYTHON_VERSION} == '3.7' ]; then
INSTALL_DEPS="${INSTALL_DEPS},exports,plot,docs"
fi
travis_wait pip install -U .[${INSTALL_DEPS}]
script:
- |
PYTEST_ADDOPTS="${PYTEST_ADDOPTS} --split=${SPLIT}"
Expand All @@ -120,6 +136,6 @@ script:
PYTEST_ADDOPTS="${PYTEST_ADDOPTS} --doctest-modules"
fi
python setup.py test
after_success: test -n "${COVERAGE}" && codecov
after_success: test -n "${COVERAGE}" && codecov --required
notifications:
email: false
7 changes: 7 additions & 0 deletions conftest.py
Expand Up @@ -9,6 +9,13 @@


collect_ignore = ["setup.py"]
try:
import matplotlib
matplotlib.rc('figure', max_open_warning=0)
del matplotlib
except ImportError:
collect_ignore.extend(["diofant/plotting/plot.py",
"diofant/plotting/plot_implicit.py"])

sp = re.compile(r'([0-9]+)/([1-9][0-9]*)')

Expand Down
2 changes: 1 addition & 1 deletion diofant/combinatorics/permutations.py
Expand Up @@ -1980,7 +1980,7 @@ def inversions(self):
References
==========
[1] https://www.cp.eng.chula.ac.th/~piak/teaching/algo/algo2008/count-inv.htm
* https://www.cp.eng.chula.ac.th/~prabhas//teaching/algo/algo2008/count-inv.htm
Examples
========
Expand Down
47 changes: 12 additions & 35 deletions diofant/concrete/gosper.py
Expand Up @@ -2,7 +2,7 @@

from ..core import Dummy, Integer, nan, symbols
from ..core.compatibility import is_sequence
from ..polys import Poly, factor, parallel_poly_from_expr
from ..polys import factor, parallel_poly_from_expr
from ..simplify import hypersimp
from ..solvers import solve

Expand Down Expand Up @@ -34,8 +34,9 @@ def gosper_normal(f, g, n, polys=True):
Examples
========
>>> gosper_normal(4*n + 5, 2*(4*n + 1)*(2*n + 3), n, polys=False)
(1/4, n + 3/2, n + 1/4)
>>> gosper_normal(4*n + 5, 2*(4*n + 1)*(2*n + 3), n)
(Poly(1/4, n, domain='QQ'), Poly(n + 3/2, n, domain='QQ'),
Poly(n + 1/4, n, domain='QQ'))
"""
(p, q), opt = parallel_poly_from_expr((f, g), n, field=True)
Expand All @@ -56,14 +57,7 @@ def gosper_normal(f, g, n, polys=True):
for j in range(1, i + 1):
C *= d.shift(-j)

A *= Z

if not polys:
A = A.as_expr()
B = B.as_expr()
C = C.as_expr()

return A, B, C
return A*Z, B, C


def gosper_term(f, n):
Expand Down Expand Up @@ -111,29 +105,24 @@ def gosper_term(f, n):
D.remove(d)

if not D:
return # 'f(n)' is *not* Gosper-summable
return

d = max(D)

coeffs = symbols('c:%s' % (d + 1), cls=Dummy)
domain = A.domain.inject(*coeffs)

x = Poly(coeffs, n, domain=domain)
x = sum(c*n**i for i, c in enumerate(reversed(coeffs)))
x = x.as_poly(n, domain=domain)
H = A*x.shift(1) - B*x - C

solution = solve(H.coeffs(), coeffs)
if solution:
solution = solution[0]

x = x.as_expr().subs(solution)
x = x.as_expr().subs(solution).subs({_: 0 for _ in coeffs})

for coeff in coeffs:
if coeff not in solution:
x = x.subs({coeff: 0})

if x == 0:
return # 'f(n)' is *not* Gosper-summable
else:
if x != 0:
return B.as_expr()*x/C.as_expr()


Expand All @@ -152,17 +141,8 @@ def gosper_sum(f, k):
Examples
========
>>> from diofant.abc import i
>>> f = (4*k + 1)*factorial(k)/factorial(2*k + 1)
>>> gosper_sum(f, (k, 0, n))
>>> gosper_sum((4*k + 1)*factorial(k)/factorial(2*k + 1), (k, 0, n))
(-factorial(n) + 2*factorial(2*n + 1))/factorial(2*n + 1)
>>> _.subs({n: 2}) == sum(f.subs({k: i}) for i in [0, 1, 2])
True
>>> gosper_sum(f, (k, 3, n))
(-60*factorial(n) + factorial(2*n + 1))/(60*factorial(2*n + 1))
>>> _.subs({n: 5}) == sum(f.subs({k: i}) for i in [3, 4, 5])
True
References
==========
Expand All @@ -188,9 +168,6 @@ def gosper_sum(f, k):
result = (f*(g + 1)).subs({k: b}) - (f*g).subs({k: a})

if result is nan:
try:
result = (f*(g + 1)).limit(k, b) - (f*g).limit(k, a)
except NotImplementedError: # pragma: no cover
result = None
result = (f*(g + 1)).limit(k, b) - (f*g).limit(k, a)

return factor(result)
7 changes: 0 additions & 7 deletions diofant/core/add.py
Expand Up @@ -413,16 +413,9 @@ def _eval_is_extended_real(self):
def _eval_is_complex(self):
return _fuzzy_group((a.is_complex for a in self.args), quick_exit=True)

def _eval_is_antihermitian(self):
return _fuzzy_group((a.is_antihermitian for a in self.args),
quick_exit=True)

def _eval_is_finite(self):
return _fuzzy_group((a.is_finite for a in self.args), quick_exit=True)

def _eval_is_hermitian(self):
return _fuzzy_group((a.is_hermitian for a in self.args), quick_exit=True)

def _eval_is_integer(self):
return _fuzzy_group((a.is_integer for a in self.args), quick_exit=True)

Expand Down
10 changes: 3 additions & 7 deletions diofant/core/assumptions.py
Expand Up @@ -56,11 +56,11 @@
'real == extended_real & finite',
'rational -> algebraic',
'algebraic -> complex',
'real -> complex & hermitian',
'imaginary -> complex & antihermitian',
'real -> complex',
'imaginary -> complex',
'complex -> finite & commutative',
'extended_real -> commutative',
'extended_real -> real | infinite',
'extended_real -> real | infinite',

'odd == integer & ~even',
'even == integer & ~odd',
Expand Down Expand Up @@ -321,10 +321,6 @@
"""Test if self can have only positive values.""",
'nonpositive':
"""Test if self can have only nonpositive values.""",
'hermitian':
"""Test if self belongs to the field of hermitian operators.""",
'antihermitian':
"""Test if self belongs to the field of antihermitian operators.""",
}


Expand Down
5 changes: 3 additions & 2 deletions diofant/core/basic.py
@@ -1,6 +1,7 @@
"""Base class for all the objects in Diofant."""

from collections import Mapping, defaultdict
from collections import defaultdict
from collections.abc import Mapping
from itertools import zip_longest

from .cache import cacheit
Expand Down Expand Up @@ -161,7 +162,7 @@ def _repr_pretty_(self, p, cycle):

def _repr_latex_(self):
from ..printing import latex
return latex(self, mode='equation')
return latex(self, mode='equation*')

def atoms(self, *types):
"""Returns the atoms that form the current object.
Expand Down
2 changes: 1 addition & 1 deletion diofant/core/containers.py
Expand Up @@ -6,7 +6,7 @@
They are supposed to work seamlessly within the Diofant framework.
"""

from collections import Mapping
from collections.abc import Mapping

from .basic import Basic
from .compatibility import as_int, iterable
Expand Down
9 changes: 0 additions & 9 deletions diofant/core/expr.py
Expand Up @@ -704,13 +704,8 @@ def conjugate(self):
return c(self)

def _eval_transpose(self):
from ..functions.elementary.complexes import conjugate
if self.is_complex or self.is_extended_real:
return self
elif self.is_hermitian:
return conjugate(self)
elif self.is_antihermitian:
return -conjugate(self)

def transpose(self):
"""Transpose self.
Expand All @@ -726,10 +721,6 @@ def transpose(self):

def _eval_adjoint(self):
from ..functions.elementary.complexes import conjugate, transpose
if self.is_hermitian:
return self
elif self.is_antihermitian:
return -self
obj = self._eval_conjugate()
if obj is not None:
return transpose(obj)
Expand Down
32 changes: 0 additions & 32 deletions diofant/core/mul.py
Expand Up @@ -1034,38 +1034,6 @@ def _eval_is_imaginary(self):
else:
return obj.is_real

def _eval_is_hermitian(self):
hermitian = True
one_nc = zero = False

for t in self.args:
if not t.is_commutative:
if one_nc:
return
one_nc = True

if t.is_antihermitian or t.is_hermitian:
if t.is_antihermitian:
hermitian = not hermitian
z = t.is_zero
if not z and zero is False:
zero = z
elif z:
if self.is_finite:
return True
return
else:
return

if zero is False or hermitian:
return hermitian

def _eval_is_antihermitian(self):
if self.is_zero:
return False
elif self.is_nonzero:
return (I*self).is_hermitian

def _eval_is_irrational(self):
for t in self.args:
a = t.is_irrational
Expand Down
13 changes: 13 additions & 0 deletions diofant/core/numbers.py
Expand Up @@ -1074,6 +1074,9 @@ def _eval_power(self, expt):
def _as_mpf_val(self, prec):
return mlib.from_rational(self.numerator, self.denominator, prec, rnd)

def _mpmath_(self, prec, rnd):
return mpmath.make_mpf(mlib.from_rational(self.numerator, self.denominator, prec, rnd))

def __abs__(self):
return Rational(abs(self.numerator), self.denominator)

Expand Down Expand Up @@ -2563,6 +2566,16 @@ def as_base_exp(self):

converter[float] = converter[decimal.Decimal] = Float

try:
import numpy as np

def _sympify_numpy(x):
return Float(mpmath.mpmathify(x))

converter[np.floating] = _sympify_numpy
except ImportError:
pass

converter[int] = Integer
converter[fractions.Fraction] = Rational

Expand Down
8 changes: 8 additions & 0 deletions diofant/functions/elementary/complexes.py
Expand Up @@ -97,6 +97,10 @@ def _eval_rewrite_as_im(self, arg):
def _eval_is_algebraic(self):
return self.args[0].is_algebraic

def _eval_is_real(self):
if self.args[0].is_complex:
return True


class im(Function):
"""Returns imaginary part of expression.
Expand Down Expand Up @@ -189,6 +193,10 @@ def _eval_rewrite_as_re(self, arg):
def _eval_is_algebraic(self):
return self.args[0].is_algebraic

def _eval_is_real(self):
if self.args[0].is_complex:
return True


###############################################################################
# ############# SIGN, ABSOLUTE VALUE, ARGUMENT and CONJUGATION ############## #
Expand Down
10 changes: 10 additions & 0 deletions diofant/functions/elementary/hyperbolic.py
Expand Up @@ -919,6 +919,16 @@ def inverse(self, argindex=1):
"""Returns the inverse of this function."""
return cosh

def _eval_rewrite_as_log(self, x):
return log(x + sqrt(x - 1)*sqrt(x + 1))

def _eval_nseries(self, x, n, logx):
x0 = self.args[0].limit(x, 0)
if x0 == 1:
return self._eval_rewrite_as_log(self.args[0])._eval_nseries(x, n, logx)
else:
return super()._eval_nseries(x, n, logx)


class atanh(Function):
"""
Expand Down

0 comments on commit af951a2

Please sign in to comment.