Instruction:
How would you implement a function in Python 3 that
processes the graph and return the coloring information.

Response:
def process(self):
        """!
        @brief Perform graph coloring using DSATUR algorithm.

        @see get_colors()

        """
        color_counter = 1;

        degrees = list();
        saturation_degrees = [0] * len(self.__data_pointer);

        self.__coloring = [0] * len(self.__data_pointer);
        uncolored_vertices = set(range(len(self.__data_pointer)));

        index_maximum_degree = 0;
        maximum_degree = 0;
        for index_node in range(len(self.__data_pointer)):
            # Fill degree of nodes in the input graph
            degrees.append( ( sum(self.__data_pointer[index_node]), index_node ) );

            # And find node with maximal degree at the same time.
            if (degrees[index_node][0] > maximum_degree):
                (maximum_degree, node_index) = degrees[index_node];
                index_maximum_degree = index_node;

        # Update saturation
        neighbors = self.__get_neighbors(index_maximum_degree);
        for index_neighbor in neighbors:
            saturation_degrees[index_neighbor] += 1;

        # Coloring the first node
        self.__coloring[index_maximum_degree] = color_counter;
        uncolored_vertices.remove(index_maximum_degree);

        while(len(uncolored_vertices) > 0):
            # Get maximum saturation degree
            maximum_satur_degree = -1;
            for index in uncolored_vertices:
                if (saturation_degrees[index] > maximum_satur_degree):
                    maximum_satur_degree = saturation_degrees[index];

            # Get list of indexes with maximum saturation degree
            indexes_maximum_satur_degree = [index for index in uncolored_vertices if saturation_degrees[index] == maximum_satur_degree];

            coloring_index = indexes_maximum_satur_degree[0];
            if (len(indexes_maximum_satur_degree) > 1): # There are more then one node with maximum saturation
                # Find node with maximum degree
                maximum_degree = -1;
                for index in indexes_maximum_satur_degree:
                    (degree, node_index) = degrees[index];
                    if (degree > maximum_degree):
                        coloring_index = node_index;
                        maximum_degree = degree;

            # Coloring
            node_index_neighbors = self.__get_neighbors(coloring_index);
            for number_color in range(1, color_counter + 1, 1):
                if (self.__get_amount_color(node_index_neighbors, number_color) == 0):
                    self.__coloring[coloring_index] = number_color;
                    break;

            # If it has not been colored then
            if (self.__coloring[coloring_index] == 0):
                color_counter += 1;     # Add new color
                self.__coloring[coloring_index] = color_counter;

            # Remove node from uncolored set
            uncolored_vertices.remove(coloring_index);

            # Update degree of saturation
            for index_neighbor in node_index_neighbors:
                subneighbors = self.__get_neighbors(index_neighbor);

                if (self.__get_amount_color(subneighbors, self.__coloring[coloring_index]) == 1):
                    saturation_degrees[index_neighbor] += 1;


Instruction:
Here you have a function in Python 3, explain what it does
def __get_amount_color(self, node_indexes, color_number):

        color_counter = 0;
        for index in node_indexes:
            if (self.__coloring[index] == color_number):
                color_counter += 1;

        return color_counter;

Response: Counts how many nodes have color color_number.


Instruction:
Write a Python 3 script for
returning the indexes of neighbors of the specified node.

Response:
def __get_neighbors(self, node_index):
        """!
        @brief Returns indexes of neighbors of the specified node.

        @param[in] node_index (uint):

        @return (list) Neighbors of the specified node.

        """

        return [ index for index in range(len(self.__data_pointer[node_index])) if self.__data_pointer[node_index][index] != 0 ];


Instruction:
Make a summary of the following Python 3 code
def show_blocks(directory):

        dimension = len(directory.get_data()[0])

        amount_canvases = 1
        if dimension > 1:
            amount_canvases = int(dimension * (dimension - 1) / 2)

        figure = plt.figure()
        grid_spec = gridspec.GridSpec(1, amount_canvases)

        pairs = list(itertools.combinations(range(dimension), 2))
        if len(pairs) == 0: pairs = [(0, 0)]

        for index in range(amount_canvases):
            ax = figure.add_subplot(grid_spec[index])
            bang_visualizer.__draw_blocks(ax, directory.get_leafs(), pairs[index])
            bang_visualizer.__draw_two_dimension_data(ax, directory.get_data(), pairs[index])

        plt.show()

Response: Show BANG - blocks in data space.


Instruction:
Write a Python 3 function for
displaying a single dendrogram of the same size.

Response:
def show_dendrogram(dendrogram):
        """!
        @brief Display dendrogram of BANG-blocks.

        @param[in] dendrogram (list): List representation of dendrogram of BANG-blocks.

        @see bang.get_dendrogram()

        """
        plt.figure()
        axis = plt.subplot(1, 1, 1)

        current_position = 0
        for index_cluster in range(len(dendrogram)):
            densities = [ block.get_density() for block in dendrogram[index_cluster] ]
            xrange = range(current_position, current_position + len(densities))

            axis.bar(xrange, densities, 1.0, linewidth=0.0, color=color_list.get_color(index_cluster))

            current_position += len(densities)

        axis.set_ylabel("density")
        axis.set_xlabel("block")
        axis.xaxis.set_ticklabels([])

        plt.xlim([-0.5, current_position - 0.5])
        plt.show()


Instruction:
Given the following Python 3 function, write the documentation
def __draw_blocks(ax, blocks, pair):
        ax.grid(False)

        density_scale = blocks[-1].get_density()
        for block in blocks:
            bang_visualizer.__draw_block(ax, pair, block, density_scale)

Response: Display BANG - blocks on specified axes.


Instruction:
Implement a function in Python 3 to
draw a single BANG - block on the specified axis.

Response:
def __draw_block(ax, pair, block, density_scale):
        """!
        @brief Display BANG-block on the specified ax.

        @param[in] ax (Axis): Axis where block should be displayed.
        @param[in] pair (tuple): Pair of coordinate index that should be displayed.
        @param[in] block (bang_block): BANG-block that should be displayed.
        @param[in] density_scale (double): Max density to display density of the block by appropriate tone.

        """
        max_corner, min_corner = bang_visualizer.__get_rectangle_description(block, pair)

        belong_cluster = block.get_cluster() is not None

        if density_scale != 0.0:
            density_scale = bang_visualizer.__maximum_density_alpha * block.get_density() / density_scale

        face_color = matplotlib.colors.to_rgba('blue', alpha=density_scale)
        edge_color = matplotlib.colors.to_rgba('black', alpha=1.0)

        rect = patches.Rectangle(min_corner, max_corner[0] - min_corner[0], max_corner[1] - min_corner[1],
                                 fill=belong_cluster,
                                 facecolor=face_color,
                                 edgecolor=edge_color,
                                 linewidth=0.5)
        ax.add_patch(rect)


Instruction:
How would you code a function in Python 3 to
create rectangle description for a specific dimension.

Response:
def __get_rectangle_description(block, pair):
        """!
        @brief Create rectangle description for block in specific dimension.

        @param[in] pair (tuple): Pair of coordinate index that should be displayed.
        @param[in] block (bang_block): BANG-block that should be displayed

        @return (tuple) Pair of corners that describes rectangle.

        """
        max_corner, min_corner = block.get_spatial_block().get_corners()

        max_corner = [max_corner[pair[0]], max_corner[pair[1]]]
        min_corner = [min_corner[pair[0]], min_corner[pair[1]]]

        if pair == (0, 0):
            max_corner[1], min_corner[1] = 1.0, -1.0

        return max_corner, min_corner


Instruction:
Write a Python 3 function for
incrementing the block index by updating level and level blocks.

Response:
def __increment_block(self):
        """!
        @brief Increment BANG block safely by updating block index, level and level block.

        """
        self.__current_block += 1
        if self.__current_block >= len(self.__level_blocks):
            self.__current_block = 0
            self.__current_level += 1

            if self.__current_level < self.__directory.get_height():
                self.__level_blocks = self.__directory.get_level(self.__current_level)


Instruction:
Can you tell what is the following Python 3 function doing
def __draw_block(self, block, block_alpha=0.0):
        max_corner, min_corner = block.get_spatial_block().get_corners()

        face_color = matplotlib.colors.to_rgba('blue', alpha=block_alpha)
        edge_color = matplotlib.colors.to_rgba('black', alpha=1.0)

        rect = patches.Rectangle(min_corner, max_corner[0] - min_corner[0], max_corner[1] - min_corner[1],
                                 fill=True,
                                 facecolor=face_color,
                                 edgecolor=edge_color,
                                 linewidth=0.5)
        self.__ax.add_patch(rect)

Response: Draws a single BANG block on the current axis.


Instruction:
How would you explain what the following Python 3 function does
def __draw_leaf_density(self):
        leafs = self.__directory.get_leafs()
        density_scale = leafs[-1].get_density()

        if density_scale == 0.0: density_scale = 1.0

        for block in leafs:
            alpha = 0.8 * block.get_density() / density_scale
            self.__draw_block(block, alpha)

Response: Draws densities by filling blocks by appropriate colors.


Instruction:
Can you generate the documentation for the following Python 3 function
def __draw_clusters(self):
        data = self.__directory.get_data()
        for index_cluster in range(len(self.__clusters)):
            color = color_list.get_color(index_cluster)
            self.__draw_cluster(data, self.__clusters[index_cluster], color, '.')

        self.__draw_cluster(self.__directory.get_data(), self.__noise, 'gray', 'x')

Response: Display clusters and outliers using different colors.


Instruction:
Write a Python 3 script to
draw a 2D single cluster on the axis using specified color and marker.

Response:
def __draw_cluster(self, data, cluster, color, marker):
        """!
        @brief Draw 2-D single cluster on axis using specified color and marker.

        """
        for item in cluster:
            self.__ax.plot(data[item][0], data[item][1], color=color, marker=marker)


