Passed
Push — master ( bf6d5c...a49e28 )
by Grega
01:20
created

CatSwarmOptimization.setParameters()   A

Complexity

Conditions 2

Size

Total Lines 19
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nop 10
dl 0
loc 19
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
# encoding=utf8
2
# pylint: disable=mixed-indentation, trailing-whitespace, multiple-statements, attribute-defined-outside-init, logging-not-lazy, no-self-use, line-too-long, arguments-differ, bad-continuation
3
import logging
4
5
import numpy as np
6
import math
7
from NiaPy.algorithms.algorithm import Algorithm
8
logging.basicConfig()
9
logger = logging.getLogger('NiaPy.algorithms.basic')
10
logger.setLevel('INFO')
11
12
__all__ = ['CatSwarmOptimization']
13
14
class CatSwarmOptimization(Algorithm):
15
    r"""Implementation of Cat swarm optimiization algorithm.
16
17
    **Algorithm:** Cat swarm optimization
18
19
    **Date:** 2019
20
21
    **Author:** Mihael Baketarić
22
23
    **License:** MIT
24
25
    **Reference paper:** Chu, Shu-Chuan & Tsai, Pei-Wei & Pan, Jeng-Shyang. (2006). Cat Swarm Optimization. 854-858. 10.1007/11801603_94.
26
    """
27
    Name = ['CatSwarmOptimization', 'CSO']
28
29 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
30
    def typeParameters(): return {
31
        'NP': lambda x: isinstance(x, int) and x > 0,
32
        'MR': lambda x: isinstance(x, (int, float)) and 0 <= x <= 1,
33
        'C1': lambda x: isinstance(x, (int, float)) and x >= 0,
34
        'SMP': lambda x: isinstance(x, int) and x > 0,
35
        'SPC': lambda x: isinstance(x, bool),
36
        'CDC': lambda x: isinstance(x, (int, float)) and 0 <= x <= 1,
37
        'SRD': lambda x: isinstance(x, (int, float)) and 0 <= x <= 1,
38
        'vMax': lambda x: isinstance(x, (int, float)) and x > 0
39
    }
40
41
    def setParameters(self, NP=30, MR=0.1, C1=2.05, SMP=3, SPC=True, CDC=0.85, SRD=0.2, vMax=1.9, **ukwargs):
42
        r"""Set the algorithm parameters.
43
44
        Arguments:
45
            NP (int): Number of individuals in population
46
            MR (float): Mixture ratio
47
            C1 (float): Constant in tracing mode
48
            SMP (int): Seeking memory pool
49
            SPC (bool): Self-position considering
50
            CDC (float): Decides how many dimensions will be varied
51
            SRD (float): Seeking range of the selected dimension
52
            vMax (float): Maximal velocity
53
54
            See Also:
55
                * :func:`NiaPy.algorithms.Algorithm.setParameters`
56
        """
57
        Algorithm.setParameters(self, NP=NP, **ukwargs)
58
        self.MR, self.C1, self.SMP, self.SPC, self.CDC, self.SRD, self.vMax = MR, C1, SMP, SPC, CDC, SRD, vMax
59
        if ukwargs: logger.info('Unused arguments: %s' % (ukwargs))
60
61
    def initPopulation(self, task):
62
        r"""Initialize population.
63
64
        Args:
65
            task (Task): Optimization task.
66
67
        Returns:
68
            Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
69
                1. Initialized population.
70
                2. Initialized populations fitness/function values.
71
                3. Additional arguments:
72
                    * Dictionary of modes (seek or trace) and velocities for each cat
73
        See Also:
74
            * :func:`NiaPy.algorithms.Algorithm.initPopulation`
75
        """
76
        pop, fpop, d = Algorithm.initPopulation(self, task)
77
        d['modes'] = self.randomSeekTrace()
78
        d['velocities'] = self.uniform(-self.vMax, self.vMax, [len(pop), task.D])
79
        return pop, fpop, d
80
81 View Code Duplication
    def repair(self, x, l, u):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
82
        r"""Repair array to range.
83
84
        Args:
85
            x (numpy.ndarray): Array to repair.
86
            l (numpy.ndarray): Lower limit of allowed range.
87
            u (numpy.ndarray): Upper limit of allowed range.
88
89
        Returns:
90
            numpy.ndarray: Repaired array.
91
        """
92
        ir = np.where(x < l)
93
        x[ir] = l[ir]
94
        ir = np.where(x > u)
95
        x[ir] = u[ir]
96
        return x
97
98
    def randomSeekTrace(self):
99
        r"""Set cats into seeking/tracing mode.
100
101
        Returns:
102
            numpy.ndarray: One or zero. One means tracing mode. Zero means seeking mode. Length of list is equal to NP.
103
        """
104
        lista = np.zeros((self.NP,), dtype=int)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable int does not seem to be defined.
Loading history...
105
        indexes = np.arange(self.NP)
106
        self.Rand.shuffle(indexes)
107
        lista[indexes[:int(self.NP * self.MR)]] = 1
108
        return lista
109
110
    def weightedSelection(self, weights):
111
        r"""Random selection considering the weights.
112
113
        Args:
114
            weights (numpy.ndarray): weight for each potential position.
115
116
        Returns:
117
            int: index of selected next position.
118
        """
