| Total Complexity | 40 |
| Total Lines | 325 |
| Duplicated Lines | 0 % |
Complex classes like syncpr often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | """! |
||
| 138 | class syncpr(sync_network): |
||
| 139 | """! |
||
| 140 | @brief Model of phase oscillatory network for pattern recognition that is based on the Kuramoto model. |
||
| 141 | @details The model uses second-order and third-order modes of the Fourier components. |
||
| 142 | |||
| 143 | Example: |
||
| 144 | @code |
||
| 145 | # Network size should be equal to size of pattern for learning. |
||
| 146 | net = syncpr(size_network, 0.3, 0.3); |
||
| 147 | |||
| 148 | # Train network using list of patterns (input images). |
||
| 149 | net.train(image_samples); |
||
| 150 | |||
| 151 | # Recognize image using 10 steps during 10 seconds of simulation. |
||
| 152 | sync_output_dynamic = net.simulate(10, 10, pattern, solve_type.RK4, True); |
||
| 153 | |||
| 154 | # Display output dynamic. |
||
| 155 | syncpr_visualizer.show_output_dynamic(sync_output_dynamic); |
||
| 156 | |||
| 157 | # Display evolution of recognition of the pattern. |
||
| 158 | syncpr_visualizer.show_pattern(sync_output_dynamic, image_height, image_width); |
||
| 159 | |||
| 160 | @endcode |
||
| 161 | |||
| 162 | """ |
||
| 163 | |||
| 164 | _increase_strength1 = 0.0; |
||
| 165 | _increase_strength2 = 0.0; |
||
| 166 | _coupling = None; |
||
| 167 | |||
| 168 | def __init__(self, num_osc, increase_strength1, increase_strength2, ccore = False): |
||
| 169 | """! |
||
| 170 | @brief Constructor of oscillatory network for pattern recognition based on Kuramoto model. |
||
| 171 | |||
| 172 | @param[in] num_osc (uint): Number of oscillators in the network. |
||
| 173 | @param[in] increase_strength1 (double): Parameter for increasing strength of the second term of the Fourier component. |
||
| 174 | @param[in] increase_strength2 (double): Parameter for increasing strength of the third term of the Fourier component. |
||
| 175 | @param[in] ccore (bool): If True simulation is performed by CCORE library (C++ implementation of pyclustering). |
||
| 176 | |||
| 177 | """ |
||
| 178 | |||
| 179 | if (ccore is True): |
||
| 180 | self._ccore_network_pointer = wrapper.syncpr_create(num_osc, increase_strength1, increase_strength2); |
||
| 181 | |||
| 182 | else: |
||
| 183 | self._increase_strength1 = increase_strength1; |
||
| 184 | self._increase_strength2 = increase_strength2; |
||
| 185 | self._coupling = [ [0.0 for i in range(num_osc)] for j in range(num_osc) ]; |
||
| 186 | |||
| 187 | super().__init__(num_osc, 1, 0, conn_type.ALL_TO_ALL, initial_type.RANDOM_GAUSSIAN); |
||
| 188 | |||
| 189 | |||
| 190 | def __del__(self): |
||
| 191 | """! |
||
| 192 | @brief Default destructor of syncpr. |
||
| 193 | |||
| 194 | """ |
||
| 195 | |||
| 196 | if (self._ccore_network_pointer is not None): |
||
| 197 | wrapper.syncpr_destroy(self._ccore_network_pointer); |
||
| 198 | self._ccore_network_pointer = None; |
||
| 199 | |||
| 200 | |||
| 201 | def __len__(self): |
||
| 202 | """! |
||
| 203 | @brief Returns size of the network. |
||
| 204 | |||
| 205 | """ |
||
| 206 | if (self._ccore_network_pointer is not None): |
||
| 207 | return wrapper.syncpr_get_size(self._ccore_network_pointer); |
||
| 208 | |||
| 209 | else: |
||
| 210 | return self._num_osc; |
||
| 211 | |||
| 212 | |||
| 213 | def train(self, samples): |
||
| 214 | """! |
||
| 215 | @brief Trains syncpr network using Hebbian rule for adjusting strength of connections between oscillators during training. |
||
| 216 | |||
| 217 | @param[in] samples (list): list of patterns where each pattern is represented by list of features that are equal to [-1; 1]. |
||
| 218 | |||
| 219 | """ |
||
| 220 | |||
| 221 | # Verify pattern for learning |
||
| 222 | for pattern in samples: |
||
| 223 | self.__validate_pattern(pattern); |
||
| 224 | |||
| 225 | if (self._ccore_network_pointer is not None): |
||
| 226 | return wrapper.syncpr_train(self._ccore_network_pointer, samples); |
||
| 227 | |||
| 228 | length = len(self); |
||
| 229 | number_samples = len(samples); |
||
| 230 | |||
| 231 | for i in range(length): |
||
| 232 | for j in range(i + 1, len(self), 1): |
||
| 233 | |||
| 234 | # go through via all patterns |
||
| 235 | for p in range(number_samples): |
||
| 236 | value1 = samples[p][i]; |
||
| 237 | value2 = samples[p][j]; |
||
| 238 | |||
| 239 | self._coupling[i][j] += value1 * value2; |
||
| 240 | |||
| 241 | self._coupling[i][j] /= length; |
||
| 242 | self._coupling[j][i] = self._coupling[i][j]; |
||
| 243 | |||
| 244 | |||
| 245 | def simulate(self, steps, time, pattern, solution = solve_type.RK4, collect_dynamic = True): |
||
| 246 | """! |
||
| 247 | @brief Performs static simulation of syncpr oscillatory network. |
||
| 248 | @details In other words network performs pattern recognition during simulation. |
||
| 249 | |||
| 250 | @param[in] steps (uint): Number steps of simulations during simulation. |
||
| 251 | @param[in] time (double): Time of simulation. |
||
| 252 | @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. |
||
| 253 | @param[in] solution (solve_type): Type of solver that should be used for simulation. |
||
| 254 | @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. |
||
| 255 | |||
| 256 | @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, |
||
| 257 | otherwise returns only last values (last step of simulation) of dynamic. |
||
| 258 | |||
| 259 | @see simulate_dynamic() |
||
| 260 | @see simulate_static() |
||
| 261 | |||
| 262 | """ |
||
| 263 | |||
| 264 | return self.simulate_static(steps, time, pattern, solution, collect_dynamic); |
||
| 265 | |||
| 266 | |||
| 267 | def simulate_dynamic(self, pattern, order = 0.998, solution = solve_type.FAST, collect_dynamic = False, step = 0.1, int_step = 0.01, threshold_changes = 0.0000001): |
||
| 268 | """! |
||
| 269 | @brief Performs dynamic simulation of the network until stop condition is not reached. |
||
| 270 | @details In other words network performs pattern recognition during simulation. |
||
| 271 | Stop condition is defined by input argument 'order' that represents memory order, but |
||
| 272 | process of simulation can be stopped if convergance rate is low whose threshold is defined |
||
| 273 | by the argument 'threshold_changes'. |
||
| 274 | |||
| 275 | @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. |
||
| 276 | @param[in] order (double): Order of process synchronization, distributed 0..1. |
||
| 277 | @param[in] solution (solve_type): Type of solution. |
||
| 278 | @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. |
||
| 279 | @param[in] step (double): Time step of one iteration of simulation. |
||
| 280 | @param[in] int_step (double): Integration step, should be less than step. |
||
| 281 | @param[in] threshold_changes (double): Additional stop condition that helps prevent infinite simulation, defines limit of changes of oscillators between current and previous steps. |
||
| 282 | |||
| 283 | @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, |
||
| 284 | otherwise returns only last values (last step of simulation) of dynamic. |
||
| 285 | |||
| 286 | @see simulate() |
||
| 287 | @see simulate_static() |
||
| 288 | |||
| 289 | """ |
||
| 290 | |||
| 291 | self.__validate_pattern(pattern); |
||
| 292 | |||
| 293 | if (self._ccore_network_pointer is not None): |
||
| 294 | ccore_instance_dynamic = wrapper.syncpr_simulate_dynamic(self._ccore_network_pointer, pattern, order, solution, collect_dynamic, step); |
||
| 295 | return syncpr_dynamic(None, None, ccore_instance_dynamic); |
||
| 296 | |||
| 297 | for i in range(0, len(pattern), 1): |
||
| 298 | if (pattern[i] > 0.0): |
||
| 299 | self._phases[i] = 0.0; |
||
| 300 | else: |
||
| 301 | self._phases[i] = math.pi / 2.0; |
||
| 302 | |||
| 303 | # For statistics and integration |
||
| 304 | time_counter = 0; |
||
| 305 | |||
| 306 | # Prevent infinite loop. It's possible when required state cannot be reached. |
||
| 307 | previous_order = 0; |
||
| 308 | current_order = self.__calculate_memory_order(pattern); |
||
| 309 | |||
| 310 | # If requested input dynamics |
||
| 311 | dyn_phase = []; |
||
| 312 | dyn_time = []; |
||
| 313 | if (collect_dynamic == True): |
||
| 314 | dyn_phase.append(self._phases); |
||
| 315 | dyn_time.append(0); |
||
| 316 | |||
| 317 | # Execute until sync state will be reached |
||
| 318 | while (current_order < order): |
||
| 319 | # update states of oscillators |
||
| 320 | self._phases = self._calculate_phases(solution, time_counter, step, int_step); |
||
| 321 | |||
| 322 | # update time |
||
| 323 | time_counter += step; |
||
| 324 | |||
| 325 | # if requested input dynamic |
||
| 326 | if (collect_dynamic == True): |
||
| 327 | dyn_phase.append(self._phases); |
||
| 328 | dyn_time.append(time_counter); |
||
| 329 | |||
| 330 | # update orders |
||
| 331 | previous_order = current_order; |
||
| 332 | current_order = self.__calculate_memory_order(pattern); |
||
| 333 | |||
| 334 | # hang prevention |
||
| 335 | if (abs(current_order - previous_order) < threshold_changes): |
||
| 336 | break; |
||
| 337 | |||
| 338 | if (collect_dynamic != True): |
||
| 339 | dyn_phase.append(self._phases); |
||
| 340 | dyn_time.append(time_counter); |
||
| 341 | |||
| 342 | output_sync_dynamic = syncpr_dynamic(dyn_phase, dyn_time, None); |
||
| 343 | return output_sync_dynamic; |
||
| 344 | |||
| 345 | |||
| 346 | def simulate_static(self, steps, time, pattern, solution = solve_type.FAST, collect_dynamic = False): |
||
| 347 | """! |
||
| 348 | @brief Performs static simulation of syncpr oscillatory network. |
||
| 349 | @details In other words network performs pattern recognition during simulation. |
||
| 350 | |||
| 351 | @param[in] steps (uint): Number steps of simulations during simulation. |
||
| 352 | @param[in] time (double): Time of simulation. |
||
| 353 | @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. |
||
| 354 | @param[in] solution (solve_type): Type of solution. |
||
| 355 | @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. |
||
| 356 | |||
| 357 | @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, |
||
| 358 | otherwise returns only last values (last step of simulation) of dynamic. |
||
| 359 | |||
| 360 | @see simulate() |
||
| 361 | @see simulate_dynamic() |
||
| 362 | |||
| 363 | """ |
||
| 364 | |||
| 365 | self.__validate_pattern(pattern); |
||
| 366 | |||
| 367 | if (self._ccore_network_pointer is not None): |
||
| 368 | ccore_instance_dynamic = wrapper.syncpr_simulate_static(self._ccore_network_pointer, steps, time, pattern, solution, collect_dynamic); |
||
| 369 | return syncpr_dynamic(None, None, ccore_instance_dynamic); |
||
| 370 | |||
| 371 | for i in range(0, len(pattern), 1): |
||
| 372 | if (pattern[i] > 0.0): |
||
| 373 | self._phases[i] = 0.0; |
||
| 374 | else: |
||
| 375 | self._phases[i] = math.pi / 2.0; |
||
| 376 | |||
| 377 | return super().simulate_static(steps, time, solution, collect_dynamic); |
||
| 378 | |||
| 379 | |||
| 380 | def memory_order(self, pattern): |
||
| 381 | """! |
||
| 382 | @brief Calculates function of the memorized pattern. |
||
| 383 | @details Throws exception if length of pattern is not equal to size of the network or if it consists feature with value that are not equal to [-1; 1]. |
||
| 384 | |||
| 385 | @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. |
||
| 386 | |||
| 387 | @return (double) Order of memory for the specified pattern. |
||
| 388 | |||
| 389 | """ |
||
| 390 | |||
| 391 | self.__validate_pattern(pattern); |
||
| 392 | |||
| 393 | if (self._ccore_network_pointer is not None): |
||
| 394 | return wrapper.syncpr_memory_order(self._ccore_network_pointer, pattern); |
||
| 395 | |||
| 396 | else: |
||
| 397 | return self.__calculate_memory_order(pattern); |
||
| 398 | |||
| 399 | |||
| 400 | def __calculate_memory_order(self, pattern): |
||
| 401 | """! |
||
| 402 | @brief Calculates function of the memorized pattern without any pattern validation. |
||
| 403 | |||
| 404 | @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. |
||
| 405 | |||
| 406 | @return (double) Order of memory for the specified pattern. |
||
| 407 | |||
| 408 | """ |
||
| 409 | |||
| 410 | memory_order = 0.0; |
||
| 411 | for index in range(len(self)): |
||
| 412 | memory_order += pattern[index] * cmath.exp( 1j * self._phases[index] ); |
||
| 413 | |||
| 414 | memory_order /= len(self); |
||
| 415 | return abs(memory_order); |
||
| 416 | |||
| 417 | |||
| 418 | def _phase_kuramoto(self, teta, t, argv): |
||
| 419 | """! |
||
| 420 | @brief Returns result of phase calculation for specified oscillator in the network. |
||
| 421 | |||
| 422 | @param[in] teta (double): Phase of the oscillator that is differentiated. |
||
| 423 | @param[in] t (double): Current time of simulation. |
||
| 424 | @param[in] argv (tuple): Index of the oscillator in the list. |
||
| 425 | |||
| 426 | @return (double) New phase for specified oscillator (don't assign it here). |
||
| 427 | |||
| 428 | """ |
||
| 429 | |||
| 430 | index = argv; |
||
| 431 | |||
| 432 | phase = 0.0; |
||
| 433 | term = 0.0; |
||
| 434 | |||
| 435 | for k in range(0, self._num_osc): |
||
| 436 | if (k != index): |
||
| 437 | phase_delta = self._phases[k] - teta; |
||
| 438 | |||
| 439 | phase += self._coupling[index][k] * math.sin(phase_delta); |
||
| 440 | |||
| 441 | term1 = self._increase_strength1 * math.sin(2.0 * phase_delta); |
||
| 442 | term2 = self._increase_strength2 * math.sin(3.0 * phase_delta); |
||
| 443 | |||
| 444 | term += (term1 - term2); |
||
| 445 | |||
| 446 | return ( phase + term / len(self) ); |
||
| 447 | |||
| 448 | |||
| 449 | def __validate_pattern(self, pattern): |
||
| 450 | """! |
||
| 451 | @brief Validates pattern. |
||
| 452 | @details Throws exception if length of pattern is not equal to size of the network or if it consists feature with value that are not equal to [-1; 1]. |
||
| 453 | |||
| 454 | @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. |
||
| 455 | |||
| 456 | """ |
||
| 457 | if (len(pattern) != len(self)): |
||
| 458 | raise NameError('syncpr: length of the pattern (' + len(pattern) + ') should be equal to size of the network'); |
||
| 459 | |||
| 460 | for feature in pattern: |
||
| 461 | if ( (feature != -1.0) and (feature != 1.0) ): |
||
| 462 | raise NameError('syncpr: patten feature (' + feature + ') should be distributed in [-1; 1]'); |
This can be caused by one of the following:
1. Missing Dependencies
This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.
2. Missing __init__.py files
This error could also result from missing
__init__.pyfiles in your module folders. Make sure that you place one file in each sub-folder.