Instruction:
Make a summary of the following Python 3 code
def animate(self, animation_velocity=75, movie_fps=25, movie_filename=None):
        def init_frame():
            self.__figure.clf()
            self.__ax = self.__figure.add_subplot(1, 1, 1)
            self.__figure.suptitle("BANG algorithm", fontsize=18, fontweight='bold')

            for point in self.__directory.get_data():
                self.__ax.plot(point[0], point[1], color='red', marker='.')

            return frame_generation(0)

        def frame_generation(index_iteration):
            if self.__current_level < self.__directory.get_height():
                block = self.__level_blocks[self.__current_block]
                self.__draw_block(block)
                self.__increment_block()

            else:
                if self.__special_frame == 0:
                    self.__draw_leaf_density()

                elif self.__special_frame == 15:
                    self.__draw_clusters()

                elif self.__special_frame == 30:
                    self.__figure.clf()
                    self.__ax = self.__figure.add_subplot(1, 1, 1)
                    self.__figure.suptitle("BANG algorithm", fontsize=18, fontweight='bold')

                    self.__draw_clusters()

                self.__special_frame += 1

        iterations = len(self.__directory) + 60
        # print("Total number of iterations: %d" % iterations)
        cluster_animation = animation.FuncAnimation(self.__figure, frame_generation, iterations,
                                                    interval=animation_velocity,
                                                    init_func=init_frame,
                                                    repeat_delay=5000)

        if movie_filename is not None:
            cluster_animation.save(movie_filename, writer = 'ffmpeg', fps = movie_fps, bitrate = 3500)
        else:
            plt.show()

Response: Animate the clustering process that is performed by BANG algorithm.


Instruction:
Can you tell what is the following Python 3 function doing
def __create_directory(self):

        min_corner, max_corner = data_corners(self.__data)
        data_block = spatial_block(max_corner, min_corner)

        cache_require = (self.__levels == 1)
        self.__root = bang_block(self.__data, 0, 0, data_block, cache_require)

        if cache_require:
            self.__leafs.append(self.__root)
            self.__store_level_blocks([self.__root])
        else:
            self.__build_directory_levels()

Response: Create BANG directory as a tree with separate storage for leafs.


Instruction:
Create a Python 3 function for
storing the level blocks if observing is enabled.

Response:
def __store_level_blocks(self, level_blocks):
        """!
        @brief Store level blocks if observing is enabled.

        @param[in] level_blocks (list): Created blocks on a new level.

        """
        self.__size += len(level_blocks)
        if self.__observe is True:
            self.__level_blocks.append(level_blocks)


Instruction:
Create a Python 3 function to
build levels of direction if amount of level is greater than one.

Response:
def __build_directory_levels(self):
        """!
        @brief Build levels of direction if amount of level is greater than one.

        """

        previous_level_blocks = [ self.__root ]

        for level in range(1, self.__levels):
            previous_level_blocks = self.__build_level(previous_level_blocks, level)
            self.__store_level_blocks(previous_level_blocks)

        self.__leafs = sorted(self.__leafs, key=lambda block: block.get_density())


Instruction:
Can you generate a brief explanation for the following Python 3 code
def __build_level(self, previous_level_blocks, level):
        current_level_blocks = []

        split_dimension = level % len(self.__data[0])
        cache_require = (level == self.__levels - 1)

        for block in previous_level_blocks:
            self.__split_block(block, split_dimension, cache_require, current_level_blocks)

        if cache_require:
            self.__leafs += current_level_blocks

        return current_level_blocks

Response: Build a new level of directory.


Instruction:
Create a Python 3 function for
splitting a specific block in the specified dimension.

Response:
def __split_block(self, block, split_dimension, cache_require, current_level_blocks):
        """!
        @brief Split specific block in specified dimension.
        @details Split is not performed for block whose density is lower than threshold value, such blocks are putted to
                  leafs.

        @param[in] block (bang_block): BANG-block that should be split.
        @param[in] split_dimension (uint): Dimension at which splitting should be performed.
        @param[in] cache_require (bool): Defines when points in cache should be stored during density calculation.
        @param[in|out] current_level_blocks (list): Block storage at the current level where new blocks should be added.

        """
        if block.get_density() <= self.__density_threshold or len(block) <= self.__amount_density:
            self.__leafs.append(block)

        else:
            left, right = block.split(split_dimension, cache_require)
            current_level_blocks.append(left)
            current_level_blocks.append(right)


Instruction:
Implement a function in Python 3 to
return two spatial blocks in specified dimension.

Response:
def split(self, dimension):
        """!
        @brief Split current block into two spatial blocks in specified dimension.

        @param[in] dimension (uint): Dimension where current block should be split.

        @return (tuple) Pair of new split blocks from current block.

        """
        first_max_corner = self.__max_corner[:]
        second_min_corner = self.__min_corner[:]

        split_border = (self.__max_corner[dimension] + self.__min_corner[dimension]) / 2.0

        first_max_corner[dimension] = split_border
        second_min_corner[dimension] = split_border

        return spatial_block(first_max_corner, self.__min_corner), spatial_block(self.__max_corner, second_min_corner)


Instruction:
Given the following Python 3 function, write the documentation
def is_neighbor(self, block):
        if block is not self:
            block_max_corner, _ = block.get_corners()
            dimension = len(block_max_corner)
            neighborhood_score = self.__calculate_neighborhood(block_max_corner)

            if neighborhood_score == dimension:
                return True

        return False

Response: Returns True if the specified block is neighbors of the current block.


Instruction:
How would you explain what the following Python 3 function does
def __calculate_neighborhood(self, block_max_corner):
        dimension = len(block_max_corner)

        length_edges = [self.__max_corner[i] - self.__min_corner[i] for i in range(dimension)]

        neighborhood_score = 0
        for i in range(dimension):
            diff = abs(block_max_corner[i] - self.__max_corner[i])

            if diff <= length_edges[i] + length_edges[i] * 0.0001:
                neighborhood_score += 1

        return neighborhood_score

Response: Calculates the neighborhood score that defined whether blocks are neighbors.


Instruction:
Write a Python 3 script to
calculate the volume of the current spatial block.

Response:
def __calculate_volume(self):
        """!
        @brief Calculates volume of current spatial block.
        @details If empty dimension is detected (where all points has the same value) then such dimension is ignored
                  during calculation of volume.

        @return (double) Volume of current spatial block.

        """

        volume = 0.0
        for i in range(0, len(self.__max_corner)):
            side_length = self.__max_corner[i] - self.__min_corner[i]

            if side_length != 0.0:
                if volume == 0.0: volume = side_length
                else: volume *= side_length

        return volume


Instruction:
Given the following Python 3 function, write the documentation
def split(self, split_dimension, cache_points):
        left_region_number = self.__region_number
        right_region_number = self.__region_number + 2 ** self.__level

        first_spatial_block, second_spatial_block = self.__spatial_block.split(split_dimension)

        left = bang_block(self.__data, left_region_number, self.__level + 1, first_spatial_block, cache_points)
        right = bang_block(self.__data, right_region_number, self.__level + 1, second_spatial_block, cache_points)

        return left, right

Response: Splits the current BANG - block into two new blocks in the specified dimension.


Instruction:
Here you have a function in Python 3, explain what it does
def __calculate_density(self, amount_points):
        volume = self.__spatial_block.get_volume()
        if volume != 0.0:
            return amount_points / volume

        return 0.0

Response: Calculates the density of the given amount of points in the given block.


Instruction:
Write a Python 3 function that can
return the amount of covered points in the spatial block.

Response:
def __get_amount_points(self):
        """!
        @brief Count covered points by the BANG-block and if cache is enable then covered points are stored.

        @return (uint) Amount of covered points.

        """
        amount = 0
        for index in range(len(self.__data)):
            if self.__data[index] in self.__spatial_block:
                self.__cache_point(index)
                amount += 1

        return amount


Instruction:
Here you have a function in Python 3, explain what it does
def __cache_point(self, index):
        if self.__cache_points:
            if self.__points is None:
                self.__points = []

            self.__points.append(index)

Response: Stores the index point that should be stored.


Instruction:
Can you generate the documentation for the following Python 3 function
def process(self):
        self.__directory = bang_directory(self.__data, self.__levels,
                                          density_threshold=self.__density_threshold,
                                          amount_threshold=self.__amount_threshold)
        self.__allocate_clusters()

        return self

Response: This method is used to process the BANG clustering algorithm.


Instruction:
Can you tell what is the following Python 3 function doing
def __validate_arguments(self):
        if self.__levels <= 0:
            raise ValueError("Incorrect amount of levels '%d'. Level value should be greater than 0." % self.__levels)

        if len(self.__data) == 0:
            raise ValueError("Empty input data. Data should contain at least one point.")

        if self.__density_threshold < 0:
            raise ValueError("Incorrect density threshold '%f'. Density threshold should not be negative." % self.__density_threshold)

Response: Validate input arguments of BANG algorithm.


Instruction:
How would you explain what the following Python 3 function does
def __allocate_clusters(self):
        leaf_blocks = self.__directory.get_leafs()
        unhandled_block_indexes = set([i for i in range(len(leaf_blocks)) if leaf_blocks[i].get_density() > self.__density_threshold])

        current_block = self.__find_block_center(leaf_blocks, unhandled_block_indexes)
        cluster_index = 0

        while current_block is not None:
            if current_block.get_density() <= self.__density_threshold or len(current_block) <= self.__amount_threshold:
                break

            self.__expand_cluster_block(current_block, cluster_index, leaf_blocks, unhandled_block_indexes)

            current_block = self.__find_block_center(leaf_blocks, unhandled_block_indexes)
            cluster_index += 1

        self.__store_clustering_results(cluster_index, leaf_blocks)

Response: Allocates clusters based on leafs of the BANG directory.


Instruction:
How would you explain what the following Python 3 function does
def __expand_cluster_block(self, block, cluster_index, leaf_blocks, unhandled_block_indexes):

        block.set_cluster(cluster_index)
        self.__update_cluster_dendrogram(cluster_index, [block])

        neighbors = self.__find_block_neighbors(block, leaf_blocks, unhandled_block_indexes)
        self.__update_cluster_dendrogram(cluster_index, neighbors)

        for neighbor in neighbors:
            neighbor.set_cluster(cluster_index)
            neighbor_neighbors = self.__find_block_neighbors(neighbor, leaf_blocks, unhandled_block_indexes)
            self.__update_cluster_dendrogram(cluster_index, neighbor_neighbors)

            neighbors += neighbor_neighbors

Response: Expand a single cluster from a specific block.


Instruction:
Implement a Python 3 function for
storing the clustering results in a convenient way.

