hsyncnet.py
1 """!
2 
3 @brief Cluster analysis algorithm: Hierarchical Sync (HSyncNet)
4 @details Implementation based on paper @cite artcile::hsyncnet::1.
5 
6 @authors Andrei Novikov (pyclustering@yandex.ru)
7 @date 2014-2020
8 @copyright GNU Public License
9 
10 @cond GNU_PUBLIC_LICENSE
11  PyClustering is free software: you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  PyClustering is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  GNU General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program. If not, see <http://www.gnu.org/licenses/>.
23 @endcond
24 
25 """
26 
27 import pyclustering.core.hsyncnet_wrapper as wrapper
28 
29 from pyclustering.core.wrapper import ccore_library
30 
31 from pyclustering.nnet import initial_type, solve_type
32 
33 from pyclustering.cluster.syncnet import syncnet, syncnet_analyser
34 
35 from pyclustering.utils import average_neighbor_distance
36 
37 
39  """!
40  @brief Class represents clustering algorithm HSyncNet. HSyncNet is bio-inspired algorithm that is based on oscillatory network that uses modified Kuramoto model.
41 
42  Example:
43  @code
44  from pyclustering.cluster.hsyncnet import hsyncnet
45  from pyclustering.nnet.sync import sync_visualizer
46  from pyclustering.utils import read_sample, draw_clusters
47  from pyclustering.samples.definitions import SIMPLE_SAMPLES
48 
49  # Read list of points for cluster analysis.
50  sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2)
51 
52  # Create network for allocation of three clusters.
53  network = hsyncnet(sample, 3)
54 
55  # Run cluster analysis and output dynamic of the network.
56  analyser = network.process(0.995, collect_dynamic=True)
57 
58  # Get allocated clusters.
59  clusters = analyser.allocate_clusters(eps=0.1)
60 
61  # Show output dynamic of the network.
62  sync_visualizer.show_output_dynamic(analyser)
63 
64  # Show allocated clusters.
65  draw_clusters(sample, clusters)
66  @endcode
67  """
68 
69  def __init__(self, source_data, number_clusters, osc_initial_phases=initial_type.RANDOM_GAUSSIAN,
70  initial_neighbors=3, increase_persent=0.15, ccore=True):
71  """!
72  @brief Costructor of the oscillatory network hSyncNet for cluster analysis.
73 
74  @param[in] source_data (list): Input data set defines structure of the network.
75  @param[in] number_clusters (uint): Number of clusters that should be allocated.
76  @param[in] osc_initial_phases (initial_type): Type of initialization of initial values of phases of oscillators.
77  @param[in] initial_neighbors (uint): Defines initial connectivity-radius by average distance to connect specified amount of oscillators (points).
78  @param[in] increase_persent (double): Percent of increasing of radius connectivity on each iteration (input values in range (0.0; 1.0) correspond to (0%; 100%)).
79  @param[in] ccore (bool): If True than DLL CCORE (C++ solution) will be used for solving.
80 
81  """
82 
83  self.__ccore_network_pointer = None
84 
85  if initial_neighbors >= len(source_data):
86  initial_neighbors = len(source_data) - 1
87 
88  if (ccore is True) and ccore_library.workable():
89  self.__ccore_network_pointer = wrapper.hsyncnet_create_network(source_data, number_clusters,
90  osc_initial_phases, initial_neighbors,
91  increase_persent)
92  else:
93  super().__init__(source_data, 0, initial_phases=osc_initial_phases, ccore=False)
94 
95  self.__initial_neighbors = initial_neighbors
96  self.__increase_persent = increase_persent
97  self._number_clusters = number_clusters
98 
99  def __del__(self):
100  """!
101  @brief Destructor of oscillatory network HSyncNet.
102 
103  """
104 
105  if self.__ccore_network_pointer is not None:
106  wrapper.hsyncnet_destroy_network(self.__ccore_network_pointer)
107  self.__ccore_network_pointer = None
108 
109  def process(self, order=0.998, solution=solve_type.FAST, collect_dynamic=False):
110  """!
111  @brief Performs clustering of input data set in line with input parameters.
112 
113  @param[in] order (double): Level of local synchronization between oscillator that defines end of synchronization process, range [0..1].
114  @param[in] solution (solve_type) Type of solving differential equation.
115  @param[in] collect_dynamic (bool): If True - returns whole history of process synchronization otherwise - only final state (when process of clustering is over).
116 
117  @return (tuple) Returns dynamic of the network as tuple of lists on each iteration (time, oscillator_phases) that depends on collect_dynamic parameter.
118 
119  @see get_clusters()
120 
121  """
122 
123  if self.__ccore_network_pointer is not None:
124  analyser = wrapper.hsyncnet_process(self.__ccore_network_pointer, order, solution, collect_dynamic)
125  return syncnet_analyser(None, None, analyser)
126 
127  number_neighbors = self.__initial_neighbors
128  current_number_clusters = float('inf')
129 
130  dyn_phase = []
131  dyn_time = []
132 
133  radius = average_neighbor_distance(self._osc_loc, number_neighbors)
134 
135  increase_step = int(len(self._osc_loc) * self.__increase_persent)
136  if increase_step < 1:
137  increase_step = 1
138 
139  analyser = None
140  while current_number_clusters > self._number_clusters:
141  self._create_connections(radius)
142 
143  analyser = self.simulate_dynamic(order, solution, collect_dynamic)
144  if collect_dynamic:
145  if len(dyn_phase) == 0:
146  self.__store_dynamic(dyn_phase, dyn_time, analyser, True)
147 
148  self.__store_dynamic(dyn_phase, dyn_time, analyser, False)
149 
150  clusters = analyser.allocate_sync_ensembles(0.05)
151 
152  # Get current number of allocated clusters
153  current_number_clusters = len(clusters)
154 
155  # Increase number of neighbors that should be used
156  number_neighbors += increase_step
157 
158  # Update connectivity radius and check if average function can be used anymore
159  radius = self.__calculate_radius(number_neighbors, radius)
160 
161  if not collect_dynamic:
162  self.__store_dynamic(dyn_phase, dyn_time, analyser, False)
163 
164  return syncnet_analyser(dyn_phase, dyn_time, None)
165 
166  def __calculate_radius(self, number_neighbors, radius):
167  """!
168  @brief Calculate new connectivity radius.
169 
170  @param[in] number_neighbors (uint): Average amount of neighbors that should be connected by new radius.
171  @param[in] radius (double): Current connectivity radius.
172 
173  @return New connectivity radius.
174 
175  """
176 
177  if number_neighbors >= len(self._osc_loc):
178  return radius * self.__increase_persent + radius
179 
180  return average_neighbor_distance(self._osc_loc, number_neighbors)
181 
182  def __store_dynamic(self, dyn_phase, dyn_time, analyser, begin_state):
183  """!
184  @brief Store specified state of Sync network to hSync.
185 
186  @param[in] dyn_phase (list): Output dynamic of hSync where state should be stored.
187  @param[in] dyn_time (list): Time points that correspond to output dynamic where new time point should be stored.
188  @param[in] analyser (syncnet_analyser): Sync analyser where Sync states are stored.
189  @param[in] begin_state (bool): If True the first state of Sync network is stored, otherwise the last state is stored.
190 
191  """
192 
193  if begin_state is True:
194  dyn_time.append(0)
195  dyn_phase.append(analyser.output[0])
196 
197  else:
198  dyn_phase.append(analyser.output[len(analyser.output) - 1])
199  dyn_time.append(len(dyn_time))
def simulate_dynamic(self, order=0.998, solution=solve_type.FAST, collect_dynamic=False, step=0.1, int_step=0.01, threshold_changes=0.0000001)
Performs dynamic simulation of the network until stop condition is not reached.
Definition: sync.py:871
def __del__(self)
Destructor of oscillatory network HSyncNet.
Definition: hsyncnet.py:99
Utils that are used by modules of pyclustering.
Definition: __init__.py:1
Performs analysis of output dynamic of the oscillatory network syncnet to extract information about c...
Definition: syncnet.py:50
def __init__(self, source_data, number_clusters, osc_initial_phases=initial_type.RANDOM_GAUSSIAN, initial_neighbors=3, increase_persent=0.15, ccore=True)
Costructor of the oscillatory network hSyncNet for cluster analysis.
Definition: hsyncnet.py:70
Class represents clustering algorithm SyncNet.
Definition: syncnet.py:166
def __calculate_radius(self, number_neighbors, radius)
Calculate new connectivity radius.
Definition: hsyncnet.py:166
def __store_dynamic(self, dyn_phase, dyn_time, analyser, begin_state)
Store specified state of Sync network to hSync.
Definition: hsyncnet.py:182
def process(self, order=0.998, solution=solve_type.FAST, collect_dynamic=False)
Performs clustering of input data set in line with input parameters.
Definition: hsyncnet.py:109
Class represents clustering algorithm HSyncNet.
Definition: hsyncnet.py:38
Cluster analysis algorithm: Sync.
Definition: syncnet.py:1
Neural and oscillatory network module.
Definition: __init__.py:1
def _create_connections(self, radius)
Create connections between oscillators in line with input radius of connectivity. ...
Definition: syncnet.py:261