Skip to content

Commit

Permalink
Merge pull request #304 from zStupan/remove_scipy_dep
Browse files Browse the repository at this point in the history
Removed scipy dependency
  • Loading branch information
firefly-cpp authored Apr 21, 2021
2 parents a32d637 + ff1317a commit ae491b4
Show file tree
Hide file tree
Showing 37 changed files with 327 additions and 393 deletions.
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ per-file-ignores =
NiaPy/tests/*:B007,D100,D101,D102,D107,D208,D211,D413,E117,E302,E701,E704,F841,S110,W191,W293,D204,RST210,E101,D204,D205,D206,E741
NiaPy/algorithms/*:B305,B007,D100,D101,D102,D107,D204,D206,D413,E101,E117,E126,E302,E305,E701,E704,E711,E741,F812,RST201,RST203,RST204,RST210,RST301,W191
NiaPy/task/*:E701
NiaPy/util/*:W191,E117,E305,E302,E704,E701,RST203,D204,E306
NiaPy/util/*:W191,E117,E305,E302,E704,E701,RST203,D204,E306,D100
NiaPy/benchmarks/*:W191,E117,E305,E302,E704,E701,RST203,D204,E306,D206,D208

22 changes: 6 additions & 16 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ Before creating bug reports, please check existing issues list as you might find

### Suggesting Enhancements
- Open new issue
- Write in details what enhancement whould you like to see in the future
- Write in details what enhancement would you like to see in the future
- If you have technical knowledge, propose solution on how to implement enhancement

### Pull requests

If you are not so familiar with Git or/and GitHub, we suggest you take a look at our [beginner's guide](.github/beginners_guide.md).

- Fill in the [reqired template](.github/pull_request_template.md)
- Fill in the [required template](.github/pull_request_template.md)
- Document new code
- Make sure all the code goes through Flake8 without problems (run ```make check``` command)
- Make sure PR builds goes through
Expand All @@ -43,11 +43,10 @@ List of NiaPy's dependencies:

| Package | Version | Platform |
| ---------- |:-------:|:--------:|
| click | Any | All |
| numpy | 1.17.0 | All |
| scipy | 1.0.0 | All |
| xlsxwriter | 1.0.2 | All |
| matplotlib | Any | All |
| matplotlib | 2.2.4 | All |
| pandas | 0.24.2 | All |
| openpyxl | 3.0.3 | All |


List of development dependencies:
Expand All @@ -65,20 +64,11 @@ List of development dependencies:
|freezegun | Any | Any |
|coverage-space | Any | Any |
|docutils | Any | Any |
|pygments | Any | Any |
|Pygments | Any | Any |
|wheel | Any | Any |
|pyinstaller | Any | Any |
|twine | Any | Any |
|sniffer | Any | Any |
|macfsevents | Any | darwin |
|enum34 | Any | Any |
|singledispatch | Any | Any |
|backports.functools-lru-cache | Any | Any |
|configparser | Any | Any |
|sphinx | Any | Any |
|sphinx-rtd-theme | Any | Any |
|funcsigs | Any | Any |
|futures | Any | Any |
|autopep8 | Any | Any |
|sphinx-autobuild | Any | Any |

Expand Down
3 changes: 0 additions & 3 deletions NiaPy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

"""Python micro framework for building nature-inspired algorithms."""

from __future__ import print_function


from NiaPy import util, algorithms, benchmarks, task
from NiaPy.runner import Runner

Expand Down
5 changes: 2 additions & 3 deletions NiaPy/algorithms/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

from numpy import random as rand, inf, ndarray, asarray, array_equal, argmin, apply_along_axis

from NiaPy.util import FesException, GenException, TimeException, RefException
from NiaPy.util.utility import objects2array
from NiaPy.util import FesException, GenException, TimeException, RefException, objects_to_array

logging.basicConfig()
logger = logging.getLogger('NiaPy.util.utility')
Expand Down Expand Up @@ -53,7 +52,7 @@ def defaultIndividualInit(task, NP, rnd=rand, itype=None, **kwargs):
1. Initialized individuals.
2. Initialized individuals function/fitness values.
"""
pop = objects2array([itype(task=task, rnd=rnd, e=True) for _ in range(NP)])
pop = objects_to_array([itype(task=task, rnd=rnd, e=True) for _ in range(NP)])
return pop, asarray([x.f for x in pop])

class Algorithm:
Expand Down
10 changes: 5 additions & 5 deletions NiaPy/algorithms/basic/ca.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from numpy import exp, random as rand, asarray

from NiaPy.algorithms.algorithm import Algorithm, Individual
from NiaPy.util.utility import objects2array
from NiaPy.util import objects_to_array

logging.basicConfig()
logger = logging.getLogger('NiaPy.algorithms.basic')
Expand Down Expand Up @@ -239,7 +239,7 @@ def initPop(self, task, NP, rnd, itype, **kwargs):
1. Initialize population of camels.
2. Initialized populations function/fitness values.
"""
caravan = objects2array([itype(E_init=self.E_init, S_init=self.S_init, task=task, rnd=rnd, e=True) for _ in range(NP)])
caravan = objects_to_array([itype(E_init=self.E_init, S_init=self.S_init, task=task, rnd=rnd, e=True) for _ in range(NP)])
return caravan, asarray([c.f for c in caravan])

def walk(self, c, cb, task):
Expand Down Expand Up @@ -324,9 +324,9 @@ def runIteration(self, task, caravan, fcaravan, cb, fcb, **dparams):
4. New global best fitness/objective value
5. Additional arguments
"""
ncaravan = objects2array([self.walk(c, cb, task) for c in caravan])
ncaravan = objects2array([self.oasis(c, self.rand(), self.alpha) for c in ncaravan])
ncaravan = objects2array([self.lifeCycle(c, self.mu, task) for c in ncaravan])
ncaravan = objects_to_array([self.walk(c, cb, task) for c in caravan])
ncaravan = objects_to_array([self.oasis(c, self.rand(), self.alpha) for c in ncaravan])
ncaravan = objects_to_array([self.lifeCycle(c, self.mu, task) for c in ncaravan])
fncaravan = asarray([c.f for c in ncaravan])
cb, fcb = self.getBest(ncaravan, fncaravan, cb, fcb)
return ncaravan, fncaravan, cb, fcb, {}
Expand Down
2 changes: 1 addition & 1 deletion NiaPy/algorithms/basic/cro.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# encoding=utf8
import logging
from scipy.spatial.distance import euclidean
from numpy import apply_along_axis, argsort, where, random as rand, asarray, delete, sqrt, sum, unique, append
from NiaPy.algorithms.algorithm import Algorithm
from NiaPy.util import euclidean

logging.basicConfig()
logger = logging.getLogger('NiaPy.algorithms.basic')
Expand Down
4 changes: 2 additions & 2 deletions NiaPy/algorithms/basic/cs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# encoding=utf8
import logging
from numpy import apply_along_axis, argsort
from scipy.stats import levy
from NiaPy.algorithms.algorithm import Algorithm
from NiaPy.util import levy_flight

logging.basicConfig()
logger = logging.getLogger('NiaPy.algorithms.basic')
Expand Down Expand Up @@ -154,7 +154,7 @@ def runIteration(self, task, pop, fpop, xb, fxb, pa_v, **dparams):
* pa_v (float): TODO
"""
i = self.randint(self.NP)
Nn = task.repair(pop[i] + self.alpha * levy.rvs(size=[task.D], random_state=self.Rand), rnd=self.Rand)
Nn = task.repair(pop[i] + levy_flight(self.alpha, size=task.D, rng=self.Rand), rnd=self.Rand)
Nn_f = task.eval(Nn)
j = self.randint(self.NP)
while i == j: j = self.randint(self.NP)
Expand Down
17 changes: 8 additions & 9 deletions NiaPy/algorithms/basic/de.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
import math

from numpy import random as rand, argmin, argmax, mean, cos, asarray, append, sin, isfinite
from scipy.spatial.distance import euclidean

from NiaPy.algorithms.algorithm import Algorithm, Individual, defaultIndividualInit
from NiaPy.util.utility import objects2array
from NiaPy.util import objects_to_array, euclidean

__all__ = ['DifferentialEvolution', 'DynNpDifferentialEvolution', 'AgingNpDifferentialEvolution', 'CrowdingDifferentialEvolution', 'MultiStrategyDifferentialEvolution', 'DynNpMultiStrategyDifferentialEvolution', 'AgingNpMultiMutationDifferentialEvolution', 'AgingIndividual', 'CrossRand1', 'CrossBest2', 'CrossBest1', 'CrossBest2', 'CrossCurr2Rand1', 'CrossCurr2Best1', 'multiMutations']

Expand Down Expand Up @@ -317,7 +316,7 @@ def evolve(self, pop, xb, task, **kwargs):
Returns:
numpy.ndarray: New evolved populations.
"""
return objects2array([self.itype(x=self.CrossMutt(pop, i, xb, self.F, self.CR, self.Rand), task=task, rnd=self.Rand, e=True) for i in range(len(pop))])
return objects_to_array([self.itype(x=self.CrossMutt(pop, i, xb, self.F, self.CR, self.Rand), task=task, rnd=self.Rand, e=True) for i in range(len(pop))])

def selection(self, pop, npop, xb, fxb, task, **kwargs):
r"""Operator for selection.
Expand All @@ -336,7 +335,7 @@ def selection(self, pop, npop, xb, fxb, task, **kwargs):
2. New global best solution.
3. New global best solutions fitness/objective value.
"""
arr = objects2array([e if e.f < pop[i].f else pop[i] for i, e in enumerate(npop)])
arr = objects_to_array([e if e.f < pop[i].f else pop[i] for i, e in enumerate(npop)])
xb, fxb = self.getBest(arr, asarray([e.f for e in arr]), xb, fxb)
return arr, xb, fxb

Expand Down Expand Up @@ -545,7 +544,7 @@ def postSelection(self, pop, task, xb, fxb, **kwargs):
"""
Gr = task.nFES // (self.pmax * len(pop)) + self.rp
nNP = len(pop) // 2
if (task.Iters + 1) == Gr and len(pop) > 3: pop = objects2array([pop[i] if pop[i].f < pop[i + nNP].f else pop[i + nNP] for i in range(nNP)])
if (task.Iters + 1) == Gr and len(pop) > 3: pop = objects_to_array([pop[i] if pop[i].f < pop[i + nNP].f else pop[i + nNP] for i in range(nNP)])
return pop, xb, fxb

def proportional(Lt_min, Lt_max, mu, x_f, avg, **args):
Expand Down Expand Up @@ -743,7 +742,7 @@ def aging(self, task, pop):
x.age += 1
Lt = round(self.age(Lt_min=self.Lt_min, Lt_max=self.Lt_max, mu=self.mu, x_f=x.f, avg=avg, x_gw=x_w.f, x_gb=x_b.f))
if x.age <= Lt: npop.append(x)
if len(npop) == 0: npop = objects2array([self.itype(task=task, rnd=self.Rand, e=True) for _ in range(self.NP)])
if len(npop) == 0: npop = objects_to_array([self.itype(task=task, rnd=self.Rand, e=True) for _ in range(self.NP)])
return npop

def popIncrement(self, pop, task):
Expand All @@ -757,7 +756,7 @@ def popIncrement(self, pop, task):
numpy.ndarray[Individual]: Increased population.
"""
deltapop = int(round(max(1, self.NP * self.deltaPopE((task.Iters + 1)))))
return objects2array([self.itype(task=task, rnd=self.Rand, e=True) for _ in range(deltapop)])
return objects_to_array([self.itype(task=task, rnd=self.Rand, e=True) for _ in range(deltapop)])

def popDecrement(self, pop, task):
r"""Decrement population.
Expand All @@ -776,7 +775,7 @@ def popDecrement(self, pop, task):
for i, e in enumerate(pop):
if i not in ni: npop.append(e)
elif self.rand() >= self.omega: npop.append(e)
return objects2array(npop)
return objects_to_array(npop)

def selection(self, pop, npop, xb, fxb, task, **kwargs):
r"""Select operator for individuals with aging.
Expand Down Expand Up @@ -929,7 +928,7 @@ def evolve(self, pop, xb, task, **kwargs):
Returns:
numpy.ndarray: New population of individuals.
"""
return objects2array([self.CrossMutt(pop, i, xb, self.F, self.CR, self.Rand, task, self.itype, self.strategies) for i in range(len(pop))])
return objects_to_array([self.CrossMutt(pop, i, xb, self.F, self.CR, self.Rand, task, self.itype, self.strategies) for i in range(len(pop))])

class DynNpMultiStrategyDifferentialEvolution(MultiStrategyDifferentialEvolution, DynNpDifferentialEvolution):
r"""Implementation of Dynamic population size Differential evolution algorithm with dynamic population size that is defined by the quality of population.
Expand Down
14 changes: 7 additions & 7 deletions NiaPy/algorithms/basic/es.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from numpy.linalg import norm, cholesky as chol, eig, solve, lstsq

from NiaPy.algorithms.algorithm import Algorithm, Individual, defaultIndividualInit
from NiaPy.util.utility import objects2array
from NiaPy.util import objects_to_array

logging.basicConfig()
logger = logging.getLogger('NiaPy.algorithms.basic')
Expand Down Expand Up @@ -175,7 +175,7 @@ def runIteration(self, task, c, fpop, xb, fxb, ki, **dparams):
* ki (int): Number of successful rho update.
"""
if (task.Iters + 1) % self.k == 0: c.rho, ki = self.updateRho(c.rho, ki), 0
cn = objects2array([task.repair(self.mutate(c.x, c.rho), self.Rand) for _i in range(self.mu)])
cn = objects_to_array([task.repair(self.mutate(c.x, c.rho), self.Rand) for _i in range(self.mu)])
cn_f = asarray([task.eval(cn[i]) for i in range(len(cn))])
ib = argmin(cn_f)
if cn_f[ib] < c.f:
Expand Down Expand Up @@ -384,9 +384,9 @@ def runIteration(self, task, c, fpop, xb, fxb, ki, **dparams):
* ki (int): Number of successful mutations.
"""
if (task.Iters + 1) % self.k == 0: _, ki = self.updateRho(c, ki), 0
cn = objects2array([IndividualES(x=self.mutateRand(c, task), task=task, rnd=self.Rand) for _ in range(self.lam)])
cn = objects_to_array([IndividualES(x=self.mutateRand(c, task), task=task, rnd=self.Rand) for _ in range(self.lam)])
cn = append(cn, c)
cn = objects2array([cn[i] for i in argsort([i.f for i in cn])[:self.mu]])
cn = objects_to_array([cn[i] for i in argsort([i.f for i in cn])[:self.mu]])
ki += self.changeCount(c, cn)
fcn = asarray([x.f for x in cn])
xb, fxb = self.getBest(cn, fcn, xb, fxb)
Expand Down Expand Up @@ -441,10 +441,10 @@ def newPop(self, pop):
numpy.ndarray: New population.
"""
pop_s = argsort([i.f for i in pop])
if self.mu < self.lam: return objects2array([pop[i] for i in pop_s[:self.mu]])
if self.mu < self.lam: return objects_to_array([pop[i] for i in pop_s[:self.mu]])
npop = list()
for i in range(int(ceil(float(self.mu) / self.lam))): npop.extend(pop[:self.lam if (self.mu - i * self.lam) >= self.lam else self.mu - i * self.lam])
return objects2array(npop)
return objects_to_array(npop)

def initPopulation(self, task):
r"""Initialize starting population.
Expand Down Expand Up @@ -483,7 +483,7 @@ def runIteration(self, task, c, fpop, xb, fxb, **dparams):
4. New global best solutions fitness/objective value.
5. Additional arguments.
"""
cn = objects2array([IndividualES(x=self.mutateRand(c, task), task=task, rand=self.Rand) for _ in range(self.lam)])
cn = objects_to_array([IndividualES(x=self.mutateRand(c, task), task=task, rand=self.Rand) for _ in range(self.lam)])
c = self.newPop(cn)
fc = asarray([x.f for x in c])
xb, fxb = self.getBest(c, fc, xb, fxb)
Expand Down
4 changes: 2 additions & 2 deletions NiaPy/algorithms/basic/foa.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
from numpy import where, apply_along_axis, zeros, append, ndarray, delete, arange, argmin, absolute, int32
from NiaPy.algorithms.algorithm import Algorithm
from NiaPy.util import limit_repair
from NiaPy.util import repair

__all__ = ['ForestOptimizationAlgorithm']

Expand Down Expand Up @@ -131,7 +131,7 @@ def localSeeding(self, task, trees):
perms = self.rand([deltas.shape[0], deltas.shape[1]]).argsort(1)
deltas = deltas[arange(deltas.shape[0])[:, None], perms]
trees += deltas
trees = apply_along_axis(limit_repair, 1, trees, task.Lower, task.Upper)
trees = apply_along_axis(repair.limit, 1, trees, task.Lower, task.Upper)
return trees

def globalSeeding(self, task, candidates, size):
Expand Down
15 changes: 3 additions & 12 deletions NiaPy/algorithms/basic/fpa.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# encoding=utf8
import logging

from scipy.special import gamma as Gamma
from numpy import where, sin, fabs, pi, zeros
from numpy import where, zeros

from NiaPy.algorithms.algorithm import Algorithm
from NiaPy.util import levy_flight

logging.basicConfig()
logger = logging.getLogger('NiaPy.algorithms.basic')
Expand Down Expand Up @@ -105,15 +105,6 @@ def repair(self, x, task):
x[ir] = task.Lower[ir] + x[ir] % task.bRange[ir]
return x

def levy(self, D):
r"""Levy function.
Returns:
float: Next Levy number.
"""
sigma = (Gamma(1 + self.beta) * sin(pi * self.beta / 2) / (Gamma((1 + self.beta) / 2) * self.beta * 2 ** ((self.beta - 1) / 2))) ** (1 / self.beta)
return 0.01 * (self.normal(0, 1, D) * sigma / fabs(self.normal(0, 1, D)) ** (1 / self.beta))

def initPopulation(self, task):
pop, fpop, d = Algorithm.initPopulation(self, task)
d.update({'S': zeros((self.NP, task.D))})
Expand All @@ -139,7 +130,7 @@ def runIteration(self, task, Sol, Sol_f, xb, fxb, S, **dparams):
5. Additional arguments.
"""
for i in range(self.NP):
if self.uniform(0, 1) > self.p: S[i] += self.levy(task.D) * (Sol[i] - xb)
if self.uniform(0, 1) > self.p: S[i] += levy_flight(beta=self.beta, size=task.D, rng=self.Rand) * (Sol[i] - xb)
else:
JK = self.Rand.permutation(self.NP)
S[i] += self.uniform(0, 1) * (Sol[JK[0]] - Sol[JK[1]])
Expand Down
4 changes: 2 additions & 2 deletions NiaPy/algorithms/basic/fss.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# encoding=utf8
from numpy import nan, asarray, zeros, full

from NiaPy.util.utility import objects2array
from NiaPy.util import objects_to_array
from NiaPy.algorithms.algorithm import Algorithm, Individual

class Fish(Individual):
Expand Down Expand Up @@ -170,7 +170,7 @@ def init_school(self, task):
school.append(fish)
curr_weight_school += fish.weight
prev_weight_school = curr_weight_school
return curr_step_individual, curr_step_volitive, curr_weight_school, prev_weight_school, objects2array(school)
return curr_step_individual, curr_step_volitive, curr_weight_school, prev_weight_school, objects_to_array(school)

def max_delta_cost(self, school):
r"""Find maximum delta cost - return 0 if none of the fishes moved.
Expand Down
6 changes: 3 additions & 3 deletions NiaPy/algorithms/basic/fwa.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
from numpy import apply_along_axis, argmin, argmax, sum, sqrt, round, argsort, fabs, asarray, where
from NiaPy.algorithms.algorithm import Algorithm
from NiaPy.util import fullArray
from NiaPy.util import full_array

logging.basicConfig()
logger = logging.getLogger('NiaPy.algorithms.basic')
Expand Down Expand Up @@ -185,7 +185,7 @@ def initAmplitude(self, task):
Returns:
numpy.ndarray[float]: Starting amplitudes.
"""
return fullArray(self.A, task.D)
return full_array(self.A, task.D)

def SparsksNo(self, x_f, xw_f, Ss):
r"""Calculate number of sparks based on function value of individual.
Expand Down Expand Up @@ -446,7 +446,7 @@ def initRanges(self, task):
2. Final amplitude values over dimensions.
3. uAmin.
"""
Ainit, Afinal = fullArray(self.Ainit, task.D), fullArray(self.Afinal, task.D)
Ainit, Afinal = full_array(self.Ainit, task.D), full_array(self.Afinal, task.D)
return Ainit, Afinal, self.uAmin(Ainit, Afinal, task)

def uAmin(self, Ainit, Afinal, task):
Expand Down
2 changes: 1 addition & 1 deletion NiaPy/algorithms/basic/gso.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# encoding=utf8
import logging

from scipy.spatial.distance import euclidean
from numpy import full, apply_along_axis, copy, sum, fmax, pi, where

from NiaPy.algorithms.algorithm import Algorithm
from NiaPy.util import euclidean

logging.basicConfig()
logger = logging.getLogger('NiaPy.algorithms.basic')
Expand Down
Loading

0 comments on commit ae491b4

Please sign in to comment.