Response:
def __store_clustering_results(self, amount_clusters, leaf_blocks):
        """!
        @brief Stores clustering results in a convenient way.

        @param[in] amount_clusters (uint): Amount of cluster that was allocated during processing.
        @param[in] leaf_blocks (list): Leaf BANG-blocks (the smallest cells).

        """
        self.__clusters = [[] for _ in range(amount_clusters)]
        for block in leaf_blocks:
            index = block.get_cluster()

            if index is not None:
                self.__clusters[index] += block.get_points()
            else:
                self.__noise += block.get_points()

        self.__clusters = [ list(set(cluster)) for cluster in self.__clusters ]
        self.__noise = list(set(self.__noise))


Instruction:
Given the following Python 3 function, write the documentation
def __find_block_center(self, level_blocks, unhandled_block_indexes):
        for i in reversed(range(len(level_blocks))):
            if level_blocks[i].get_density() <= self.__density_threshold:
                return None

            if level_blocks[i].get_cluster() is None:
                unhandled_block_indexes.remove(i)
                return level_blocks[i]

        return None

Response: Find the center block that is cluster center for new cluster.


Instruction:
Can you create a Python 3 function that
finds all neighbors that can be part of a new cluster.

Response:
def __find_block_neighbors(self, block, level_blocks, unhandled_block_indexes):
        """!
        @brief Search block neighbors that are parts of new clusters (density is greater than threshold and that are
                not cluster members yet), other neighbors are ignored.

        @param[in] block (bang_block): BANG-block for which neighbors should be found (which can be part of cluster).
        @param[in] level_blocks (list): BANG-blocks on specific level.
        @param[in] unhandled_block_indexes (set): Blocks that have not been processed yet.

        @return (list) Block neighbors that can become part of cluster.

        """
        neighbors = []

        handled_block_indexes = []
        for unhandled_index in unhandled_block_indexes:
            if block.is_neighbor(level_blocks[unhandled_index]):
                handled_block_indexes.append(unhandled_index)
                neighbors.append(level_blocks[unhandled_index])

                # Maximum number of neighbors is eight
                if len(neighbors) == 8:
                    break

        for handled_index in handled_block_indexes:
            unhandled_block_indexes.remove(handled_index)

        return neighbors


Instruction:
How would you implement a function in Python 3 that
updates the dendrogram with the given index_cluster and blocks.

Response:
def __update_cluster_dendrogram(self, index_cluster, blocks):
        """!
        @brief Append clustered blocks to dendrogram.

        @param[in] index_cluster (uint): Cluster index that was assigned to blocks.
        @param[in] blocks (list): Blocks that were clustered.

        """
        if len(self.__dendrogram) <= index_cluster:
            self.__dendrogram.append([])

        blocks = sorted(blocks, key=lambda block: block.get_density(), reverse=True)
        self.__dendrogram[index_cluster] += blocks


Instruction:
Write a Python 3 function that can
allocate a map of color indexes that are assigned to each object in the input data space.

Response:
def allocate_map_coloring(self, tolerance, threshold_steps = 10):
        """!
        @brief Returns list of color indexes that are assigned to each object from input data space accordingly.

        @param[in] tolerance (double): Tolerance level that define maximal difference between outputs of oscillators in one synchronous ensemble.
        @param[in] threshold_steps (uint): Number of steps from the end of simulation that should be analysed for ensemble allocation.
                    If amount of simulation steps has been less than threshold steps than amount of steps will be reduced to amount
                    of simulation steps.

        @remark Results can be obtained only after network simulation (graph processing by the network).

        @return (list) Color indexes that are assigned to each object from input data space accordingly.

        @see allocate_clusters()

        """
        clusters = self.allocate_clusters(tolerance, threshold_steps)

        coloring_map = [0] * len(self._dynamic[0])

        for color_index in range(len(clusters)):
            for node_index in clusters[color_index]:
                coloring_map[node_index] = color_index

        return coloring_map


Instruction:
Given the following Python 3 function, write the documentation
def __find_pair_clusters(self, clusters):

        maximum_goodness = 0.0;
        cluster_indexes = [-1, -1];

        for i in range(0, len(clusters)):
            for j in range(i + 1, len(clusters)):
                goodness = self.__calculate_goodness(clusters[i], clusters[j]);
                if (goodness > maximum_goodness):
                    maximum_goodness = goodness;
                    cluster_indexes = [i, j];

        return cluster_indexes;

Response: Returns a list of pairs of clusters that are best candidates for merging in line with goodness measure.


Instruction:
Create a Python 3 function for
calculating the number of links between two clusters.

Response:
def __calculate_links(self, cluster1, cluster2):
        """!
        @brief Returns number of link between two clusters.
        @details Link between objects (points) exists only if distance between them less than connectivity radius.

        @param[in] cluster1 (list): The first cluster.
        @param[in] cluster2 (list): The second cluster.

        @return (uint) Number of links between two clusters.

        """

        number_links = 0;

        for index1 in cluster1:
            for index2 in cluster2:
                number_links += self.__adjacency_matrix[index1][index2];

        return number_links;


Instruction:
Make a summary of the following Python 3 code
def __create_adjacency_matrix(self):

        size_data = len(self.__pointer_data);

        self.__adjacency_matrix = [ [ 0 for i in range(size_data) ] for j in range(size_data) ];
        for i in range(0, size_data):
            for j in range(i + 1, size_data):
                distance = euclidean_distance(self.__pointer_data[i], self.__pointer_data[j]);
                if (distance <= self.__eps):
                    self.__adjacency_matrix[i][j] = 1;
                    self.__adjacency_matrix[j][i] = 1;

Response: Creates adjacency matrix for the current object.


Instruction:
Create a Python 3 function to
calculate the goodness measurement between two clusters.

Response:
def __calculate_goodness(self, cluster1, cluster2):
        """!
        @brief Calculates coefficient 'goodness measurement' between two clusters. The coefficient defines level of suitability of clusters for merging.

        @param[in] cluster1 (list): The first cluster.
        @param[in] cluster2 (list): The second cluster.

        @return Goodness measure between two clusters.

        """

        number_links = self.__calculate_links(cluster1, cluster2);
        devider = (len(cluster1) + len(cluster2)) ** self.__degree_normalization - len(cluster1) ** self.__degree_normalization - len(cluster2) ** self.__degree_normalization;

        return (number_links / devider);


Instruction:
Make a summary of the following Python 3 code
def __process_by_ccore(self):
        ccore_metric = metric_wrapper.create_instance(self.__metric)
        self.__score = wrapper.silhoeutte(self.__data, self.__clusters, ccore_metric.get_pointer())

Response: This method is called by the pyclustering library when the data is read from the CCORE file.


Instruction:
Make a summary of the following Python 3 code
def __process_by_python(self):
        for index_cluster in range(len(self.__clusters)):
            for index_point in self.__clusters[index_cluster]:
                self.__score[index_point] = self.__calculate_score(index_point, index_cluster)

Response: This method is used by the process_by_python method.


Instruction:
Given the following Python 3 function, write the documentation
def __calculate_score(self, index_point, index_cluster):
        difference = self.__calculate_dataset_difference(index_point)

        a_score = self.__calculate_within_cluster_score(index_cluster, difference)
        b_score = self.__caclulate_optimal_neighbor_cluster_score(index_cluster, difference)

        return (b_score - a_score) / max(a_score, b_score)

Response: Calculates the score of the specific object defined by index_point and index_cluster.


Instruction:
Can you generate the documentation for the following Python 3 function
def __calculate_within_cluster_score(self, index_cluster, difference):

        score = self.__calculate_cluster_difference(index_cluster, difference)
        if len(self.__clusters[index_cluster]) == 1:
            return float('nan')
        return score / (len(self.__clusters[index_cluster]) - 1)

Response: Calculates the score of the object in a specific cluster.


Instruction:
Write a Python 3 function that can
calculate the score for the specific object for the specific cluster.

Response:
def __calculate_cluster_score(self, index_cluster, difference):
        """!
        @brief Calculates 'B*' score for the specific object for specific cluster.

        @param[in] index_point (uint): Index point from input data for which 'B*' score should be calculated.
        @param[in] index_cluster (uint): Index cluster to which the point is belong to.

        @return (float) 'B*' score for the object for specific cluster.

        """

        score = self.__calculate_cluster_difference(index_cluster, difference)
        return score / len(self.__clusters[index_cluster])


Instruction:
Make a summary of the following Python 3 code
def __caclulate_optimal_neighbor_cluster_score(self, index_cluster, difference):

        optimal_score = float('inf')
        for index_neighbor_cluster in range(len(self.__clusters)):
            if index_cluster != index_neighbor_cluster:
                candidate_score = self.__calculate_cluster_score(index_neighbor_cluster, difference)
                if candidate_score < optimal_score:
                    optimal_score = candidate_score

        if optimal_score == float('inf'):
            optimal_score = -1.0

        return optimal_score

Response: Calculates the optimal score for the specific object for the nearest cluster.


Instruction:
Create a Python 3 function to
calculate the difference between the specified object and each object in the specified cluster.

Response:
def __calculate_cluster_difference(self, index_cluster, difference):
        """!
        @brief Calculates distance from each object in specified cluster to specified object.

        @param[in] index_point (uint): Index point for which difference is calculated.

        @return (list) Distance from specified object to each object from input data in specified cluster.

        """
        cluster_difference = 0.0
        for index_point in self.__clusters[index_cluster]:
            cluster_difference += difference[index_point]

        return cluster_difference


Instruction:
Given the following Python 3 function, write the documentation
def __calculate_dataset_difference(self, index_point):

        if self.__metric.get_type() != type_metric.USER_DEFINED:
            dataset_differences = self.__metric(self.__data, self.__data[index_point])
        else:
            dataset_differences = [self.__metric(point, self.__data[index_point]) for point in self.__data]

        return dataset_differences

Response: Calculates the difference between each object from each input data point to the specified object.


Instruction:
Write a Python 3 script for
returning the next algorithm type that corresponds to specified enumeration value.

Response:
def get_type(self):
        """!
        @brief Returns algorithm type that corresponds to specified enumeration value.

        @return (type) Algorithm type for cluster analysis.

        """
        if self == silhouette_ksearch_type.KMEANS:
            return kmeans
        elif self == silhouette_ksearch_type.KMEDIANS:
            return kmedians
        elif self == silhouette_ksearch_type.KMEDOIDS:
            return kmedoids
        else:
            return None


