From 958569134cd971579a05d5570da88495046e430a Mon Sep 17 00:00:00 2001 From: Emerson de Andrade Date: Sun, 15 Oct 2023 21:41:28 -0300 Subject: [PATCH] updated gradient calculation instead of using the module auto_differentiation.py (removed) to compute the gradient (for the geofencing behavior), the package numdifftools is now integrated. --- .github/workflows/release.yml | 24 ++ .github/workflows/tests_package.yml | 2 +- README.md | 4 +- docs/requirements.txt | 1 + .../03_Custom_Animations.ipynb | 3 +- docs/source/index.rst | 2 +- ...le_customized_aggregation_area_coverage.py | 3 +- notebooks/03_Custom_Animations.ipynb | 3 +- pyswarming/__init__.py | 2 +- pyswarming/auto_differentiation.py | 387 ------------------ pyswarming/behaviors.py | 9 +- setup.py | 3 +- tests/test_behaviors.py | 6 +- 13 files changed, 43 insertions(+), 406 deletions(-) create mode 100644 .github/workflows/release.yml delete mode 100644 pyswarming/auto_differentiation.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..78998c9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,24 @@ +name: Upload Python Package + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* \ No newline at end of file diff --git a/.github/workflows/tests_package.yml b/.github/workflows/tests_package.yml index 9add517..84e0fbc 100644 --- a/.github/workflows/tests_package.yml +++ b/.github/workflows/tests_package.yml @@ -26,7 +26,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install flake8 pytest numpy matplotlib + pip install flake8 pytest numpy numdifftools matplotlib if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Lint with flake8 run: | diff --git a/README.md b/README.md index dd07014..52ae1d6 100755 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Tests](https://github.com/mrsonandrade/pyswarming/actions/workflows/tests_package.yml/badge.svg)](https://github.com/mrsonandrade/pyswarming/actions/workflows/tests_package.yml) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) [![Documentation Status](https://readthedocs.org/projects/pyswarming/badge/?version=latest)](https://pyswarming.readthedocs.io/en/latest/?badge=latest) -![version](https://img.shields.io/badge/version-1.1.3-blue) +![version](https://img.shields.io/badge/version-1.1.4-blue) [![Downloads](https://static.pepy.tech/personalized-badge/pyswarming?period=total&units=none&left_color=black&right_color=blue&left_text=Downloads)](https://pepy.tech/project/pyswarming) [![DOI](https://joss.theoj.org/papers/10.21105/joss.05647/status.svg)](https://doi.org/10.21105/joss.05647) @@ -19,7 +19,7 @@ pip install pyswarming ## Dependencies -`pyswarming`'s dependencies are: `numpy` and `matplotlib`. +`pyswarming`'s dependencies are: `numpy`, `numdifftools` and `matplotlib`. ## Documentation diff --git a/docs/requirements.txt b/docs/requirements.txt index b3e5e4d..1600b7e 100755 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,6 @@ ipykernel numpy +numdifftools pyswarming matplotlib nbsphinx diff --git a/docs/source/example_notebooks/03_Custom_Animations.ipynb b/docs/source/example_notebooks/03_Custom_Animations.ipynb index 6ea029e..f2180b2 100755 --- a/docs/source/example_notebooks/03_Custom_Animations.ipynb +++ b/docs/source/example_notebooks/03_Custom_Animations.ipynb @@ -392,8 +392,7 @@ "robot4, = ax.plot([], [], marker='o', lw=0)\n", "\n", "# sphere function: used as region to be filled\n", - "def sphere(x, y, z, x0=0, y0=0, z0=0, radius=4.0):\n", - " return (x-x0)**2 + (y-y0)**2 + (z-z0)**2 - radius\n", + "sphere = lambda x: x[0]**2 + x[1]**2 + x[2]**2 - 4.0\n", "\n", "# initialization function: plot the background of each frame\n", "def init():\n", diff --git a/docs/source/index.rst b/docs/source/index.rst index 73d83ae..820b5b4 100755 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -27,7 +27,7 @@ You can install ``pyswarming`` from PyPI using pip (**Recommended**):: Dependencies ============ -``pyswarming``'s dependencies are: ``numpy`` and ``matplotlib``. +``pyswarming``'s dependencies are: ``numpy``, ``numdifftools`` and ``matplotlib``. Algorithms covered diff --git a/examples/example_customized_aggregation_area_coverage.py b/examples/example_customized_aggregation_area_coverage.py index d3b1535..138b582 100644 --- a/examples/example_customized_aggregation_area_coverage.py +++ b/examples/example_customized_aggregation_area_coverage.py @@ -44,8 +44,7 @@ robot4, = ax.plot([], [], marker='o', lw=0) # sphere function: used as region to be filled -def sphere(x, y, z, x0=0, y0=0, z0=0, radius=4.0): - return (x-x0)**2 + (y-y0)**2 + (z-z0)**2 - radius +sphere = lambda x: x[0]**2 + x[1]**2 + x[2]**2 - 4.0 # initialization function: plot the background of each frame def init(): diff --git a/notebooks/03_Custom_Animations.ipynb b/notebooks/03_Custom_Animations.ipynb index aa814ec..5aaab99 100755 --- a/notebooks/03_Custom_Animations.ipynb +++ b/notebooks/03_Custom_Animations.ipynb @@ -414,8 +414,7 @@ "robot4, = ax.plot([], [], marker='o', lw=0)\n", "\n", "# sphere function: used as region to be filled\n", - "def sphere(x, y, z, x0=0, y0=0, z0=0, radius=4.0):\n", - " return (x-x0)**2 + (y-y0)**2 + (z-z0)**2 - radius\n", + "sphere = lambda x: x[0]**2 + x[1]**2 + x[2]**2 - 4.0\n", "\n", "# initialization function: plot the background of each frame\n", "def init():\n", diff --git a/pyswarming/__init__.py b/pyswarming/__init__.py index ff2fbb3..72a1a0f 100755 --- a/pyswarming/__init__.py +++ b/pyswarming/__init__.py @@ -38,6 +38,6 @@ __all__.append(module_j) name = "pyswarming" -__version__ = "1.1.3" +__version__ = "1.1.4" __author__ = "Emerson Martins de Andrade, Antonio Carlos Fernandes and Joel Sena Sales Jr" __author_email__ = "mrson@oceanica.ufrj.br" diff --git a/pyswarming/auto_differentiation.py b/pyswarming/auto_differentiation.py deleted file mode 100644 index 47d921f..0000000 --- a/pyswarming/auto_differentiation.py +++ /dev/null @@ -1,387 +0,0 @@ -'Toolkit for automatic-differentiation of Python functions' - -# Resources for automatic-differentiation: -# https://en.wikipedia.org/wiki/Automatic_differentiation -# https://justindomke.wordpress.com/2009/02/17/ -# http://www.autodiff.org/ - -from __future__ import division -import math - -## Dual Number Class ##################################################### - -class Num(float): - ''' The auto-differentiation number class works likes a float - for a function input, but all operations on that number - will concurrently compute the derivative. - - Creating Nums - ------------- - New numbers are created with: Num(x, dx) - Make constants (not varying with respect to x) with: Num(3.5) - Make variables (that vary with respect to x) with: Num(3.5, 1.0) - The short-cut for Num(3.5, 1.0) is: Var(3.5) - - Accessing Nums - -------------- - Convert a num back to a float with: float(n) - The derivative is accessed with: n.dx - Or with a the short-cut function: d(n) - - Functions of One Variable - ------------------------- - >>> f = lambda x: cos(2.5 * x) ** 3 - >>> y = f(Var(1.5)) # Evaluate at x=1.5 - >>> y # f(1.5) - -0.552497105486732 - >>> y.dx # f'(1.5) - 2.88631746797551 - - Partial Derivatives and Gradients of Multi-variable Functions - ------------------------------------------------------------- - - The tool can also be used to compute gradients of multivariable - functions by making one of the inputs variable and the keeping - the remaining inputs constant: - - >>> f = lambda x, y: x*y + sin(x) - >>> f(2.5, 3.5) # Evaluate at (2.5, 3.5) - 9.348472144103956 - >>> d(f(Var(2.5), 3.5)) # Partial with respect to x - 2.6988563844530664 - >>> d(f(2.5, Var(3.5))) # Partial with respect to y - 2.5 - >>> gradient(f, (2.5, 3.5)) - (2.6988563844530664, 2.5) - - See: https://www.wolframalpha.com/input/?lk=3&i=grad(x*y+%2B+sin(x)) - - ''' - # Tables of Derivatives: - # http://hyperphysics.phy-astr.gsu.edu/hbase/math/derfunc.html - # http://tutorial.math.lamar.edu/pdf/Common_Derivatives_Integrals.pdf - # http://www.nps.edu/Academics/Schools/GSEAS/Departments/Math/pdf_sources/BlueBook27.pdf - # https://www.wolframalpha.com/input/?lk=3&i=d%2Fdx(u(x)%5E(v(x))) - - __slots__ = ['dx'] - - def __new__(cls, value, dx=0.0): - if isinstance(value, cls): return value - inst = float.__new__(cls, value) - inst.dx = dx - return inst - - def __add__(u, v): - return Num(float(u) + float(v), d(u) + d(v)) - - def __sub__(u, v): - return Num(float(u) - float(v), d(u) - d(v)) - - def __mul__(u, v): - u, v, du, dv = float(u), float(v), d(u), d(v) - return Num(u * v, u * dv + v * du) - - def __truediv__(u, v): - u, v, du, dv = float(u), float(v), d(u), d(v) - return Num(u / v, (v * du - u * dv) / v ** 2.0) - - def __pow__(u, v): - u, v, du, dv = float(u), float(v), d(u), d(v) - return Num(u ** v, - (v * u ** (v - 1.0) * du if du else 0.0) + - (math.log(u) * u ** v * dv if dv else 0.0)) - - def __floordiv__(u, v): - return Num(float(u) // float(v), 0.0) - - def __mod__(u, v): - u, v, du, dv = float(u), float(v), d(u), d(v) - return Num(u % v, du - u // v * dv) - - def __pos__(u): - return u - - def __neg__(u): - return Num(-float(u), -d(u)) - - __radd__ = __add__ - __rmul__ = __mul__ - - def __rsub__(self, other): - return -(self - other) - - def __rtruediv__(self, other): - return Num(other) / self - - def __rpow__(self, other): - return Num(other) ** self - - def __rmod__(u, v): - return Num(v) % u - - def __rfloordiv__(self, other): - return Num(other) // self - - def __abs__(self): - return self if self >= 0.0 else -self - -## Convenience Functions ################################################# -Var = lambda x: Num(x, 1.0) -d = lambda x: getattr(x, 'dx', 0.0) - -## Math Module Functions and Constants ################################### -sqrt = lambda u: Num(math.sqrt(u), d(u) / (2.0 * math.sqrt(u))) -log = lambda u: Num(math.log(u), d(u) / float(u)) -log2 = lambda u: Num(math.log2(u), d(u) / (float(u) * math.log(2.0))) -log10 = lambda u: Num(math.log10(u), d(u) / (float(u) * math.log(10.0))) -log1p = lambda u: Num(math.log1p(u), d(u) / (float(u) + 1.0)) -exp = lambda u: Num(math.exp(u), math.exp(u) * d(u)) -expm1 = lambda u: Num(math.expm1(u), math.exp(u) * d(u)) -sin = lambda u: Num(math.sin(u), math.cos(u) * d(u)) -cos = lambda u: Num(math.cos(u), -math.sin(u) * d(u)) -tan = lambda u: Num(math.tan(u), d(u) / math.cos(u) ** 2.0) -sinh = lambda u: Num(math.sinh(u), math.cosh(u) * d(u)) -cosh = lambda u: Num(math.cosh(u), math.sinh(u) * d(u)) -tanh = lambda u: Num(math.tanh(u), d(u) / math.cosh(u) ** 2.0) -asin = lambda u: Num(math.asin(u), d(u) / math.sqrt(1.0 - float(u) ** 2.0)) -acos = lambda u: Num(math.acos(u), -d(u) / math.sqrt(1.0 - float(u) ** 2.0)) -atan = lambda u: Num(math.atan(u), d(u) / (1.0 + float(u) ** 2.0)) -asinh = lambda u: Num(math.asinh(u), d(u) / math.hypot(u, 1.0)) -acosh = lambda u: Num(math.acosh(u), d(u) / math.sqrt(float(u) ** 2.0 - 1.0)) -atanh = lambda u: Num(math.atanh(u), d(u) / (1.0 - float(u) ** 2.0)) -radians = lambda u: Num(math.radians(u), math.radians(d(u))) -degrees = lambda u: Num(math.degrees(u), math.degrees(d(u))) -erf = lambda u: Num(math.erf(u), - 2.0 / math.sqrt(math.pi) * math.exp(-(float(u) ** 2.0)) * d(u)) -erfc = lambda u: Num(math.erfc(u), - -2.0 / math.sqrt(math.pi) * math.exp(-(float(u) ** 2.0)) * d(u)) -hypot = lambda u, v: Num(math.hypot(u, v), - (u * d(u) + v * d(v)) / math.hypot(u, v)) -fsum = lambda u: Num(math.fsum(map(float, u)), math.fsum(map(d, u))) -fabs = lambda u: abs(Num(u)) -fmod = lambda u, v: Num(u) % v -copysign = lambda u, v: Num(math.copysign(u, v), - d(u) if math.copysign(1.0, float(u) * float(v)) > 0.0 else -d(u)) -ceil = lambda u: Num(math.ceil(u), 0.0) -floor = lambda u: Num(math.floor(u), 0.0) -trunc = lambda u: Num(math.trunc(u), 0.0) -pi = Num(math.pi) -e = Num(math.e) - -## Backport Python 3 Math Module Functions ############################### - -if not hasattr(math, 'isclose'): - math.isclose = lambda x, y, rel_tol=1e-09: abs(x/y - 1.0) <= rel_tol - -if not hasattr(math, 'log2'): - math.log2 = lambda x: math.log(x) / math.log(2.0) - -## Vector Functions ###################################################### - -def partial(func, point, index): - ''' Partial derivative at a given point - - >>> func = lambda x, y: x*y + sin(x) - >>> point = (2.5, 3.5) - >>> partial(func, point, 0) # Partial with respect to x - 2.6988563844530664 - >>> partial(func, point, 1) # Partial with respect to y - 2.5 - - ''' - return d(func(*[Num(x, i==index) for i, x in enumerate(point)])) - -def gradient(func, point): - ''' Vector of the partial derivatives of a scalar field - - >>> func = lambda x, y: x*y + sin(x) - >>> point = (2.5, 3.5) - >>> gradient(func, point) - (2.6988563844530664, 2.5) - - See: https://www.wolframalpha.com/input/?lk=3&i=grad(x*y+%2B+sin(x)) - - ''' - return tuple(partial(func, point, index) for index in range(len(point))) - -def directional_derivative(func, point, direction): - ''' The dot product of the gradient and a direction vector. - Computed directly with a single function call. - - >>> func = lambda x, y: x*y + sin(x) - >>> point = (2.5, 3.5) - >>> direction = (1.5, -2.2) - >>> directional_derivative(func, point, direction) - -1.4517154233204006 - - Same result as separately computing and dotting the gradient: - >>> math.fsum(g * d for g, d in zip(gradient(func, point), direction)) - -1.4517154233204002 - - See: https://en.wikipedia.org/wiki/Directional_derivative - - ''' - return d(func(*map(Num, point, direction))) - -def divergence(F, point): - ''' Sum of the partial derivatives of a vector field - - >>> F = lambda x, y, z: (x*y+sin(x)+3*x, x-y-5*x, cos(2*x)-sin(y)**2) - >>> divergence(F, (3.5, 2.1, -3.3)) - 3.163543312709203 - - # http://www.wolframalpha.com/input/?i=div+%7Bx*y%2Bsin(x)%2B3*x,+x-y-5*x,+cos(2*x)-sin(y)%5E2%7D - >>> x, y, z = (3.5, 2.1, -3.3) - >>> math.cos(x) + y + 2 - 3.1635433127092036 - - >>> F = lambda x, y, z: (8 * exp(-x), cosh(z), - y**2) - >>> divergence(F, (2, -1, 4)) - -1.0826822658929016 - - # https://www.youtube.com/watch?v=S2rT2zK2bdo - >>> x, y, z = (2, -1, 4) - >>> -8 * math.exp(-x) - -1.0826822658929016 - - ''' - return math.fsum(d(F(*[Num(x, i==index) for i, x in enumerate(point)])[index]) - for index in range(len(point))) - -def curl(F, point): - ''' Rotation around a vector field - - >>> F = lambda x, y, z: (x*y+sin(x)+3*x, x-y-5*x, cos(2*x)-sin(y)**2) - >>> curl(F, (3.5, 2.1, -3.3)) - (0.8715757724135881, 1.3139731974375781, -7.5) - - # http://www.wolframalpha.com/input/?i=curl+%7Bx*y%2Bsin(x)%2B3*x,+x-y-5*x,+cos(2*x)-sin(y)%5E2%7D - >>> x, y, z = (3.5, 2.1, -3.3) - >>> (-2 * math.sin(y) * math.cos(y), 2 * math.sin(2 * x), -x - 4) - (0.8715757724135881, 1.3139731974375781, -7.5) - - # https://www.youtube.com/watch?v=UW4SQz29TDc - >>> F = lambda x, y, z: (y**4 - x**2 * z**2, x**2 + y**2, -x**2 * y * z) - >>> curl(F, (1, 3, -2)) - (2.0, -8.0, -106.0) - - >>> F = lambda x, y, z: (8 * exp(-x), cosh(z), - y**2) - >>> curl(F, (2, -1, 4)) - (-25.289917197127753, 0.0, 0.0) - - # https://www.youtube.com/watch?v=S2rT2zK2bdo - >>> x, y, z = (2, -1, 4) - >>> (-(x * y + math.sinh(z)), 0.0, 0.0) - (-25.289917197127753, 0.0, 0.0) - - ''' - x, y, z = point - _, Fyx, Fzx = map(d, F(Var(x), y, z)) - Fxy, _, Fzy = map(d, F(x, Var(y), z)) - Fxz, Fyz, _ = map(d, F(x, y, Var(z))) - return (Fzy - Fyz, Fxz - Fzx, Fyx - Fxy) - - -if __name__ == '__main__': - - # River flow example: https://www.youtube.com/watch?v=vvzTEbp9lrc - W = 20 # width of river in meters - C = 0.1 # max flow divided by (W/2)**2 - F = lambda x, y=0, z=0: (0.0, C * x * (W - x), 0.0) - for x in range(W+1): - print('%d --> %r' % (x, curl(F, (x, 0.0, 0.0)))) - - def numeric_derivative(func, x, eps=0.001): - 'Estimate the derivative using numerical methods' - y0 = func(x - eps) - y1 = func(x + eps) - return (y1 - y0) / (2.0 * eps) - - def test(x_array, *testcases): - for f in testcases: - print(f.__name__.center(40)) - print('-' * 40) - for x in map(Var, x_array): - y = f(x) - actual = d(y) - expected = numeric_derivative(f, x, 2**-16) - print('%7.3f %12.4f %12.4f' % (x, actual, expected)) - assert math.isclose(expected, actual, rel_tol=1e-5) - print('') - - def test_pow_const_base(x): - return 3.1 ** (2.3 * x + 0.4) - - def test_pow_const_exp(x): - return (2.3 * x + 0.4) ** (-1.3) - - def test_pow_general(x): - return (x / 3.5) ** sin(3.5 * x) - - def test_hyperbolics(x): - return 3 * cosh(1/x) + 5 * sinh(x/2.5) ** 2 - 0.7 * tanh(1.7/x) ** 1.5 - - def test_sqrt(x): - return cos(sqrt(abs(sin(x) + 5))) - - def test_conversions(x): - return degrees(x ** 1.5 + 18) * radians(0.83 ** x + 37) - - def test_hypot(x): - return hypot(sin(x), cos(1.1 / x)) - - def test_erf(x): - return (sin(x) * erf(x**0.85 - 3.123) + - cos(x) * erfc(x**0.851 - 3.25)) - - def test_rounders(x): - return (tan(x) * floor(cos(x**2 + 0.37) * 2.7) + - log(x) * ceil(cos(x**3 + 0.31) * 12.1) * 10.1 + - exp(x) * trunc(sin(x**1.4 + 8.0)) * 1234.567) - - def test_inv_trig(x): - return (atan((x - 0.303) ** 2.9 + 0.1234) + - acos((x - 4.1) / 3.113) * 5 + - asin((x - 4.3) / 3.717)) - - def test_mod(x): - return 137.1327 % (sin(x + 0.3) * 40.123) + cos(x) % 5.753 - - def test_logs(x): - return log2(fabs(sin(x))) + log10(fabs(cos(x))) + log1p(fabs(tan(x))) - - def test_fsum(x): - import random - random.seed(8675309) - data = [Num(random.random()**x, random.random()**x) for i in range(100)] - return fsum(data) - - def test_inv_hyperbolics(x): - return (acosh(x**1.1234567 + 0.89) + 3.51 * asinh(x**1.234567 + 8.9) + - atanh(x / 15.0823)) - - def test_copysign(x): - return (copysign(7.17 * x + 5.11, 1.0) + copysign(4.1 * x, 0.0) + - copysign(8.909 * x + 0.18, -0.0) + copysign(4.321 * x + .12, -1.0) + - copysign(-3.53 * x + 11.5, 1.0) + copysign(-1.4 * x + 2.1, 0.0) + - copysign(-9.089 * x + 0.813, -0.0) + copysign(-1.2347 * x, -1.0) + - copysign(sin(x), x - math.pi)) - - def test_combined(x): - return (1.7 - 3 * cos(x) ** 2 / sin(3 * x) * 0.1 * exp(+cos(x)) + - sqrt(abs(x - 4.13)) + tan(2.5 * x) * log(3.1 * x**1.5) + - (4.7 * x + 3.1) ** cos(0.43 * x + 8.1) - 2.9 + tan(-x) + - sqrt(radians(log(x) + 1.7)) + e / x + expm1(x / pi)) - - x_array = [2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5] - tests = [test_combined, test_pow_const_base, test_pow_const_exp, - test_pow_general, test_hyperbolics, test_sqrt, test_copysign, - test_inv_trig, test_conversions, test_hypot, test_rounders, - test_inv_hyperbolics, test_mod, test_logs, test_fsum, test_erf] - test(x_array, *tests) - - # Run doctests when the underlying C math library matches the one used to - # generate the code examples (the approximation algorithms vary slightly). - if 2 + math.sinh(4) == 29.289917197127753: - import doctest - print(doctest.testmod()) diff --git a/pyswarming/behaviors.py b/pyswarming/behaviors.py index 4a75f3d..af6789e 100755 --- a/pyswarming/behaviors.py +++ b/pyswarming/behaviors.py @@ -57,7 +57,7 @@ import numpy as np -from auto_differentiation import gradient +from numdifftools import Gradient def leaderless_heading_consensus(theta_i, theta_j): @@ -857,6 +857,7 @@ def geofencing(r_i, A): A : function function of the interested region. + e.g. A = lambda x: np.sqrt(x[0]+x[1]+x[2]) Returns ------- @@ -864,9 +865,11 @@ def geofencing(r_i, A): array containing contribution """ - gradA = np.asarray(gradient(A, (r_i[0],r_i[1],r_i[2]))) + gradF = Gradient(A) - g_i = - (1.0 / (1.0 + np.exp(-A(r_i[0],r_i[1],r_i[2])))) * (gradA / np.linalg.norm(gradA)) + gradA = gradF([r_i[0],r_i[1],r_i[2]]) + + g_i = - (1.0 / (1.0 + np.exp(-A([r_i[0],r_i[1],r_i[2]])))) * (gradA / np.linalg.norm(gradA)) return g_i diff --git a/setup.py b/setup.py index d01c58f..ca23245 100755 --- a/setup.py +++ b/setup.py @@ -6,12 +6,13 @@ # Packages that pyswarming uses explicitly: INSTALL_REQUIRES = [ "numpy", + "numdifftools", "matplotlib", ] setuptools.setup( name="pyswarming", - version="1.1.3", + version="1.1.4", author="Emerson Martins de Andrade", author_email="mrson@oceanica.ufrj.br", description="A research toolkit for Swarm Robotics", diff --git a/tests/test_behaviors.py b/tests/test_behaviors.py index e860e34..688953e 100755 --- a/tests/test_behaviors.py +++ b/tests/test_behaviors.py @@ -611,8 +611,7 @@ def test_geofencing_1(): s_i = 1.0 # linear speed # sphere function: used as region to be filled - def sphere(x, y, z, x0=0, y0=0, z0=0, radius=4.0): - return (x-x0)**2 + (y-y0)**2 + (z-z0)**2 - radius + sphere = lambda x: x[0]**2 + x[1]**2 + x[2]**2 - 4.0 for r_ind in range(len(r)): r_i = r[r_ind] @@ -673,8 +672,7 @@ def test_area_coverage_1(): s_i = 1.0 # linear speed # sphere function: used as region to be filled - def sphere(x, y, z, x0=0, y0=0, z0=0, radius=4.0): - return (x-x0)**2 + (y-y0)**2 + (z-z0)**2 - radius + sphere = lambda x: x[0]**2 + x[1]**2 + x[2]**2 - 4.0 for r_ind in range(len(r)): r_i = r[r_ind]