119
        cumulative_sum = np.cumsum(weights)
120
        return np.argmax(cumulative_sum >= (self.rand() * cumulative_sum[-1]))
121
122
    def seekingMode(self, task, cat, fcat, pop, fpop, fxb):
123
        r"""Seeking mode.
124
125
        Args:
126
            task (Task): Optimization task.
127
            cat (numpy.ndarray): Individual from population.
128
            fcat (float): Current individual's fitness/function value.
129
            pop (numpy.ndarray): Current population.
130
            fpop (numpy.ndarray): Current population fitness/function values.
131
            fxb (float): Current best cat fitness/function value.
132
133
        Returns:
134
            Tuple[numpy.ndarray, float, numpy.ndarray, float]:
135
                1. Updated individual's position
136
                2. Updated individual's fitness/function value
137
                3. Updated global best position
138
                4. Updated global best fitness/function value
139
        """
140
        cat_copies = []
141
        cat_copies_fs = []
142
        for j in range(self.SMP - 1 if self.SPC else self.SMP):
143
            cat_copies.append(cat.copy())
144
            indexes = np.arange(task.D)
145
            self.Rand.shuffle(indexes)
146
            to_vary_indexes = indexes[:int(task.D * self.CDC)]
147
            if self.randint(2) == 1:
148
                cat_copies[j][to_vary_indexes] += cat_copies[j][to_vary_indexes] * self.SRD
149
            else:
150
                cat_copies[j][to_vary_indexes] -= cat_copies[j][to_vary_indexes] * self.SRD
151
            cat_copies[j] = task.repair(cat_copies[j])
152
            cat_copies_fs.append(task.eval(cat_copies[j]))
153
        if self.SPC:
154
            cat_copies.append(cat.copy())
155
            cat_copies_fs.append(fcat)
156
157
        cat_copies_select_probs = np.ones(len(cat_copies))
158
        fmax = np.max(cat_copies_fs)
159
        fmin = np.min(cat_copies_fs)
160
        if any(x != cat_copies_fs[0] for x in cat_copies_fs):
161
            fb = fmax
162
            if math.isinf(fb):
163
                cat_copies_select_probs = np.full(len(cat_copies), fb)
164
            else:
165
                cat_copies_select_probs = np.abs(cat_copies_fs - fb) / (fmax - fmin)
166
        if fmin < fxb:
167
            fxb = fmin
168
            ind = self.randint(self.NP, 1, 0)
169
            pop[ind] = cat_copies[np.where(cat_copies_fs == fmin)[0][0]]
170
            fpop[ind] = fmin
171
        sel_index = self.weightedSelection(cat_copies_select_probs)
172
        return cat_copies[sel_index], cat_copies_fs[sel_index], pop, fpop
173
174
    def tracingMode(self, task, cat, velocity, xb):
175
        r"""Tracing mode.
176
177
        Args:
178
            task (Task): Optimization task.
179
            cat (numpy.ndarray): Individual from population.
180
            velocity (numpy.ndarray): Velocity of individual.
181
            xb (numpy.ndarray): Current best individual.
182
        Returns:
183
            Tuple[numpy.ndarray, float, numpy.ndarray]:
184
                1. Updated individual's position
185
                2. Updated individual's fitness/function value
186
                3. Updated individual's velocity vector
187
        """
188
        Vnew = self.repair(velocity + (self.uniform(0, 1, len(velocity)) * self.C1 * (xb - cat)), np.full(task.D, -self.vMax), np.full(task.D, self.vMax))
189
        cat_new = task.repair(cat + Vnew)
190
        return cat_new, task.eval(cat_new), Vnew
191
192
    def runIteration(self, task, pop, fpop, xb, fxb, velocities, modes, **dparams):
193
        r"""Core function of Cat Swarm Optimization algorithm.
194
195
        Args:
196
            task (Task): Optimization task.
197
            pop (numpy.ndarray): Current population.
198
            fpop (numpy.ndarray): Current population fitness/function values.
199
            xb (numpy.ndarray): Current best individual.
200
            fxb (float): Current best cat fitness/function value.
201
            velocities (numpy.ndarray): Velocities of individuals.
202
            modes (numpy.ndarray): Flag of each individual.
203
            **dparams (Dict[str, Any]): Additional function arguments.
204
205
        Returns:
206
            Tuple[numpy.ndarray, numpy.ndarray[float], Dict[str, Any]]:
207
                1. New population
208
                2. New population fitness/function values
209
                3. Additional arguments:
210
                    * Dictionary of modes (seek or trace) and velocities for each cat
211
        """
212
        pop_copies = pop.copy()
213
        for k in range(len(pop_copies)):
214
            if modes[k] == 0:
215
                pop_copies[k], fpop[k], pop_copies[:], fpop[:] = self.seekingMode(task, pop_copies[k], fpop[k], pop_copies, fpop, fxb)
216
            else:  # if cat in tracing mode
217
                pop_copies[k], fpop[k], velocities[k] = self.tracingMode(task, pop_copies[k], velocities[k], xb)
218
        return pop_copies, fpop, {'velocities': velocities, 'modes': self.randomSeekTrace()}
219
220
# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3
221