Instruction:
Make a summary of the following Python 3 code
def __process_by_python(self):
        self.__scores = {}

        for k in range(self.__kmin, self.__kmax):
            clusters = self.__calculate_clusters(k)
            if len(clusters) != k:
                self.__scores[k] = float('nan')
                continue

            score = silhouette(self.__data, clusters).process().get_score()

            self.__scores[k] = sum(score) / len(score)

            if self.__scores[k] > self.__score:
                self.__score = self.__scores[k]
                self.__amount = k

Response: Performs processing using python code.


Instruction:
Can you create a Python 3 function that
calculates the clusters of the specified size using the algorithm.

Response:
def __calculate_clusters(self, k):
        """!
        @brief Performs cluster analysis using specified K value.

        @param[in] k (uint): Amount of clusters that should be allocated.

        @return (array_like) Allocated clusters.

        """
        initial_values = kmeans_plusplus_initializer(self.__data, k).initialize(return_index=self.__return_index)
        algorithm_type = self.__algorithm.get_type()
        return algorithm_type(self.__data, initial_values).process().get_clusters()


Instruction:
Implement a function in Python 3 to
check the algorithm s arguments and raises an exception if they are not.

Response:
def __verify_arguments(self):
        """!
        @brief Checks algorithm's arguments and if some of them is incorrect then exception is thrown.

        """
        if self.__kmax > len(self.__data):
            raise ValueError("K max value '" + str(self.__kmax) + "' is bigger than amount of objects '" +
                             str(len(self.__data)) + "' in input data.")

        if self.__kmin <= 1:
            raise ValueError("K min value '" + str(self.__kmin) + "' should be greater than 1 (impossible to provide "
                             "silhouette score for only one cluster).")


Instruction:
Can you generate the documentation for the following Python 3 function
def notify(self, clusters, centers):
        self.__evolution_clusters.append(clusters)
        self.__evolution_centers.append(centers)

Response: This method is called by the event loop when the cluster and cluster centers are updated.


Instruction:
Can you write a function in Python 3 where it
displays K - Means clustering results for a given set of clusters.

Response:
def show_clusters(sample, clusters, centers, initial_centers = None, **kwargs):
        """!
        @brief Display K-Means clustering results.

        @param[in] sample (list): Dataset that was used for clustering.
        @param[in] clusters (array_like): Clusters that were allocated by the algorithm.
        @param[in] centers (array_like): Centers that were allocated by the algorithm.
        @param[in] initial_centers (array_like): Initial centers that were used by the algorithm, if 'None' then initial centers are not displyed.
        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'figure', 'display', 'offset').

        Keyword Args:

            - figure (figure): If 'None' then new is figure is created, otherwise specified figure is used for visualization.
            - display (bool): If 'True' then figure will be shown by the method, otherwise it should be shown manually using matplotlib function 'plt.show()'.
            - offset (uint): Specify axes index on the figure where results should be drawn (only if argument 'figure' is specified).

        @return (figure) Figure where clusters were drawn.

        """

        visualizer = cluster_visualizer()
        visualizer.append_clusters(clusters, sample)

        offset = kwargs.get('offset', 0)
        figure = kwargs.get('figure', None)
        display = kwargs.get('display', True)

        if figure is None:
            figure = visualizer.show(display = False)
        else:
            visualizer.show(figure = figure, display = False)

        kmeans_visualizer.__draw_centers(figure, offset, visualizer, centers, initial_centers)
        kmeans_visualizer.__draw_rays(figure, offset, visualizer, sample, clusters, centers)

        if display is True:
            plt.show()

        return figure


Instruction:
Make a summary of the following Python 3 code
def animate_cluster_allocation(data, observer, animation_velocity = 500, movie_fps = 1, save_movie = None):
        figure = plt.figure()

        def init_frame():
            return frame_generation(0)

        def frame_generation(index_iteration):
            figure.clf()

            figure.suptitle("K-Means algorithm (iteration: " + str(index_iteration) + ")", fontsize=18, fontweight='bold')

            clusters = observer.get_clusters(index_iteration)
            centers = observer.get_centers(index_iteration)
            kmeans_visualizer.show_clusters(data, clusters, centers, None, figure=figure, display=False)

            figure.subplots_adjust(top=0.85)

            return [figure.gca()]

        iterations = len(observer)
        cluster_animation = animation.FuncAnimation(figure, frame_generation, iterations, interval=animation_velocity,
                                                    init_func=init_frame, repeat_delay=5000)

        if save_movie is not None:
            cluster_animation.save(save_movie, writer='ffmpeg', fps=movie_fps, bitrate=3000)
        else:
            plt.show()

Response: Animate the cluster allocation of the given data.


Instruction:
How would you explain what the following Python 3 function does
def __process_by_ccore(self):
        ccore_metric = metric_wrapper.create_instance(self.__metric)

        results = wrapper.kmeans(self.__pointer_data, self.__centers, self.__tolerance, self.__itermax, (self.__observer is not None), ccore_metric.get_pointer())
        self.__clusters = results[0]
        self.__centers = results[1]

        if self.__observer is not None:
            self.__observer.set_evolution_clusters(results[2])
            self.__observer.set_evolution_centers(results[3])

        self.__total_wce = results[4][0]

Response: Processes the cluster by CCORE.


Instruction:
Given the following Python 3 function, write the documentation
def __process_by_python(self):

        maximum_change = float('inf')
        iteration = 0

        if self.__observer is not None:
            initial_clusters = self.__update_clusters()
            self.__observer.notify(initial_clusters, self.__centers.tolist())

        while maximum_change > self.__tolerance and iteration < self.__itermax:
            self.__clusters = self.__update_clusters()
            updated_centers = self.__update_centers()  # changes should be calculated before assignment

            if self.__observer is not None:
                self.__observer.notify(self.__clusters, updated_centers.tolist())

            maximum_change = self.__calculate_changes(updated_centers)

            self.__centers = updated_centers    # assign center after change calculation
            iteration += 1

        self.__calculate_total_wce()

Response: Processes the cluster by python code.


Instruction:
Make a summary of the following Python 3 code
def get_centers(self):

        if isinstance(self.__centers, list):
            return self.__centers

        return self.__centers.tolist()

Response: Returns a list of centers of allocated clusters.


Instruction:
Given the following Python 3 function, write the documentation
def __update_clusters(self):

        clusters = [[] for _ in range(len(self.__centers))]

        dataset_differences = self.__calculate_dataset_difference(len(clusters))

        optimum_indexes = numpy.argmin(dataset_differences, axis=0)
        for index_point in range(len(optimum_indexes)):
            index_cluster = optimum_indexes[index_point]
            clusters[index_cluster].append(index_point)

        clusters = [cluster for cluster in clusters if len(cluster) > 0]

        return clusters

Response: Updates the clusters in the file with the closest point from each cluster.


Instruction:
How would you implement a function in Python 3 that
updates the centers of the cluster points in the line with contained objects.

Response:
def __update_centers(self):
        """!
        @brief Calculate centers of clusters in line with contained objects.

        @return (numpy.array) Updated centers.

        """

        dimension = self.__pointer_data.shape[1]
        centers = numpy.zeros((len(self.__clusters), dimension))

        for index in range(len(self.__clusters)):
            cluster_points = self.__pointer_data[self.__clusters[index], :]
            centers[index] = cluster_points.mean(axis=0)

        return numpy.array(centers)


Instruction:
Can you generate the documentation for the following Python 3 function
def __calculate_total_wce(self):

        dataset_differences = self.__calculate_dataset_difference(len(self.__clusters))

        self.__total_wce = 0
        for index_cluster in range(len(self.__clusters)):
            for index_point in self.__clusters[index_cluster]:
                self.__total_wce += dataset_differences[index_cluster][index_point]

Response: Calculates total within cluster errors that depend on metric that was chosen for K - Means algorithm.


Instruction:
Explain what the following Python 3 code does
def __calculate_dataset_difference(self, amount_clusters):
        dataset_differences = numpy.zeros((amount_clusters, len(self.__pointer_data)))
        for index_center in range(amount_clusters):
            if self.__metric.get_type() != type_metric.USER_DEFINED:
                dataset_differences[index_center] = self.__metric(self.__pointer_data, self.__centers[index_center])
            else:
                dataset_differences[index_center] = [ self.__metric(point, self.__centers[index_center])
                                                      for point in self.__pointer_data ]

        return dataset_differences

Response: Calculate the difference between each point and each cluster center.


Instruction:
Write a Python 3 function for
calculating the change estimation between previous and current iteration using new cluster centers.

Response:
def __calculate_changes(self, updated_centers):
        """!
        @brief Calculates changes estimation between previous and current iteration using centers for that purpose.

        @param[in] updated_centers (array_like): New cluster centers.

        @return (float) Maximum changes between centers.

        """
        if len(self.__centers) != len(updated_centers):
            maximum_change = float('inf')

        else:
            changes = self.__metric(self.__centers, updated_centers)
            maximum_change = numpy.max(changes)

        return maximum_change


Instruction:
Write a Python 3 script to
initialize the initial centers in line with input parameters.

Response:
def initialize(self, **kwargs):
        """!
        @brief Generates random centers in line with input parameters.

        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'return_index').

        Keyword Args:

            - return_index (bool): If True then returns indexes of points from input data instead of points itself.

        @return (list) List of initialized initial centers.
                  If argument 'return_index' is False then returns list of points.
                  If argument 'return_index' is True then returns list of indexes.

        """
        return_index = kwargs.get('return_index', False)
        if self.__amount == len(self.__data):
            if return_index:
                return list(range(len(self.__data)))
            return self.__data[:]

        return [self.__create_center(return_index) for _ in range(self.__amount)]


Instruction:
Explain what the following Python 3 code does
def __create_center(self, return_index):
        random_index_point = random.randint(0, len(self.__data[0]))
        if random_index_point not in self.__available_indexes:
            random_index_point = self.__available_indexes.pop()
        else:
            self.__available_indexes.remove(random_index_point)

        if return_index:
            return random_index_point
        return self.__data[random_index_point]

Response: Creates a random center.


Instruction:
Make a summary of the following Python 3 code
def __check_parameters(self):
        if (self.__amount <= 0) or (self.__amount > len(self.__data)):
            raise AttributeError("Amount of cluster centers '" + str(self.__amount) + "' should be at least 1 and "
                                 "should be less or equal to amount of points in data.")

        if self.__candidates != kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE:
            if (self.__candidates <= 0) or (self.__candidates > len(self.__data)):
                raise AttributeError("Amount of center candidates '" + str(self.__candidates) + "' should be at least 1 "
                                     "and should be less or equal to amount of points in data.")

        if len(self.__data) == 0:
            raise AttributeError("Data is empty.")

Response: Checks input parameters of the algorithm and raises an exception if something wrong.


Instruction:
Can you implement a function in Python 3 that
calculates the next center for the data.

Response:
def __get_next_center(self, centers, return_index):
        """!
        @brief Calculates the next center for the data.

        @param[in] centers (array_like): Current initialized centers.
        @param[in] return_index (bool): If True then return center's index instead of point.

        @return (array_like) Next initialized center.<br>
                (uint) Index of next initialized center if return_index is True.

        """

        distances = self.__calculate_shortest_distances(self.__data, centers, return_index)

        if self.__candidates == kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE:
            center_index = numpy.nanargmax(distances)
        else:
            probabilities = self.__calculate_probabilities(distances)
            center_index = self.__get_probable_center(distances, probabilities)

        if return_index:
            return center_index

        return self.__data[center_index]


Instruction:
How would you implement a function in Python 3 that
gets the initial center.

Response:
def __get_initial_center(self, return_index):
        """!
        @brief Choose randomly first center.

        @param[in] return_index (bool): If True then return center's index instead of point.

        @return (array_like) First center.<br>
                (uint) Index of first center.

        """

        index_center = random.randint(0, len(self.__data) - 1)
        if return_index:
            return index_center

        return self.__data[index_center]


Instruction:
How would you explain what the following Python 3 function does
def __calculate_probabilities(self, distances):

        total_distance = numpy.sum(distances)
        if total_distance != 0.0:
            probabilities = distances / total_distance
            return numpy.cumsum(probabilities)
        else:
            return numpy.zeros(len(distances))

Response: Calculates the cumulative probabilities of being center of each point.


Instruction:
Given the following Python 3 function, write the documentation
def __get_probable_center(self, distances, probabilities):

        index_best_candidate = -1
        for _ in range(self.__candidates):
            candidate_probability = random.random()
            index_candidate = 0

            for index_object in range(len(probabilities)):
                if candidate_probability < probabilities[index_object]:
                    index_candidate = index_object
                    break

            if index_best_candidate == -1:
                index_best_candidate = next(iter(self.__free_indexes))
            elif distances[index_best_candidate] < distances[index_candidate]:
                index_best_candidate = index_candidate

        return index_best_candidate

Response: Calculates the next probable center considering amount of candidates.


Instruction:
Write a Python 3 script for
initializing the initial centers of the current object.

Response:
def initialize(self, **kwargs):
        """!
        @brief Calculates initial centers using K-Means++ method.

        @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'return_index').

        Keyword Args:

            - return_index (bool): If True then returns indexes of points from input data instead of points itself.

        @return (list) List of initialized initial centers.
                  If argument 'return_index' is False then returns list of points.
                  If argument 'return_index' is True then returns list of indexes.

        """

        return_index = kwargs.get('return_index', False)

        index_point = self.__get_initial_center(True)
        centers = [index_point]
        self.__free_indexes.remove(index_point)

        # For each next center
        for _ in range(1, self.__amount):
            index_point = self.__get_next_center(centers, True)
            centers.append(index_point)
            self.__free_indexes.remove(index_point)

        if not return_index:
            centers = [self.__data[index] for index in centers]

        return centers


Instruction:
How would you code a function in Python 3 to
object allocation if M = 0 then only object will be allocated

Response:
def twenty_five_neurons_mix_stimulated():
    "Object allocation"
    "If M = 0 then only object will be allocated"
    params = pcnn_parameters();

    params.AF = 0.1;
    params.AL = 0.0;
    params.AT = 0.7;
    params.VF = 1.0;
    params.VL = 1.0;
    params.VT = 10.0;
    params.M = 0.0;

    template_dynamic_pcnn(25, 100, [0, 0, 0, 0, 0,
                                    0, 0, 0, 0, 0,
                                    0, 1, 1, 0, 0,
                                    0, 1, 1, 0, 0,
                                    0, 0, 0, 0, 0], params, conn_type.GRID_FOUR, False);


Instruction:
How would you explain what the following Python 3 function does
def hundred_neurons_mix_stimulated():
    "Allocate several clusters: the first contains borders (indexes of oscillators) and the second objects (indexes of oscillators)"
    params = pcnn_parameters();

    params.AF = 0.1;
    params.AL = 0.1;
    params.AT = 0.8;
    params.VF = 1.0;
    params.VL = 1.0;
    params.VT = 20.0;
    params.W = 1.0;
    params.M = 1.0;

    template_dynamic_pcnn(100, 50,  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                     0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
                                     0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
                                     0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                     0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
                                     0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
                                     0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0], params, conn_type.GRID_EIGHT, False);

Response: Allocate several clusters : the first contains borders and the second objects


Instruction:
Can you tell what is the following Python 3 function doing
def __get_canonical_separate(self, input_separate):
        if (isinstance(input_separate, list)):
            separate = [0] * len(self.dynamics[0]);
            for canvas_index in range(len(input_separate)):
                dynamic_indexes = input_separate[canvas_index];
                for dynamic_index in dynamic_indexes:
                    separate[dynamic_index] = canvas_index;

            return separate;

        elif (input_separate is False):
            if (isinstance(self.dynamics[0], list) is True):
                return [ self.canvas ] * len(self.dynamics[0]);
            else:
                return [ self.canvas ];

        elif (input_separate is True):
            if (isinstance(self.dynamics[0], list) is True):
                return range(self.canvas, self.canvas + len(self.dynamics[0]));
            else:
                return [ self.canvas ];

        else:
            raise Exception("Incorrect type of argument 'separate' '%s'." % type(input_separate));

Response: Returns the unified representation of separation value.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def set_canvas_properties(self, canvas, x_title=None, y_title=None, x_lim=None, y_lim=None, x_labels=True, y_labels=True):
        self.__canvases[canvas] = canvas_descr(x_title, y_title, x_lim, y_lim, x_labels, y_labels);

Response: Set properties of a canvas.


Instruction:
Make a summary of the following Python 3 code
def append_dynamic(self, t, dynamic, canvas=0, color='blue'):
        description = dynamic_descr(canvas, t, dynamic, False, color);
        self.__dynamic_storage.append(description);
        self.__update_canvas_xlim(description.time, description.separate);

Response: Append a new dynamic entry to the list of dynamic entries.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def append_dynamics(self, t, dynamics, canvas=0, separate=False, color='blue'):
        description = dynamic_descr(canvas, t, dynamics, separate, color);
        self.__dynamic_storage.append(description);
        self.__update_canvas_xlim(description.time, description.separate);

Response: Append several dynamics to a canvas or canvases.


Instruction:
Can you write a function in Python 3 where it
displays the dynamics and the related objects in the specified axis.

Response:
def show(self, axis=None, display=True):
        """!
        @brief Draw and show output dynamics.

        @param[in] axis (axis): If is not 'None' then user specified axis is used to display output dynamic.
        @param[in] display (bool): Whether output dynamic should be displayed or not, if not, then user
                    should call 'plt.show()' by himself.

        """

        if (not axis):
            (_, axis) = plt.subplots(self.__size, 1);

        self.__format_canvases(axis);

        for dynamic in self.__dynamic_storage:
            self.__display_dynamic(axis, dynamic);

        if (display):
            plt.show();


Instruction:
Given the following Python 3 function, write the documentation
def output(self):
        if self.__ccore_pcnn_dynamic_pointer is not None:
            return wrapper.pcnn_dynamic_get_output(self.__ccore_pcnn_dynamic_pointer)

        return self.__dynamic

Response: Returns the oscillato outputs during simulation.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def time(self):
        if self.__ccore_pcnn_dynamic_pointer is not None:
            return wrapper.pcnn_dynamic_get_time(self.__ccore_pcnn_dynamic_pointer)

        return list(range(len(self)))

Response: Returns a list of the time when dynamic is measured during simulation.


Instruction:
Can you create a Python 3 function that
allocates clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster.

Response:
def allocate_sync_ensembles(self):
        """!
        @brief Allocate clusters in line with ensembles of synchronous oscillators where each
               synchronous ensemble corresponds to only one cluster.

        @return (list) Grours (lists) of indexes of synchronous oscillators.
                For example, [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].

        """

        if self.__ccore_pcnn_dynamic_pointer is not None:
            return wrapper.pcnn_dynamic_allocate_sync_ensembles(self.__ccore_pcnn_dynamic_pointer)

        sync_ensembles = []
        traverse_oscillators = set()

        number_oscillators = len(self.__dynamic[0])

        for t in range(len(self.__dynamic) - 1, 0, -1):
            sync_ensemble = []
            for i in range(number_oscillators):
                if self.__dynamic[t][i] == self.__OUTPUT_TRUE:
                    if i not in traverse_oscillators:
                        sync_ensemble.append(i)
                        traverse_oscillators.add(i)

            if sync_ensemble != []:
                sync_ensembles.append(sync_ensemble)

        return sync_ensembles


Instruction:
Can you generate a brief explanation for the following Python 3 code
def allocate_spike_ensembles(self):

        if self.__ccore_pcnn_dynamic_pointer is not None:
            return wrapper.pcnn_dynamic_allocate_spike_ensembles(self.__ccore_pcnn_dynamic_pointer)

        spike_ensembles = []
        number_oscillators = len(self.__dynamic[0])

        for t in range(len(self.__dynamic)):
            spike_ensemble = []

            for index in range(number_oscillators):
                if self.__dynamic[t][index] == self.__OUTPUT_TRUE:
                    spike_ensemble.append(index)

            if len(spike_ensemble) > 0:
                spike_ensembles.append(spike_ensemble)

        return spike_ensembles

Response: Analyses output dynamic of network and allocates spikes on each iteration.


Instruction:
Can you write a function in Python 3 where it
allocates a time signal of the network output.

Response:
def allocate_time_signal(self):
        """!
        @brief Analyses output dynamic and calculates time signal (signal vector information) of network output.

        @return (list) Time signal of network output.

        """

        if self.__ccore_pcnn_dynamic_pointer is not None:
            return wrapper.pcnn_dynamic_allocate_time_signal(self.__ccore_pcnn_dynamic_pointer)

        signal_vector_information = []
        for t in range(0, len(self.__dynamic)):
            signal_vector_information.append(sum(self.__dynamic[t]))

        return signal_vector_information


Instruction:
Can you tell what is the following Python 3 function doing
def show_time_signal(pcnn_output_dynamic):

        time_signal = pcnn_output_dynamic.allocate_time_signal()
        time_axis = range(len(time_signal))

        plt.subplot(1, 1, 1)
        plt.plot(time_axis, time_signal, '-')
        plt.ylabel("G (time signal)")
        plt.xlabel("t (iteration)")
        plt.grid(True)

        plt.show()

Response: Show the time signal using network dynamic during simulation.


Instruction:
Here you have a function in Python 3, explain what it does
def show_output_dynamic(pcnn_output_dynamic, separate_representation = False):

        draw_dynamics(pcnn_output_dynamic.time, pcnn_output_dynamic.output, x_title = "t", y_title = "y(t)", separate = separate_representation)

Response: Show the output dynamic of each oscillator in the neural network during simulation.


Instruction:
Implement a function in Python 3 to
animate the output of each oscillator in the simulation.

Response:
def animate_spike_ensembles(pcnn_output_dynamic, image_size):
        """!
        @brief Shows animation of output dynamic (output of each oscillator) during simulation.

        @param[in] pcnn_output_dynamic (pcnn_dynamic): Output dynamic of the pulse-coupled neural network.
        @param[in] image_size (tuple): Image size represented as (height, width).

        """

        figure = plt.figure()

        time_signal = pcnn_output_dynamic.allocate_time_signal()
        spike_ensembles = pcnn_output_dynamic.allocate_spike_ensembles()

        spike_animation = []
        ensemble_index = 0
        for t in range(len(time_signal)):
            image_color_segments = [(255, 255, 255)] * (image_size[0] * image_size[1])

            if time_signal[t] > 0:
                for index_pixel in spike_ensembles[ensemble_index]:
                    image_color_segments[index_pixel] = (0, 0, 0)

                ensemble_index += 1

            stage = numpy.array(image_color_segments, numpy.uint8)
            stage = numpy.reshape(stage, image_size + ((3),)) # ((3),) it's size of RGB - third dimension.
            image_cluster = Image.fromarray(stage, 'RGB')

            spike_animation.append( [ plt.imshow(image_cluster, interpolation='none') ] )

        im_ani = animation.ArtistAnimation(figure, spike_animation, interval=75, repeat_delay=3000, blit=True)
        plt.show()


Instruction:
Implement a Python 3 function for
returning a dynamic simulation of the neural network using the given number of steps and stimulus.

Response:
def simulate(self, steps, stimulus):
        """!
        @brief Performs static simulation of pulse coupled neural network using.

        @param[in] steps (uint): Number steps of simulations during simulation.
        @param[in] stimulus (list): Stimulus for oscillators, number of stimulus should be equal to number of oscillators.

        @return (pcnn_dynamic) Dynamic of oscillatory network - output of each oscillator on each step of simulation.

        """

        if len(stimulus) != len(self):
            raise NameError('Number of stimulus should be equal to number of oscillators. Each stimulus corresponds to only one oscillators.')

        if self.__ccore_pcnn_pointer is not None:
            ccore_instance_dynamic = wrapper.pcnn_simulate(self.__ccore_pcnn_pointer, steps, stimulus)
            return pcnn_dynamic(None, ccore_instance_dynamic)

        dynamic = []
        dynamic.append(self._outputs)

        for step in range(1, steps, 1):
            self._outputs = self._calculate_states(stimulus)

            dynamic.append(self._outputs)

        return pcnn_dynamic(dynamic)


Instruction:
Implement a Python 3 function for
calculating the states of oscillators in the network for the current step and stored them except outputs of oscillators.

Response:
def _calculate_states(self, stimulus):
        """!
        @brief Calculates states of oscillators in the network for current step and stored them except outputs of oscillators.

        @param[in] stimulus (list): Stimulus for oscillators, number of stimulus should be equal to number of oscillators.

        @return (list) New outputs for oscillators (do not stored it).

        """

        feeding = [0.0] * self._num_osc
        linking = [0.0] * self._num_osc
        outputs = [0.0] * self._num_osc
        threshold = [0.0] * self._num_osc

        for index in range(0, self._num_osc, 1):
            neighbors = self.get_neighbors(index)

            feeding_influence = 0.0
            linking_influence = 0.0

            for index_neighbour in neighbors:
                feeding_influence += self._outputs[index_neighbour] * self._params.M
                linking_influence += self._outputs[index_neighbour] * self._params.W

            feeding_influence *= self._params.VF
            linking_influence *= self._params.VL

            feeding[index] = self._params.AF * self._feeding[index] + stimulus[index] + feeding_influence
            linking[index] = self._params.AL * self._linking[index] + linking_influence

            # calculate internal activity
            internal_activity = feeding[index] * (1.0 + self._params.B * linking[index])

            # calculate output of the oscillator
            if internal_activity > self._threshold[index]:
                outputs[index] = self.__OUTPUT_TRUE
            else:
                outputs[index] = self.__OUTPUT_FALSE

            # In case of Fast Linking we should calculate threshold until output is changed.
            if self._params.FAST_LINKING is not True:
                threshold[index] = self._params.AT * self._threshold[index] + self._params.VT * outputs[index]

        # In case of Fast Linking we need to wait until output is changed.
        if self._params.FAST_LINKING is True:
            output_change = True    # Set it True for the for the first iteration.
            previous_outputs = outputs[:]

            while output_change is True:
                current_output_change = False

                for index in range(0, self._num_osc, 1):
                    linking_influence = 0.0

                    neighbors = self.get_neighbors(index)
                    for index_neighbour in neighbors:
                        linking_influence += previous_outputs[index_neighbour] * self._params.W

                    linking_influence *= self._params.VL
                    linking[index] = linking_influence

                    internal_activity = feeding[index] * (1.0 + self._params.B * linking[index])

                    # calculate output of the oscillator
                    if internal_activity > self._threshold[index]:
                        outputs[index] = self.__OUTPUT_TRUE
                    else:
                        outputs[index] = self.__OUTPUT_FALSE

                    current_output_change |= (outputs[index] != previous_outputs[index])

                output_change = current_output_change

                if output_change is True:
                    previous_outputs = outputs[:]

        # In case of Fast Linking threshold should be calculated after fast linking.
        if self._params.FAST_LINKING is True:
            for index in range(0, self._num_osc, 1):
                threshold[index] = self._params.AT * self._threshold[index] + self._params.VT * outputs[index]

        self._feeding = feeding[:]
        self._linking = linking[:]
        self._threshold = threshold[:]

        return outputs


Instruction:
Can you generate a brief explanation for the following Python 3 code
def size(self):

        if self.__ccore_som_pointer is not None:
            self._size = wrapper.som_get_size(self.__ccore_som_pointer)

        return self._size

Response: Returns the size of the self - organized map that is defined by total number of neurons.


Instruction:
Here you have a function in Python 3, explain what it does
def weights(self):

        if self.__ccore_som_pointer is not None:
            self._weights = wrapper.som_get_weights(self.__ccore_som_pointer)

        return self._weights

Response: Returns a list of weight of each neuron.


Instruction:
Given the following Python 3 function, write the documentation
def awards(self):

        if self.__ccore_som_pointer is not None:
            self._award = wrapper.som_get_awards(self.__ccore_som_pointer)

        return self._award

Response: Returns the amount of captured objects by each neuron after training.


Instruction:
Explain what the following Python 3 code does
def capture_objects(self):

        if self.__ccore_som_pointer is not None:
            self._capture_objects = wrapper.som_get_capture_objects(self.__ccore_som_pointer)

        return self._capture_objects

Response: Returns a list of tuples containing the names of the objects that were captured by each neuron.


Instruction:
How would you explain what the following Python 3 function does
def __initialize_locations(self, rows, cols):

        location = list()
        for i in range(rows):
            for j in range(cols):
                location.append([float(i), float(j)])

        return location

Response: Initializes locations in SOM grid


Instruction:
Implement a function in Python 3 to
initialize the distance matrix in SOM grid.

Response:
def __initialize_distances(self, size, location):
        """!
        @brief Initialize distance matrix in SOM grid.

        @param[in] size (uint): Amount of neurons in the network.
        @param[in] location (list): List of coordinates of each neuron in the network.

        @return (list) Distance matrix between neurons in the network.

        """
        sqrt_distances = [ [ [] for i in range(size) ] for j in range(size) ]
        for i in range(size):
            for j in range(i, size, 1):
                dist = euclidean_distance_square(location[i], location[j])
                sqrt_distances[i][j] = dist
                sqrt_distances[j][i] = dist

        return sqrt_distances


Instruction:
How would you code a function in Python 3 to
create initial weights for the neurons in line with the specified initialization.

Response:
def _create_initial_weights(self, init_type):
        """!
        @brief Creates initial weights for neurons in line with the specified initialization.

        @param[in] init_type (type_init): Type of initialization of initial neuron weights (random, random in center of the input data, random distributed in data, ditributed in line with uniform grid).

        """

        dim_info = dimension_info(self._data)

        step_x = dim_info.get_center()[0]
        if self._rows > 1: step_x = dim_info.get_width()[0] / (self._rows - 1);

        step_y = 0.0
        if dim_info.get_dimensions() > 1:
            step_y = dim_info.get_center()[1]
            if self._cols > 1: step_y = dim_info.get_width()[1] / (self._cols - 1);

        # generate weights (topological coordinates)
        random.seed()

        # Uniform grid.
        if init_type == type_init.uniform_grid:
            # Predefined weights in line with input data.
            self._weights = [ [ [] for i in range(dim_info.get_dimensions()) ] for j in range(self._size)]
            for i in range(self._size):
                location = self._location[i]
                for dim in range(dim_info.get_dimensions()):
                    if dim == 0:
                        if self._rows > 1:
                            self._weights[i][dim] = dim_info.get_minimum_coordinate()[dim] + step_x * location[dim]
                        else:
                            self._weights[i][dim] = dim_info.get_center()[dim]

                    elif dim == 1:
                        if self._cols > 1:
                            self._weights[i][dim] = dim_info.get_minimum_coordinate()[dim] + step_y * location[dim]
                        else:
                            self._weights[i][dim] = dim_info.get_center()[dim]
                    else:
                        self._weights[i][dim] = dim_info.get_center()[dim]

        elif init_type == type_init.random_surface:
            # Random weights at the full surface.
            self._weights = [[random.uniform(dim_info.get_minimum_coordinate()[i], dim_info.get_maximum_coordinate()[i]) for i in range(dim_info.get_dimensions())] for _ in range(self._size)]

        elif init_type == type_init.random_centroid:
            # Random weights at the center of input data.
            self._weights = [[(random.random() + dim_info.get_center()[i])  for i in range(dim_info.get_dimensions())] for _ in range(self._size)]

        else:
            # Random weights of input data.
            self._weights = [[random.random() for i in range(dim_info.get_dimensions())] for _ in range(self._size)]


Instruction:
Make a summary of the following Python 3 code
def _create_connections(self, conn_type):

        self._neighbors = [[] for index in range(self._size)]

        for index in range(0, self._size, 1):
            upper_index = index - self._cols
            upper_left_index = index - self._cols - 1
            upper_right_index = index - self._cols + 1

            lower_index = index + self._cols
            lower_left_index = index + self._cols - 1
            lower_right_index = index + self._cols + 1

            left_index = index - 1
            right_index = index + 1

            node_row_index = math.floor(index / self._cols)
            upper_row_index = node_row_index - 1
            lower_row_index = node_row_index + 1

            if (conn_type == type_conn.grid_eight) or (conn_type == type_conn.grid_four):
                if upper_index >= 0:
                    self._neighbors[index].append(upper_index)

                if lower_index < self._size:
                    self._neighbors[index].append(lower_index)

            if (conn_type == type_conn.grid_eight) or (conn_type == type_conn.grid_four) or (conn_type == type_conn.honeycomb):
                if (left_index >= 0) and (math.floor(left_index / self._cols) == node_row_index):
                    self._neighbors[index].append(left_index)

                if (right_index < self._size) and (math.floor(right_index / self._cols) == node_row_index):
                    self._neighbors[index].append(right_index)

            if conn_type == type_conn.grid_eight:
                if (upper_left_index >= 0) and (math.floor(upper_left_index / self._cols) == upper_row_index):
                    self._neighbors[index].append(upper_left_index)

                if (upper_right_index >= 0) and (math.floor(upper_right_index / self._cols) == upper_row_index):
                    self._neighbors[index].append(upper_right_index)

                if (lower_left_index < self._size) and (math.floor(lower_left_index / self._cols) == lower_row_index):
                    self._neighbors[index].append(lower_left_index)

                if (lower_right_index < self._size) and (math.floor(lower_right_index / self._cols) == lower_row_index):
                    self._neighbors[index].append(lower_right_index)

            if conn_type == type_conn.honeycomb:
                if (node_row_index % 2) == 0:
                    upper_left_index = index - self._cols
                    upper_right_index = index - self._cols + 1

                    lower_left_index = index + self._cols
                    lower_right_index = index + self._cols + 1
                else:
                    upper_left_index = index - self._cols - 1
                    upper_right_index = index - self._cols

                    lower_left_index = index + self._cols - 1
                    lower_right_index = index + self._cols

                if (upper_left_index >= 0) and (math.floor(upper_left_index / self._cols) == upper_row_index):
                    self._neighbors[index].append(upper_left_index)

                if (upper_right_index >= 0) and (math.floor(upper_right_index / self._cols) == upper_row_index):
                    self._neighbors[index].append(upper_right_index)

                if (lower_left_index < self._size) and (math.floor(lower_left_index / self._cols) == lower_row_index):
                    self._neighbors[index].append(lower_left_index)

                if (lower_right_index < self._size) and (math.floor(lower_right_index / self._cols) == lower_row_index):
                    self._neighbors[index].append(lower_right_index)

Response: Create all of the connections between oscillators in the network.


Instruction:
Can you generate the documentation for the following Python 3 function
def _competition(self, x):

        index = 0
        minimum = euclidean_distance_square(self._weights[0], x)

        for i in range(1, self._size, 1):
            candidate = euclidean_distance_square(self._weights[i], x)
            if candidate < minimum:
                index = i
                minimum = candidate

        return index

Response: Calculates the distance of a pattern from the input data set.


Instruction:
Implement a function in Python 3 to
train a new self - organized feature map.

Response:
def train(self, data, epochs, autostop=False):
        """!
        @brief Trains self-organized feature map (SOM).

        @param[in] data (list): Input data - list of points where each point is represented by list of features, for example coordinates.
        @param[in] epochs (uint): Number of epochs for training.
        @param[in] autostop (bool): Automatic termination of learining process when adaptation is not occurred.

        @return (uint) Number of learining iterations.

        """

        self._data = data

        if self.__ccore_som_pointer is not None:
            return wrapper.som_train(self.__ccore_som_pointer, data, epochs, autostop)

        self._sqrt_distances = self.__initialize_distances(self._size, self._location)

        for i in range(self._size):
            self._award[i] = 0
            self._capture_objects[i].clear()

        # weights
        self._create_initial_weights(self._params.init_type)

        previous_weights = None

        for epoch in range(1, epochs + 1):
            # Depression term of coupling
            self._local_radius = (self._params.init_radius * math.exp(-(epoch / epochs))) ** 2
            self._learn_rate = self._params.init_learn_rate * math.exp(-(epoch / epochs))

            # Clear statistics
            if autostop:
                for i in range(self._size):
                    self._award[i] = 0
                    self._capture_objects[i].clear()

            for i in range(len(self._data)):
                # Step 1: Competition:
                index = self._competition(self._data[i])

                # Step 2: Adaptation:
                self._adaptation(index, self._data[i])

                # Update statistics
                if (autostop == True) or (epoch == epochs):
                    self._award[index] += 1
                    self._capture_objects[index].append(i)

            # Check requirement of stopping
            if autostop:
                if previous_weights is not None:
                    maximal_adaptation = self._get_maximal_adaptation(previous_weights)
                    if maximal_adaptation < self._params.adaptation_threshold:
                        return epoch

                previous_weights = [item[:] for item in self._weights]

        return epochs


Instruction:
How would you explain what the following Python 3 function does
def simulate(self, input_pattern):

        if self.__ccore_som_pointer is not None:
            return wrapper.som_simulate(self.__ccore_som_pointer, input_pattern)

        return self._competition(input_pattern)

Response: Simulate a list of objects and returns the index of the first object that is in the list of objects.


Instruction:
Can you write a function in Python 3 where it
calculates the maximum change in line with comparison between previous and current weights.

Response:
def _get_maximal_adaptation(self, previous_weights):
        """!
        @brief Calculates maximum changes of weight in line with comparison between previous weights and current weights.

        @param[in] previous_weights (list): Weights from the previous step of learning process.

        @return (double) Value that represents maximum changes of weight after adaptation process.

        """

        dimension = len(self._data[0])
        maximal_adaptation = 0.0

        for neuron_index in range(self._size):
            for dim in range(dimension):
                current_adaptation = previous_weights[neuron_index][dim] - self._weights[neuron_index][dim]

                if current_adaptation < 0:
                    current_adaptation = -current_adaptation

                if maximal_adaptation < current_adaptation:
                    maximal_adaptation = current_adaptation

        return maximal_adaptation


Instruction:
Explain what the following Python 3 code does
def get_winner_number(self):

        if self.__ccore_som_pointer is not None:
            self._award = wrapper.som_get_awards(self.__ccore_som_pointer)

        winner_number = 0
        for i in range(self._size):
            if self._award[i] > 0:
                winner_number += 1

        return winner_number

Response: Calculates the number of winner at the last step of learning process.


Instruction:
How would you implement a function in Python 3 that
shows the distance matrix of the U - matrix.

Response:
def show_distance_matrix(self):
        """!
        @brief Shows gray visualization of U-matrix (distance matrix).

        @see get_distance_matrix()

        """
        distance_matrix = self.get_distance_matrix()

        plt.imshow(distance_matrix, cmap = plt.get_cmap('hot'), interpolation='kaiser')
        plt.title("U-Matrix")
        plt.colorbar()
        plt.show()


Instruction:
Implement a function in Python 3 to
calculate the distance matrix of a set of nodes and neighbors.

Response:
def get_distance_matrix(self):
        """!
        @brief Calculates distance matrix (U-matrix).
        @details The U-Matrix visualizes based on the distance in input space between a weight vector and its neighbors on map.

        @return (list) Distance matrix (U-matrix).

        @see show_distance_matrix()
        @see get_density_matrix()

        """
        if self.__ccore_som_pointer is not None:
            self._weights = wrapper.som_get_weights(self.__ccore_som_pointer)

            if self._conn_type != type_conn.func_neighbor:
                self._neighbors = wrapper.som_get_neighbors(self.__ccore_som_pointer)

        distance_matrix = [[0.0] * self._cols for i in range(self._rows)]

        for i in range(self._rows):
            for j in range(self._cols):
                neuron_index = i * self._cols + j

                if self._conn_type == type_conn.func_neighbor:
                    self._create_connections(type_conn.grid_eight)

                for neighbor_index in self._neighbors[neuron_index]:
                    distance_matrix[i][j] += euclidean_distance_square(self._weights[neuron_index], self._weights[neighbor_index])

                distance_matrix[i][j] /= len(self._neighbors[neuron_index])

        return distance_matrix


Instruction:
Given the following Python 3 function, write the documentation
def show_density_matrix(self, surface_divider = 20.0):
        density_matrix = self.get_density_matrix(surface_divider)

        plt.imshow(density_matrix, cmap = plt.get_cmap('hot'), interpolation='kaiser')
        plt.title("P-Matrix")
        plt.colorbar()
        plt.show()

Response: Show the density matrix using kernel density estimation.


Instruction:
Here you have a function in Python 3, explain what it does
def get_density_matrix(self, surface_divider = 20.0):

        if self.__ccore_som_pointer is not None:
            self._weights = wrapper.som_get_weights(self.__ccore_som_pointer)

        density_matrix = [[0] * self._cols for i in range(self._rows)]
        dimension = len(self._weights[0])

        dim_max = [ float('-Inf') ] * dimension
        dim_min = [ float('Inf') ] * dimension

        for weight in self._weights:
            for index_dim in range(dimension):
                if weight[index_dim] > dim_max[index_dim]:
                    dim_max[index_dim] = weight[index_dim]

                if weight[index_dim] < dim_min[index_dim]:
                    dim_min[index_dim] = weight[index_dim]

        radius = [0.0] * len(self._weights[0])
        for index_dim in range(dimension):
            radius[index_dim] = ( dim_max[index_dim] - dim_min[index_dim] ) / surface_divider

        ## TODO: do not use data
        for point in self._data:
            for index_neuron in range(len(self)):
                point_covered = True

                for index_dim in range(dimension):
                    if abs(point[index_dim] - self._weights[index_neuron][index_dim]) > radius[index_dim]:
                        point_covered = False
                        break

                row = int(math.floor(index_neuron / self._cols))
                col = index_neuron - row * self._cols

                if point_covered is True:
                    density_matrix[row][col] += 1

        return density_matrix

Response: Calculates the density matrix for the current time series.


Instruction:
Explain what the following Python 3 code does
def show_winner_matrix(self):

        if self.__ccore_som_pointer is not None:
            self._award = wrapper.som_get_awards(self.__ccore_som_pointer)

        (fig, ax) = plt.subplots()
        winner_matrix = [[0] * self._cols for i in range(self._rows)]

        for i in range(self._rows):
            for j in range(self._cols):
                neuron_index = i * self._cols + j

                winner_matrix[i][j] = self._award[neuron_index]
                ax.text(i, j, str(winner_matrix[i][j]), va='center', ha='center')

        ax.imshow(winner_matrix, cmap = plt.get_cmap('cool'), interpolation='none')
        ax.grid(True)

        plt.title("Winner Matrix")
        plt.show()

Response: Show the winner matrix of the neurons and the amount of won objects from input dataspace at the last training iteration.


Instruction:
Here you have a function in Python 3, explain what it does
def show_network(self, awards = False, belongs = False, coupling = True, dataset = True, marker_type = 'o'):

        if self.__ccore_som_pointer is not None:
            self._size = wrapper.som_get_size(self.__ccore_som_pointer)
            self._weights = wrapper.som_get_weights(self.__ccore_som_pointer)
            self._neighbors = wrapper.som_get_neighbors(self.__ccore_som_pointer)
            self._award = wrapper.som_get_awards(self.__ccore_som_pointer)

        dimension = len(self._weights[0])

        fig = plt.figure()

        # Check for dimensions
        if (dimension == 1) or (dimension == 2):
            axes = fig.add_subplot(111)
        elif dimension == 3:
            axes = fig.gca(projection='3d')
        else:
            raise NotImplementedError('Impossible to show network in data-space that is differ from 1D, 2D or 3D.')

        if (self._data is not None) and (dataset is True):
            for x in self._data:
                if dimension == 1:
                    axes.plot(x[0], 0.0, 'b|', ms = 30)

                elif dimension == 2:
                    axes.plot(x[0], x[1], 'b.')

                elif dimension == 3:
                    axes.scatter(x[0], x[1], x[2], c = 'b', marker = '.')

        # Show neurons
        for index in range(self._size):
            color = 'g'
            if self._award[index] == 0:
                color = 'y'

            if dimension == 1:
                axes.plot(self._weights[index][0], 0.0, color + marker_type)

                if awards:
                    location = '{0}'.format(self._award[index])
                    axes.text(self._weights[index][0], 0.0, location, color='black', fontsize = 10)

                if belongs and self._data is not None:
                    location = '{0}'.format(index)
                    axes.text(self._weights[index][0], 0.0, location, color='black', fontsize = 12)
                    for k in range(len(self._capture_objects[index])):
                        point = self._data[self._capture_objects[index][k]]
                        axes.text(point[0], 0.0, location, color='blue', fontsize = 10)

            if dimension == 2:
                axes.plot(self._weights[index][0], self._weights[index][1], color + marker_type)

                if awards:
                    location = '{0}'.format(self._award[index])
                    axes.text(self._weights[index][0], self._weights[index][1], location, color='black', fontsize=10)

                if belongs and self._data is not None:
                    location = '{0}'.format(index)
                    axes.text(self._weights[index][0], self._weights[index][1], location, color='black', fontsize=12)
                    for k in range(len(self._capture_objects[index])):
                        point = self._data[self._capture_objects[index][k]]
                        axes.text(point[0], point[1], location, color='blue', fontsize=10)

                if (self._conn_type != type_conn.func_neighbor) and (coupling != False):
                    for neighbor in self._neighbors[index]:
                        if neighbor > index:
                            axes.plot([self._weights[index][0], self._weights[neighbor][0]],
                                      [self._weights[index][1], self._weights[neighbor][1]],
                                      'g', linewidth=0.5)

            elif dimension == 3:
                axes.scatter(self._weights[index][0], self._weights[index][1], self._weights[index][2], c=color, marker=marker_type)

                if (self._conn_type != type_conn.func_neighbor) and (coupling != False):
                    for neighbor in self._neighbors[index]:
                        if neighbor > index:
                            axes.plot([self._weights[index][0], self._weights[neighbor][0]],
                                      [self._weights[index][1], self._weights[neighbor][1]],
                                      [self._weights[index][2], self._weights[neighbor][2]],
                                      'g-', linewidth=0.5)

        plt.title("Network Structure")
        plt.grid()
        plt.show()

Response: Show the network in the current dimension of data.


Instruction:
Make a summary of the following Python 3 code
def calculate_sync_order(oscillator_phases):

        exp_amount = 0.0;
        average_phase = 0.0;

        for phase in oscillator_phases:
            exp_amount += math.expm1( abs(1j * phase) );
            average_phase += phase;

        exp_amount /= len(oscillator_phases);
        average_phase = math.expm1( abs(1j * (average_phase / len(oscillator_phases))) );

        return abs(average_phase) / abs(exp_amount);

Response: Calculates the level of global synchronization for the given list of oscillator phases.


Instruction:
How would you code a function in Python 3 to
calculate the local order of the local synchronization for the specified oscillator phases and the oscillatory network.

Response:
def calculate_local_sync_order(oscillator_phases, oscillatory_network):
        """!
        @brief Calculates level of local synchorization (local order parameter) for input phases for the specified network.
        @details This parameter is tend 1.0 when the oscillatory network close to local synchronization and it tend to 0.0 when
                  desynchronization is observed in the network.

        @param[in] oscillator_phases (list): List of oscillator phases that are used for level of local (partial) synchronization.
        @param[in] oscillatory_network (sync): Instance of oscillatory network whose connections are required for calculation.

        @return (double) Level of local synchronization (local order parameter).

        """

        exp_amount = 0.0;
        num_neigh = 0.0;

        for i in range(0, len(oscillatory_network), 1):
            for j in range(0, len(oscillatory_network), 1):
                if (oscillatory_network.has_connection(i, j) == True):
                    exp_amount += math.exp(-abs(oscillator_phases[j] - oscillator_phases[i]));
                    num_neigh += 1.0;

        if (num_neigh == 0):
            num_neigh = 1.0;

        return exp_amount / num_neigh;


Instruction:
Can you create a Python 3 function that
returns the dynamic of the Sync network during simulation.

Response:
def output(self):
        """!
        @brief (list) Returns output dynamic of the Sync network (phase coordinates of each oscillator in the network) during simulation.

        """
        if ( (self._ccore_sync_dynamic_pointer is not None) and ( (self._dynamic is None) or (len(self._dynamic) == 0) ) ):
            self._dynamic = wrapper.sync_dynamic_get_output(self._ccore_sync_dynamic_pointer);

        return self._dynamic;


Instruction:
Create a Python 3 function to
return the list of time when dynamic is measured during simulation.

Response:
def time(self):
        """!
        @brief (list) Returns sampling times when dynamic is measured during simulation.

        """
        if ( (self._ccore_sync_dynamic_pointer is not None) and ( (self._time is None) or (len(self._time) == 0) ) ):
            self._time = wrapper.sync_dynamic_get_time(self._ccore_sync_dynamic_pointer);

        return self._time;


Instruction:
Explain what the following Python 3 code does
def allocate_sync_ensembles(self, tolerance = 0.01, indexes = None, iteration = None):

        if (self._ccore_sync_dynamic_pointer is not None):
            ensembles = wrapper.sync_dynamic_allocate_sync_ensembles(self._ccore_sync_dynamic_pointer, tolerance, iteration);

            if (indexes is not None):
                for ensemble in ensembles:
                    for index in range(len(ensemble)):
                        ensemble[index] = indexes[ ensemble[index] ];

            return ensembles;

        if ( (self._dynamic is None) or (len(self._dynamic) == 0) ):
            return [];

        number_oscillators = len(self._dynamic[0]);
        last_state = None;

        if (iteration is None):
            last_state = self._dynamic[len(self._dynamic) - 1];
        else:
            last_state = self._dynamic[iteration];

        clusters = [];
        if (number_oscillators > 0):
            clusters.append([0]);

        for i in range(1, number_oscillators, 1):
            cluster_allocated = False;
            for cluster in clusters:
                for neuron_index in cluster:
                    last_state_shifted = abs(last_state[i] - 2 * pi);

                    if ( ( (last_state[i] < (last_state[neuron_index] + tolerance)) and (last_state[i] > (last_state[neuron_index] - tolerance)) ) or
                         ( (last_state_shifted < (last_state[neuron_index] + tolerance)) and (last_state_shifted > (last_state[neuron_index] - tolerance)) ) ):
                        cluster_allocated = True;

                        real_index = i;
                        if (indexes is not None):
                            real_index = indexes[i];

                        cluster.append(real_index);
                        break;

                if (cluster_allocated == True):
                    break;

            if (cluster_allocated == False):
                clusters.append([i]);

        return clusters;

Response: Allocate clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster.


Instruction:
Make a summary of the following Python 3 code
def allocate_correlation_matrix(self, iteration = None):

        if (self._ccore_sync_dynamic_pointer is not None):
            return wrapper.sync_dynamic_allocate_correlation_matrix(self._ccore_sync_dynamic_pointer, iteration);

        if ( (self._dynamic is None) or (len(self._dynamic) == 0) ):
            return [];

        dynamic = self._dynamic;
        current_dynamic = dynamic[len(dynamic) - 1];

        if (iteration is not None):
            current_dynamic = dynamic[iteration];

        number_oscillators = len(dynamic[0]);
        affinity_matrix = [ [ 0.0 for i in range(number_oscillators) ] for j in range(number_oscillators) ];

        for i in range(number_oscillators):
            for j in range(number_oscillators):
                phase1 = current_dynamic[i];
                phase2 = current_dynamic[j];

                affinity_matrix[i][j] = abs(math.sin(phase1 - phase2));

        return affinity_matrix;

Response: Allocate the correlation matrix between oscillators at the specified step of simulation.