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

        if (self.__centroid is not None):
            return self.__centroid;

        self.__centroid = [0] * len(self.linear_sum);
        for index_dimension in range(0, len(self.linear_sum)):
            self.__centroid[index_dimension] = self.linear_sum[index_dimension] / self.number_points;

        return self.__centroid;

Response: Returns the centroid of the cluster represented by the entry.


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

        if (self.__radius is not None):
            return self.__radius;

        centroid = self.get_centroid();

        radius_part_1 = self.square_sum;

        radius_part_2 = 0.0;
        radius_part_3 = 0.0;

        if (type(centroid) == list):
            radius_part_2 = 2.0 * sum(list_math_multiplication(self.linear_sum, centroid));
            radius_part_3 = self.number_points * sum(list_math_multiplication(centroid, centroid));
        else:
            radius_part_2 = 2.0 * self.linear_sum * centroid;
            radius_part_3 = self.number_points * centroid * centroid;

        self.__radius = ( (1.0 / self.number_points) * (radius_part_1 - radius_part_2 + radius_part_3) ) ** 0.5;
        return self.__radius;

Response: Calculates the radius of the cluster that is represented by the entry.


Instruction:
Implement a Python 3 function for
calculating the diameter of the cluster that is represented by the entry.

Response:
def get_diameter(self):
        """!
        @brief Calculates diameter of cluster that is represented by the entry.
        @details It's calculated once when it's requested after the last changes.

        @return (double) Diameter of cluster that is represented by the entry.

        """

        if (self.__diameter is not None):
            return self.__diameter;

        diameter_part = 0.0;
        if (type(self.linear_sum) == list):
            diameter_part = self.square_sum * self.number_points - 2.0 * sum(list_math_multiplication(self.linear_sum, self.linear_sum)) + self.square_sum * self.number_points;
        else:
            diameter_part = self.square_sum * self.number_points - 2.0 * self.linear_sum * self.linear_sum + self.square_sum * self.number_points;

        self.__diameter = ( diameter_part / (self.number_points * (self.number_points - 1)) ) ** 0.5;
        return self.__diameter;


Instruction:
Write a Python 3 function that can
calculate the average inter cluster distance between current and specified clusters.

Response:
def __get_average_inter_cluster_distance(self, entry):
        """!
        @brief Calculates average inter cluster distance between current and specified clusters.

        @param[in] entry (cfentry): Clustering feature to which distance should be obtained.

        @return (double) Average inter cluster distance.

        """

        linear_part_distance = sum(list_math_multiplication(self.linear_sum, entry.linear_sum));

        return ( (entry.number_points * self.square_sum - 2.0 * linear_part_distance + self.number_points * entry.square_sum) / (self.number_points * entry.number_points) ) ** 0.5;


Instruction:
Create a Python 3 function to
calculate the average distance between current and specified clusters.

Response:
def __get_average_intra_cluster_distance(self, entry):
        """!
        @brief Calculates average intra cluster distance between current and specified clusters.

        @param[in] entry (cfentry): Clustering feature to which distance should be obtained.

        @return (double) Average intra cluster distance.

        """

        linear_part_first = list_math_addition(self.linear_sum, entry.linear_sum);
        linear_part_second = linear_part_first;

        linear_part_distance = sum(list_math_multiplication(linear_part_first, linear_part_second));

        general_part_distance = 2.0 * (self.number_points + entry.number_points) * (self.square_sum + entry.square_sum) - 2.0 * linear_part_distance;

        return (general_part_distance / ( (self.number_points + entry.number_points) * (self.number_points + entry.number_points - 1.0) )) ** 0.5;


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

        linear_part_12 = list_math_addition(self.linear_sum, entry.linear_sum);
        variance_part_first = (self.square_sum + entry.square_sum) - \
            2.0 * sum(list_math_multiplication(linear_part_12, linear_part_12)) / (self.number_points + entry.number_points) + \
            (self.number_points + entry.number_points) * sum(list_math_multiplication(linear_part_12, linear_part_12)) / (self.number_points + entry.number_points)**2.0;

        linear_part_11 = sum(list_math_multiplication(self.linear_sum, self.linear_sum));
        variance_part_second = -( self.square_sum - (2.0 * linear_part_11 / self.number_points) + (linear_part_11 / self.number_points) );

        linear_part_22 = sum(list_math_multiplication(entry.linear_sum, entry.linear_sum));
        variance_part_third = -( entry.square_sum - (2.0 / entry.number_points) * linear_part_22 + entry.number_points * (1.0 / entry.number_points ** 2.0) * linear_part_22 );

        return (variance_part_first + variance_part_second + variance_part_third);

Response: Calculates the variance increase distance between current and specified clusters.


Instruction:
Can you tell what is the following Python 3 function doing
def get_distance(self, node, type_measurement):

        return self.feature.get_distance(node.feature, type_measurement);

Response: Calculates the distance between two nodes in line with specified type measurement.


Instruction:
Implement a function in Python 3 to
insert a successor node into the node s successor list.

Response:
def insert_successor(self, successor):
        """!
        @brief Insert successor to the node.

        @param[in] successor (cfnode): Successor for adding.

        """

        self.feature += successor.feature;
        self.successors.append(successor);

        successor.parent = self;


Instruction:
Create a Python 3 function to
remove the successor from the node.

Response:
def remove_successor(self, successor):
        """!
        @brief Remove successor from the node.

        @param[in] successor (cfnode): Successor for removing.

        """

        self.feature -= successor.feature;
        self.successors.append(successor);

        successor.parent = self;


Instruction:
How would you implement a function in Python 3 that
merges a non - leaf node with the current node.

Response:
def merge(self, node):
        """!
        @brief Merge non-leaf node to the current.

        @param[in] node (non_leaf_node): Non-leaf node that should be merged with current.

        """

        self.feature += node.feature;

        for child in node.successors:
            child.parent = self;
            self.successors.append(child);


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

        farthest_node1 = None;
        farthest_node2 = None;
        farthest_distance = 0;

        for i in range(0, len(self.successors)):
            candidate1 = self.successors[i];

            for j in range(i + 1, len(self.successors)):
                candidate2 = self.successors[j];
                candidate_distance = candidate1.get_distance(candidate2, type_measurement);

                if (candidate_distance > farthest_distance):
                    farthest_distance = candidate_distance;
                    farthest_node1 = candidate1;
                    farthest_node2 = candidate2;

                    return [farthest_node1, farthest_node2];

Response: Returns a list of the pair of farthest successors of the node in line with measurement type.


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

        nearest_node1 = None;
        nearest_node2 = None;
        nearest_distance = float("Inf");

        for i in range(0, len(self.successors)):
            candidate1 = self.successors[i];

            for j in range(i + 1, len(self.successors)):
                candidate2 = self.successors[j];
                candidate_distance = candidate1.get_distance(candidate2, type_measurement);

                if (candidate_distance < nearest_distance):
                    nearest_distance = candidate_distance;
                    nearest_node1 = candidate1;
                    nearest_node2 = candidate2;

        return [nearest_node1, nearest_node2];

Response: Returns a list of the nearest successors of the node in line with measurement type.


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

        self.feature += entry;
        self.entries.append(entry);

Response: Insert a new entry into the leaf node.


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

        self.feature -= entry;
        self.entries.remove(entry);

Response: Removes a clustering feature from the leaf node.


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

        self.feature += node.feature;

        # Move entries from merged node
        for entry in node.entries:
            self.entries.append(entry);

Response: Merge the leaf node with the current node.


Instruction:
Implement a function in Python 3 to
return a list of the two farthest entries of the node that are represented by the given type_measurement.

Response:
def get_farthest_entries(self, type_measurement):
        """!
        @brief Find pair of farthest entries of the node.

        @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining farthest entries.

        @return (list) Pair of farthest entries of the node that are represented by list.

        """

        farthest_entity1 = None;
        farthest_entity2 = None;
        farthest_distance = 0;

        for i in range(0, len(self.entries)):
            candidate1 = self.entries[i];

            for j in range(i + 1, len(self.entries)):
                candidate2 = self.entries[j];
                candidate_distance = candidate1.get_distance(candidate2, type_measurement);

                if (candidate_distance > farthest_distance):
                    farthest_distance = candidate_distance;
                    farthest_entity1 = candidate1;
                    farthest_entity2 = candidate2;

        return [farthest_entity1, farthest_entity2];


Instruction:
Can you write a function in Python 3 where it
returns the index of the nearest entry of the specified entry.

Response:
def get_nearest_index_entry(self, entry, type_measurement):
        """!
        @brief Find nearest index of nearest entry of node for the specified entry.

        @param[in] entry (cfentry): Entry that is used for calculation distance.
        @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining nearest entry to the specified.

        @return (uint) Index of nearest entry of node for the specified entry.

        """

        minimum_distance = float('Inf');
        nearest_index = 0;

        for candidate_index in range(0, len(self.entries)):
            candidate_distance = self.entries[candidate_index].get_distance(entry, type_measurement);
            if (candidate_distance < minimum_distance):
                nearest_index = candidate_index;

        return nearest_index;


Instruction:
Given the following Python 3 function, write the documentation
def get_nearest_entry(self, entry, type_measurement):

        min_key = lambda cur_entity: cur_entity.get_distance(entry, type_measurement);
        return min(self.__entries, key = min_key);

Response: Returns the nearest entry of the specified entry.


Instruction:
Write a Python 3 function that can
return a list of CF - nodes that are located at the specified level.

Response:
def get_level_nodes(self, level):
        """!
        @brief Traverses CF-tree to obtain nodes at the specified level.

        @param[in] level (uint): CF-tree level from that nodes should be returned.

        @return (list) List of CF-nodes that are located on the specified level of the CF-tree.

        """

        level_nodes = [];
        if (level < self.__height):
            level_nodes = self.__recursive_get_level_nodes(level, self.__root);

        return level_nodes;


Instruction:
Explain what the following Python 3 code does
def __recursive_get_level_nodes(self, level, node):

        level_nodes = [];
        if (level is 0):
            level_nodes.append(node);

        else:
            for sucessor in node.successors:
                level_nodes += self.__recursive_get_level_nodes(level - 1, sucessor);

        return level_nodes;

Response: Returns a list of CF - nodes that are located at the specified level recursively.


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

        entry = cfentry(len(cluster), linear_sum(cluster), square_sum(cluster));
        self.insert(entry);

Response: Insert a new cluster into the tree.


Instruction:
Explain what the following Python 3 code does
def insert(self, entry):

        if (self.__root is None):
            node = leaf_node(entry, None, [ entry ], None);

            self.__root = node;
            self.__leafes.append(node);

            # Update statistics
            self.__amount_entries += 1;
            self.__amount_nodes += 1;
            self.__height += 1;             # root has successor now
        else:
            child_node_updation = self.__recursive_insert(entry, self.__root);
            if (child_node_updation is True):
                # Splitting has been finished, check for possibility to merge (at least we have already two children).
                if (self.__merge_nearest_successors(self.__root) is True):
                    self.__amount_nodes -= 1;

Response: Insert a new entry into the tree.


Instruction:
How would you implement a function in Python 3 that
searches the tree for the nearest leaf to the specified entry.

Response:
def find_nearest_leaf(self, entry, search_node = None):
        """!
        @brief Search nearest leaf to the specified clustering feature.

        @param[in] entry (cfentry): Clustering feature.
        @param[in] search_node (cfnode): Node from that searching should be started, if None then search process will be started for the root.

        @return (leaf_node) Nearest node to the specified clustering feature.

        """

        if (search_node is None):
            search_node = self.__root;

        nearest_node = search_node;

        if (search_node.type == cfnode_type.CFNODE_NONLEAF):
            min_key = lambda child_node: child_node.feature.get_distance(entry, self.__type_measurement);
            nearest_child_node = min(search_node.successors, key = min_key);

            nearest_node = self.find_nearest_leaf(entry, nearest_child_node);

        return nearest_node;


Instruction:
Can you tell what is the following Python 3 function doing
def __recursive_insert(self, entry, search_node):

        # None-leaf node
        if (search_node.type == cfnode_type.CFNODE_NONLEAF):
            return self.__insert_for_noneleaf_node(entry, search_node);

        # Leaf is reached
        else:
            return self.__insert_for_leaf_node(entry, search_node);

Response: This method performs all required procedures during the insertion of the given entry to the tree.


Instruction:
Given the following Python 3 function, write the documentation
def __insert_for_leaf_node(self, entry, search_node):

        node_amount_updation = False;

        # Try to absorb by the entity
        index_nearest_entry = search_node.get_nearest_index_entry(entry, self.__type_measurement);
        merged_entry = search_node.entries[index_nearest_entry] + entry;

        # Otherwise try to add new entry
        if (merged_entry.get_diameter() > self.__threshold):
            # If it's not exceeded append entity and update feature of the leaf node.
            search_node.insert_entry(entry);

            # Otherwise current node should be splitted
            if (len(search_node.entries) > self.__max_entries):
                self.__split_procedure(search_node);
                node_amount_updation = True;

            # Update statistics
            self.__amount_entries += 1;

        else:
            search_node.entries[index_nearest_entry] = merged_entry;
            search_node.feature += entry;

        return node_amount_updation;

Response: Internal method that recursively inserts a single entry into a leaf node.


Instruction:
Given the following Python 3 function, write the documentation
def __insert_for_noneleaf_node(self, entry, search_node):

        node_amount_updation = False;

        min_key = lambda child_node: child_node.get_distance(search_node, self.__type_measurement);
        nearest_child_node = min(search_node.successors, key = min_key);

        child_node_updation = self.__recursive_insert(entry, nearest_child_node);

        # Update clustering feature of none-leaf node.
        search_node.feature += entry;

        # Check branch factor, probably some leaf has been splitted and threshold has been exceeded.
        if (len(search_node.successors) > self.__branch_factor):

            # Check if it's aleady root then new root should be created (height is increased in this case).
            if (search_node is self.__root):
                self.__root = non_leaf_node(search_node.feature, None, [ search_node ], None);
                search_node.parent = self.__root;

                # Update statistics
                self.__amount_nodes += 1;
                self.__height += 1;

            [new_node1, new_node2] = self.__split_nonleaf_node(search_node);

            # Update parent list of successors
            parent = search_node.parent;
            parent.successors.remove(search_node);
            parent.successors.append(new_node1);
            parent.successors.append(new_node2);

            # Update statistics
            self.__amount_nodes += 1;
            node_amount_updation = True;

        elif (child_node_updation is True):
            # Splitting has been finished, check for possibility to merge (at least we have already two children).
            if (self.__merge_nearest_successors(search_node) is True):
                self.__amount_nodes -= 1;

        return node_amount_updation;

Response: Recursive insert entry from a single node to the tree.


Instruction:
Can you implement a function in Python 3 that
starts node splitting procedure in the CF - tree from the specify node.

Response:
def __split_procedure(self, split_node):
        """!
        @brief Starts node splitting procedure in the CF-tree from the specify node.

        @param[in] split_node (cfnode): CF-tree node that should be splitted.

        """
        if (split_node is self.__root):
            self.__root = non_leaf_node(split_node.feature, None, [ split_node ], None);
            split_node.parent = self.__root;

            # Update statistics
            self.__amount_nodes += 1;
            self.__height += 1;

        [new_node1, new_node2] = self.__split_leaf_node(split_node);

        self.__leafes.remove(split_node);
        self.__leafes.append(new_node1);
        self.__leafes.append(new_node2);

        # Update parent list of successors
        parent = split_node.parent;
        parent.successors.remove(split_node);
        parent.successors.append(new_node1);
        parent.successors.append(new_node2);

        # Update statistics
        self.__amount_nodes += 1;


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

        [farthest_node1, farthest_node2] = node.get_farthest_successors(self.__type_measurement);

        # create new non-leaf nodes
        new_node1 = non_leaf_node(farthest_node1.feature, node.parent, [ farthest_node1 ], None);
        new_node2 = non_leaf_node(farthest_node2.feature, node.parent, [ farthest_node2 ], None);

        farthest_node1.parent = new_node1;
        farthest_node2.parent = new_node2;

        # re-insert other successors
        for successor in node.successors:
            if ( (successor is not farthest_node1) and (successor is not farthest_node2) ):
                distance1 = new_node1.get_distance(successor, self.__type_measurement);
                distance2 = new_node2.get_distance(successor, self.__type_measurement);

                if (distance1 < distance2):
                    new_node1.insert_successor(successor);
                else:
                    new_node2.insert_successor(successor);

        return [new_node1, new_node2];

Response: Returns a list of two non - leaf nodes that are not leaf nodes.


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

        # search farthest pair of entries
        [farthest_entity1, farthest_entity2] = node.get_farthest_entries(self.__type_measurement);

        # create new nodes
        new_node1 = leaf_node(farthest_entity1, node.parent, [ farthest_entity1 ], None);
        new_node2 = leaf_node(farthest_entity2, node.parent, [ farthest_entity2 ], None);

        # re-insert other entries
        for entity in node.entries:
            if ( (entity is not farthest_entity1) and (entity is not farthest_entity2) ):
                distance1 = new_node1.feature.get_distance(entity, self.__type_measurement);
                distance2 = new_node2.feature.get_distance(entity, self.__type_measurement);

                if (distance1 < distance2):
                    new_node1.insert_entry(entity);
                else:
                    new_node2.insert_entry(entity);

        return [new_node1, new_node2];

Response: This method splits a leaf node into two nodes.


Instruction:
Can you tell what is the following Python 3 function doing
def show_feature_destibution(self, data = None):
        visualizer = cluster_visualizer();

        print("amount of nodes: ", self.__amount_nodes);

        if (data is not None):
            visualizer.append_cluster(data, marker = 'x');

        for level in range(0, self.height):
            level_nodes = self.get_level_nodes(level);

            centers = [ node.feature.get_centroid() for node in level_nodes ];
            visualizer.append_cluster(centers, None, markersize = (self.height - level + 1) * 5);

        visualizer.show();

Response: Shows the feature distribution.


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

        if (self.__ccore is True):
            self.__clusters = wrapper.agglomerative_algorithm(self.__pointer_data, self.__number_clusters, self.__similarity);

        else:
            self.__clusters = [[index] for index in range(0, len(self.__pointer_data))];

            current_number_clusters = len(self.__clusters);

            while (current_number_clusters > self.__number_clusters):
                self.__merge_similar_clusters();
                current_number_clusters = len(self.__clusters);

Response: This method processes the agglomerative algorithm and returns the cluster information.


Instruction:
Write a Python 3 function for
merging the most similar clusters in line with link type.

Response:
def __merge_similar_clusters(self):
        """!
        @brief Merges the most similar clusters in line with link type.

        """

        if (self.__similarity == type_link.AVERAGE_LINK):
            self.__merge_by_average_link();

        elif (self.__similarity == type_link.CENTROID_LINK):
            self.__merge_by_centroid_link();

        elif (self.__similarity == type_link.COMPLETE_LINK):
            self.__merge_by_complete_link();

        elif (self.__similarity == type_link.SINGLE_LINK):
            self.__merge_by_signle_link();

        else:
            raise NameError('Not supported similarity is used');


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

        minimum_average_distance = float('Inf');

        for index_cluster1 in range(0, len(self.__clusters)):
            for index_cluster2 in range(index_cluster1 + 1, len(self.__clusters)):

                # Find farthest objects
                candidate_average_distance = 0.0;
                for index_object1 in self.__clusters[index_cluster1]:
                    for index_object2 in self.__clusters[index_cluster2]:
                        candidate_average_distance += euclidean_distance_square(self.__pointer_data[index_object1], self.__pointer_data[index_object2]);

                candidate_average_distance /= (len(self.__clusters[index_cluster1]) + len(self.__clusters[index_cluster2]));

                if (candidate_average_distance < minimum_average_distance):
                    minimum_average_distance = candidate_average_distance;
                    indexes = [index_cluster1, index_cluster2];

        self.__clusters[indexes[0]] += self.__clusters[indexes[1]];
        self.__clusters.pop(indexes[1]);

Response: This method merges the most similar clusters in line with average link type.


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

        minimum_centroid_distance = float('Inf');
        indexes = None;

        for index1 in range(0, len(self.__centers)):
            for index2 in range(index1 + 1, len(self.__centers)):
                distance = euclidean_distance_square(self.__centers[index1], self.__centers[index2]);
                if (distance < minimum_centroid_distance):
                    minimum_centroid_distance = distance;
                    indexes = [index1, index2];

        self.__clusters[indexes[0]] += self.__clusters[indexes[1]];
        self.__centers[indexes[0]] = self.__calculate_center(self.__clusters[indexes[0]]);

        self.__clusters.pop(indexes[1]);   # remove merged cluster.
        self.__centers.pop(indexes[1]);

Response: Merges the most similar clusters in line with the centroid link type.


Instruction:
Create a Python 3 function for
merging the most similar clusters in line with complete link type.

Response:
def __merge_by_complete_link(self):
        """!
        @brief Merges the most similar clusters in line with complete link type.

        """

        minimum_complete_distance = float('Inf');
        indexes = None;

        for index_cluster1 in range(0, len(self.__clusters)):
            for index_cluster2 in range(index_cluster1 + 1, len(self.__clusters)):
                candidate_maximum_distance = self.__calculate_farthest_distance(index_cluster1, index_cluster2);

                if (candidate_maximum_distance < minimum_complete_distance):
                    minimum_complete_distance = candidate_maximum_distance;
                    indexes = [index_cluster1, index_cluster2];

        self.__clusters[indexes[0]] += self.__clusters[indexes[1]];
        self.__clusters.pop(indexes[1]);


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

        minimum_single_distance = float('Inf');
        indexes = None;

        for index_cluster1 in range(0, len(self.__clusters)):
            for index_cluster2 in range(index_cluster1 + 1, len(self.__clusters)):
                candidate_minimum_distance = self.__calculate_nearest_distance(index_cluster1, index_cluster2);

                if (candidate_minimum_distance < minimum_single_distance):
                    minimum_single_distance = candidate_minimum_distance;
                    indexes = [index_cluster1, index_cluster2];

        self.__clusters[indexes[0]] += self.__clusters[indexes[1]];
        self.__clusters.pop(indexes[1]);

Response: Merges the most similar clusters in line with single link type.


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

        dimension = len(self.__pointer_data[cluster[0]]);
        center = [0] * dimension;
        for index_point in cluster:
            for index_dimension in range(0, dimension):
                center[index_dimension] += self.__pointer_data[index_point][index_dimension];

        for index_dimension in range(0, dimension):
            center[index_dimension] /= len(cluster);

        return center;

Response: Calculates the new center of the specified cluster.


Instruction:
Can you create a Python 3 function that
creates a new self - organized map using the CCORE pyclustering library.

Response:
def som_create(rows, cols, conn_type, parameters):
    """!
    @brief Create of self-organized map using CCORE pyclustering library.

    @param[in] rows (uint): Number of neurons in the column (number of rows).
    @param[in] cols (uint): Number of neurons in the row (number of columns).
    @param[in] conn_type (type_conn): Type of connection between oscillators in the network (grid four, grid eight, honeycomb, function neighbour).
    @param[in] parameters (som_parameters): Other specific parameters.

    @return (POINTER) C-pointer to object of self-organized feature in memory.

    """

    ccore = ccore_library.get()

    c_params = c_som_parameters()

    c_params.init_type = parameters.init_type
    c_params.init_radius = parameters.init_radius
    c_params.init_learn_rate = parameters.init_learn_rate
    c_params.adaptation_threshold = parameters.adaptation_threshold

    ccore.som_create.restype = POINTER(c_void_p)
    som_pointer = ccore.som_create(c_uint(rows), c_uint(cols), c_uint(conn_type), pointer(c_params))

    return som_pointer


Instruction:
Can you write a function in Python 3 where it
loads the dump of the network to SOM.

Response:
def som_load(som_pointer, weights, award, capture_objects):
    """!
    @brief Load dump of the network to SOM.
    @details Initialize SOM using existed weights, amount of captured objects by each neuron, captured
              objects by each neuron. Initialization is not performed if weights are empty.

    @param[in] som_pointer (POINTER): pointer to object of self-organized map.
    @param[in] weights (list): weights that should assigned to neurons.
    @param[in] awards (list): amount of captured objects by each neuron.
    @param[in] capture_objects (list): captured objects by each neuron.

    """

    if len(weights) == 0:
        return

    ccore = ccore_library.get()

    package_weights = package_builder(weights, c_double).create()
    package_award = package_builder(award, c_size_t).create()
    package_capture_objects = package_builder(capture_objects, c_size_t).create()

    ccore.som_load(som_pointer, package_weights, package_award, package_capture_objects)


Instruction:
Explain what the following Python 3 code does
def som_train(som_pointer, data, epochs, autostop):

    pointer_data = package_builder(data, c_double).create()

    ccore = ccore_library.get()
    ccore.som_train.restype = c_size_t
    return ccore.som_train(som_pointer, pointer_data, c_uint(epochs), autostop)

Response: Trains self - organized feature map using CCORE pyclustering library.


Instruction:
Implement a function in Python 3 to
simulate a list of objects in a self - organized map.

Response:
def som_simulate(som_pointer, pattern):
    """!
    @brief Processes input pattern (no learining) and returns index of neuron-winner.
    @details Using index of neuron winner catched object can be obtained using property capture_objects.

    @param[in] som_pointer (c_pointer): pointer to object of self-organized map.
    @param[in] pattern (list): input pattern.

    @return Returns index of neuron-winner.

    """

    pointer_data = package_builder(pattern, c_double).create()

    ccore = ccore_library.get()
    ccore.som_simulate.restype = c_size_t
    return ccore.som_simulate(som_pointer, pointer_data)


Instruction:
Create a Python 3 function to
return the number of winner at the last step of learning process.

Response:
def som_get_winner_number(som_pointer):
    """!
    @brief Returns of number of winner at the last step of learning process.

    @param[in] som_pointer (c_pointer): pointer to object of self-organized map.

    """

    ccore = ccore_library.get()
    ccore.som_get_winner_number.restype = c_size_t
    return ccore.som_get_winner_number(som_pointer)


Instruction:
Write a Python 3 script for
returning the size of the self - organized map.

Response:
def som_get_size(som_pointer):
    """!
    @brief Returns size of self-organized map (number of neurons).

    @param[in] som_pointer (c_pointer): pointer to object of self-organized map.

    """

    ccore = ccore_library.get()
    ccore.som_get_size.restype = c_size_t
    return ccore.som_get_size(som_pointer)


Instruction:
Implement a function in Python 3 to
return list of indexes of captured objects by each neuron.

Response:
def som_get_capture_objects(som_pointer):
    """!
    @brief Returns list of indexes of captured objects by each neuron.

    @param[in] som_pointer (c_pointer): pointer to object of self-organized map.

    """

    ccore = ccore_library.get()

    ccore.som_get_capture_objects.restype = POINTER(pyclustering_package)
    package = ccore.som_get_capture_objects(som_pointer)

    result = package_extractor(package).extract()
    return result


Instruction:
Write a Python 3 function for
allocating clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster.

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

        @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators.
        @param[in] threshold_steps (uint): Number of steps from the end of simulation that should be analysed for ensemble allocation.
                    If amout of simulation steps has been less than threshold steps than amount of steps will be reduced to amout
                    of simulation steps.

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

        """

        clusters = [ [0] ];

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

        for i in range(1, number_oscillators, 1):
            captured_neuron = True;
            for cluster in clusters:
                neuron_index = cluster[0];

                analysis_steps = threshold_steps;
                if (len(self._dynamic) < analysis_steps):
                    analysis_steps = len(self._dynamic);

                analysis_start_step_index = len(self._dynamic) - 1;

                for step in range(analysis_start_step_index, analysis_start_step_index - analysis_steps, -1):
                    neuron_amplitude = self._dynamic[step][neuron_index];
                    candidate_amplitude = self._dynamic[step][i];

                    if ( not (candidate_amplitude < (neuron_amplitude + tolerance)) or not (candidate_amplitude > (neuron_amplitude - tolerance)) ):
                        captured_neuron = False;
                        break;

                if ( captured_neuron is True ):
                    cluster.append(i);
                    break;

            if (captured_neuron is False):
                clusters.append([i]);

        return clusters;


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

        self._outputs = [val for val in values];
        self._outputs_buffer = [val for val in values];

Response: Sets the outputs of the neurons.


Instruction:
Here you have a function in Python 3, explain what it does
def _neuron_states(self, inputs, t, argv):

        xi = inputs[0];
        index = argv;

        # own impact
        impact = self._weight[index][index] * self._outputs[index];

        for i in range(0, self._num_osc, 1):
            if (self.has_connection(i, index)):
                impact += self._weight[index][i] * self._outputs[i];

        x = -xi + impact;

        if (xi > 1): self._outputs_buffer[index] = 1;
        if (xi < -1): self._outputs_buffer[index] = -1;

        return x;

Response: Returns the new value of the neuron.


Instruction:
Can you generate the documentation for the following Python 3 function
def simulate_static(self, steps, time, solution = solve_type.RK4, collect_dynamic = False):

        # Check solver before simulation
        if (solution == solve_type.FAST):
            raise NameError("Solver FAST is not support due to low accuracy that leads to huge error.");
        elif (solution == solve_type.RKF45):
            raise NameError("Solver RKF45 is not support in python version.");

        dyn_state = None;
        dyn_time = None;

        if (collect_dynamic == True):
            dyn_state = [];
            dyn_time = [];

            dyn_state.append(self._states);
            dyn_time.append(0);

        step = time / steps;
        int_step = step / 10.0;

        for t in numpy.arange(step, time + step, step):
            # update states of oscillators
            self._states = self._calculate_states(solution, t, step, int_step);

            # update states of oscillators
            if (collect_dynamic is True):
                dyn_state.append(self._states);
                dyn_time.append(t);

        if (collect_dynamic is False):
            dyn_state.append(self._states);
            dyn_time.append(time);

        return hysteresis_dynamic(dyn_state, dyn_time);

Response: A method that performs a static simulation of the hysteresis oscillatory network.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _calculate_states(self, solution, t, step, int_step):

        next_states = [0] * self._num_osc;

        for index in range (0, self._num_osc, 1):
            result = odeint(self._neuron_states, self._states[index], numpy.arange(t - step, t, int_step), (index , ));
            next_states[index] = result[len(result) - 1][0];

        self._outputs = [val for val in self._outputs_buffer];
        return next_states;

Response: Calculates the new states for the given solution and returns the new states for the given solution.


Instruction:
Make a summary of the following Python 3 code
def output(self):
        if (self.__ccore_legion_dynamic_pointer is not None):
            return wrapper.legion_dynamic_get_output(self.__ccore_legion_dynamic_pointer);

        return self.__output;

Response: Returns the output of the legion.


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

        if (self.__ccore_legion_dynamic_pointer is not None):
            return wrapper.legion_dynamic_get_inhibitory_output(self.__ccore_legion_dynamic_pointer);

        return self.__inhibitor;

Response: Returns the dynamic inhibitor of the global inhibitor of the network.


Instruction:
Can you implement a function in Python 3 that
returns the simulation time.

Response:
def time(self):
        """!
        @brief Returns simulation time.

        """
        if (self.__ccore_legion_dynamic_pointer is not None):
            return wrapper.legion_dynamic_get_time(self.__ccore_legion_dynamic_pointer);

        return list(range(len(self)));


Instruction:
Can you generate a brief explanation for the following Python 3 code
def allocate_sync_ensembles(self, tolerance = 0.1):

        if (self.__ccore_legion_dynamic_pointer is not None):
            self.__output = wrapper.legion_dynamic_get_output(self.__ccore_legion_dynamic_pointer);

        return allocate_sync_ensembles(self.__output, tolerance);

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


Instruction:
Write a Python 3 script to
create stimulus for oscillators in line with stimulus map and parameters.

Response:
def __create_stimulus(self, stimulus):
        """!
        @brief Create stimulus for oscillators in line with stimulus map and parameters.

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

        """

        if (len(stimulus) != self._num_osc):
            raise NameError("Number of stimulus should be equal number of oscillators in the network.");
        else:
            self._stimulus = [];

            for val in stimulus:
                if (val > 0): self._stimulus.append(self._params.I);
                else: self._stimulus.append(0);


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

        if (self._stimulus is None):
            raise NameError("Stimulus should initialed before creation of the dynamic connections in the network.");

        self._dynamic_coupling = [ [0] * self._num_osc for i in range(self._num_osc)];

        for i in range(self._num_osc):
            neighbors = self.get_neighbors(i);

            if ( (len(neighbors) > 0) and (self._stimulus[i] > 0) ):
                number_stimulated_neighbors = 0.0;
                for j in neighbors:
                    if (self._stimulus[j] > 0):
                        number_stimulated_neighbors += 1.0;

                if (number_stimulated_neighbors > 0):
                    dynamic_weight = self._params.Wt / number_stimulated_neighbors;

                    for j in neighbors:
                        self._dynamic_coupling[i][j] = dynamic_weight;

Response: Create dynamic connections in line with input stimulus.


Instruction:
Write a Python 3 function that can
return a list of all the dynamic and static structures that are used for the given solution.

Response:
def simulate(self, steps, time, stimulus, solution = solve_type.RK4, collect_dynamic = True):
        """!
        @brief Performs static simulation of LEGION oscillatory network.

        @param[in] steps (uint): Number steps of simulations during simulation.
        @param[in] time (double): Time of simulation.
        @param[in] stimulus (list): Stimulus for oscillators, number of stimulus should be equal to number of oscillators,
                   example of stimulus for 5 oscillators [0, 0, 1, 1, 0], value of stimulus is defined by parameter 'I'.
        @param[in] solution (solve_type): Method that is used for differential equation.
        @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics.

        @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time,
                otherwise returns only last values (last step of simulation) of dynamic.

        """

        if (self.__ccore_legion_pointer is not None):
            pointer_dynamic = wrapper.legion_simulate(self.__ccore_legion_pointer, steps, time, solution, collect_dynamic, stimulus);
            return legion_dynamic(None, None, None, pointer_dynamic);

        # Check solver before simulation
        if (solution == solve_type.FAST):
            raise NameError("Solver FAST is not support due to low accuracy that leads to huge error.");

        elif (solution == solve_type.RKF45):
            raise NameError("Solver RKF45 is not support in python version. RKF45 is supported in CCORE implementation.");

        # set stimulus
        self.__create_stimulus(stimulus);

        # calculate dynamic weights
        self.__create_dynamic_connections();

        dyn_exc = None;
        dyn_time = None;
        dyn_ginh = None;

        # Store only excitatory of the oscillator
        if (collect_dynamic == True):
            dyn_exc = [];
            dyn_time = [];
            dyn_ginh = [];

        step = time / steps;
        int_step = step / 10.0;

        for t in numpy.arange(step, time + step, step):
            # update states of oscillators
            self._calculate_states(solution, t, step, int_step);

            # update states of oscillators
            if (collect_dynamic == True):
                dyn_exc.append(self._excitatory);
                dyn_time.append(t);
                dyn_ginh.append(self._global_inhibitor);
            else:
                dyn_exc = self._excitatory;
                dyn_time = t;
                dyn_ginh = self._global_inhibitor;

        return legion_dynamic(dyn_exc, dyn_ginh, dyn_time);


Instruction:
Write a Python 3 function that can
calculate the new states of each oscillator in the network.

Response:
def _calculate_states(self, solution, t, step, int_step):
        """!
        @brief Calculates new state of each oscillator in the network.

        @param[in] solution (solve_type): Type solver of the differential equation.
        @param[in] t (double): Current time of simulation.
        @param[in] step (double): Step of solution at the end of which states of oscillators should be calculated.
        @param[in] int_step (double): Step differentiation that is used for solving differential equation.

        """

        next_excitatory = [0.0] * self._num_osc;
        next_inhibitory = [0.0] * self._num_osc;

        next_potential = [];
        if (self._params.ENABLE_POTENTIONAL is True):
            next_potential = [0.0] * self._num_osc;

        # Update states of oscillators
        for index in range (0, self._num_osc, 1):
            if (self._params.ENABLE_POTENTIONAL is True):
                result = odeint(self._legion_state, [self._excitatory[index], self._inhibitory[index], self._potential[index]], numpy.arange(t - step, t, int_step), (index , ));
                [ next_excitatory[index], next_inhibitory[index], next_potential[index] ] = result[len(result) - 1][0:3];

            else:
                result = odeint(self._legion_state_simplify, [self._excitatory[index], self._inhibitory[index] ], numpy.arange(t - step, t, int_step), (index , ));
                [ next_excitatory[index], next_inhibitory[index] ] = result[len(result) - 1][0:2];

            # Update coupling term
            neighbors = self.get_neighbors(index);

            coupling = 0
            for index_neighbor in neighbors:
                coupling += self._dynamic_coupling[index][index_neighbor] * heaviside(self._excitatory[index_neighbor] - self._params.teta_x);

            self._buffer_coupling_term[index] = coupling - self._params.Wz * heaviside(self._global_inhibitor - self._params.teta_xz);

        # Update state of global inhibitory
        result = odeint(self._global_inhibitor_state, self._global_inhibitor, numpy.arange(t - step, t, int_step), (None, ));
        self._global_inhibitor = result[len(result) - 1][0];

        self._noise = [random.random() * self._params.ro for i in range(self._num_osc)];
        self._coupling_term = self._buffer_coupling_term[:];
        self._inhibitory = next_inhibitory[:];
        self._excitatory = next_excitatory[:];

        if (self._params.ENABLE_POTENTIONAL is True):
            self._potential = next_potential[:];


Instruction:
Write a Python 3 function that can
return new value of global inhibitor.

Response:
def _global_inhibitor_state(self, z, t, argv):
        """!
        @brief Returns new value of global inhibitory

        @param[in] z (dobule): Current value of inhibitory.
        @param[in] t (double): Current time of simulation.
        @param[in] argv (tuple): It's not used, can be ignored.

        @return (double) New value if global inhibitory (not assign).

        """

        sigma = 0.0;

        for x in self._excitatory:
            if (x > self._params.teta_zx):
                sigma = 1.0;
                break;

        return self._params.fi * (sigma - z);


Instruction:
Write a Python 3 function for
returning the new excitatoty and inhibitory parts of the oscillator.

Response:
def _legion_state_simplify(self, inputs, t, argv):
        """!
        @brief Returns new values of excitatory and inhibitory parts of oscillator of oscillator.
        @details Simplify model doesn't consider oscillator potential.

        @param[in] inputs (list): Initial values (current) of oscillator [excitatory, inhibitory].
        @param[in] t (double): Current time of simulation.
        @param[in] argv (uint): Extra arguments that are not used for integration - index of oscillator.

        @return (list) New values of excitatoty and inhibitory part of oscillator (not assign).

        """

        index = argv;

        x = inputs[0];  # excitatory
        y = inputs[1];  # inhibitory

        dx = 3.0 * x - x ** 3.0 + 2.0 - y + self._stimulus[index] + self._coupling_term[index] + self._noise[index];
        dy = self._params.eps * (self._params.gamma * (1.0 + math.tanh(x / self._params.betta)) - y);

        neighbors = self.get_neighbors(index);
        potential = 0.0;

        for index_neighbor in neighbors:
            potential += self._params.T * heaviside(self._excitatory[index_neighbor] - self._params.teta_x);

        return [dx, dy];


Instruction:
Implement a Python 3 function for
returning the new values of excitatoty and inhibitory parts of oscillator and potential of oscillator.

Response:
def _legion_state(self, inputs, t, argv):
        """!
        @brief Returns new values of excitatory and inhibitory parts of oscillator and potential of oscillator.

        @param[in] inputs (list): Initial values (current) of oscillator [excitatory, inhibitory, potential].
        @param[in] t (double): Current time of simulation.
        @param[in] argv (uint): Extra arguments that are not used for integration - index of oscillator.

        @return (list) New values of excitatoty and inhibitory part of oscillator and new value of potential (not assign).

        """

        index = argv;

        x = inputs[0];  # excitatory
        y = inputs[1];  # inhibitory
        p = inputs[2];  # potential

        potential_influence = heaviside(p + math.exp(-self._params.alpha * t) - self._params.teta);

        dx = 3.0 * x - x ** 3.0 + 2.0 - y + self._stimulus[index] * potential_influence + self._coupling_term[index] + self._noise[index];
        dy = self._params.eps * (self._params.gamma * (1.0 + math.tanh(x / self._params.betta)) - y);

        neighbors = self.get_neighbors(index);
        potential = 0.0;

        for index_neighbor in neighbors:
            potential += self._params.T * heaviside(self._excitatory[index_neighbor] - self._params.teta_x);

        dp = self._params.lamda * (1.0 - p) * heaviside(potential - self._params.teta_p) - self._params.mu * p;

        return [dx, dy, dp];


Instruction:
Make a summary of the following Python 3 code
def allocate_map_coloring(self, tolerance = 0.1):

        clusters = self.allocate_color_clusters(tolerance);
        number_oscillators = len(self._dynamic[0]);

        coloring_map = [0] * number_oscillators;

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

        return coloring_map;

Response: Allocate a coloring map for each node in the graph.


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

        for row in range(0, len(graph_matrix)):
            for column in range (0, len(graph_matrix[row])):
                if (graph_matrix[row][column] > 0):
                    self.set_connection(row, column);

Response: Creates the connection in the network in line with graph.


Instruction:
Write a Python 3 script to
allocate clusters in line with state of oscillators.

Response:
def allocate_clusters(self, eps = 0.01, indexes = None, iteration = None):
        """!
        @brief Returns list of clusters in line with state of ocillators (phases).

        @param[in] eps (double): Tolerance level that define maximal difference between phases of oscillators in one cluster.
        @param[in] indexes (list): List of real object indexes and it should be equal to amount of oscillators (in case of 'None' - indexes are in range [0; amount_oscillators]).
        @param[in] iteration (uint): Iteration of simulation that should be used for allocation.

        @return (list) List of clusters, for example [ [cluster1], [cluster2], ... ].)

        """

        return self.allocate_sync_ensembles(eps, indexes, iteration);


Instruction:
Implement a Python 3 function for
animating the allocation of a set of oscillators in a set of data.

Response:
def animate_cluster_allocation(dataset, analyser, animation_velocity = 75, tolerance = 0.1, save_movie = None, title = None):
        """!
        @brief Shows animation of output dynamic (output of each oscillator) during simulation on a circle from [0; 2pi].

        @param[in] dataset (list): Input data that was used for processing by the network.
        @param[in] analyser (syncnet_analyser): Output dynamic analyser of the Sync network.
        @param[in] animation_velocity (uint): Interval between frames in milliseconds.
        @param[in] tolerance (double): Tolerance level that define maximal difference between phases of oscillators in one cluster.
        @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter.
        @param[in] title (string): If it is specified then title will be displayed on the animation plot.

        """

        figure = plt.figure();

        def init_frame():
            return frame_generation(0);

        def frame_generation(index_dynamic):
            figure.clf();
            if (title is not None):
                figure.suptitle(title, fontsize = 26, fontweight = 'bold');

            ax1 = figure.add_subplot(121, projection='polar');

            clusters = analyser.allocate_clusters(eps = tolerance, iteration = index_dynamic);
            dynamic = analyser.output[index_dynamic];

            visualizer = cluster_visualizer(size_row = 2);
            visualizer.append_clusters(clusters, dataset);

            artist1, = ax1.plot(dynamic, [1.0] * len(dynamic), marker = 'o', color = 'blue', ls = '');

            visualizer.show(figure, display = False);
            artist2 = figure.gca();

            return [ artist1, artist2 ];

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

        if (save_movie is not None):
#             plt.rcParams['animation.ffmpeg_path'] = 'D:\\Program Files\\ffmpeg-3.3.1-win64-static\\bin\\ffmpeg.exe';
#             ffmpeg_writer = animation.FFMpegWriter(fps = 15);
#             cluster_animation.save(save_movie, writer = ffmpeg_writer);
            cluster_animation.save(save_movie, writer = 'ffmpeg', fps = 15, bitrate = 1500);
        else:
            plt.show();


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

        if (self._ena_conn_weight is True):
            self._conn_weight = [[0] * self._num_osc for _ in range(0, self._num_osc, 1)];

        maximum_distance = 0;
        minimum_distance = float('inf');

        # Create connections
        for i in range(0, self._num_osc, 1):
            for j in range(i + 1, self._num_osc, 1):
                    dist = euclidean_distance(self._osc_loc[i], self._osc_loc[j]);

                    if (self._ena_conn_weight is True):
                        self._conn_weight[i][j] = dist;
                        self._conn_weight[j][i] = dist;

                        if (dist > maximum_distance): maximum_distance = dist;
                        if (dist < minimum_distance): minimum_distance = dist;

                    if (dist <= radius):
                        self.set_connection(i, j);

        if (self._ena_conn_weight is True):
            multiplier = 1;
            subtractor = 0;

            if (maximum_distance != minimum_distance):
                multiplier = (maximum_distance - minimum_distance);
                subtractor = minimum_distance;

            for i in range(0, self._num_osc, 1):
                for j in range(i + 1, self._num_osc, 1):
                    value_conn_weight = (self._conn_weight[i][j] - subtractor) / multiplier;

                    self._conn_weight[i][j] = value_conn_weight;
                    self._conn_weight[j][i] = value_conn_weight;

Response: Create the connection between oscillators in line with input radius of connectivity.


Instruction:
Write a Python 3 function for
processing the cluster analysis using the CCOS network.

Response:
def process(self, order = 0.998, solution = solve_type.FAST, collect_dynamic = True):
        """!
        @brief Peforms cluster analysis using simulation of the oscillatory network.

        @param[in] order (double): Order of synchronization that is used as indication for stopping processing.
        @param[in] solution (solve_type): Specified type of solving diff. equation.
        @param[in] collect_dynamic (bool): Specified requirement to collect whole dynamic of the network.

        @return (syncnet_analyser) Returns analyser of results of clustering.

        """

        if (self._ccore_network_pointer is not None):
            pointer_output_dynamic = syncnet_process(self._ccore_network_pointer, order, solution, collect_dynamic);
            return syncnet_analyser(None, None, pointer_output_dynamic);
        else:
            output_sync_dynamic = self.simulate_dynamic(order, solution, collect_dynamic);
            return syncnet_analyser(output_sync_dynamic.output, output_sync_dynamic.time, None);


Instruction:
Can you tell what is the following Python 3 function doing
def _phase_kuramoto(self, teta, t, argv):

        index = argv;   # index of oscillator
        phase = 0.0;      # phase of a specified oscillator that will calculated in line with current env. states.

        neighbors = self.get_neighbors(index);
        for k in neighbors:
            conn_weight = 1.0;
            if (self._ena_conn_weight is True):
                conn_weight = self._conn_weight[index][k];

            phase += conn_weight * self._weight * math.sin(self._phases[k] - teta);

        divider = len(neighbors);
        if (divider == 0):
            divider = 1.0;

        return ( self._freq[index] + (phase / divider) );

Response: Returns the new value of the phase of the specified oscillator.


Instruction:
Write a Python 3 script for
showing the connected components in the network.

Response:
def show_network(self):
        """!
        @brief Shows connections in the network. It supports only 2-d and 3-d representation.

        """

        if ( (self._ccore_network_pointer is not None) and (self._osc_conn is None) ):
            self._osc_conn = sync_connectivity_matrix(self._ccore_network_pointer);

        dimension = len(self._osc_loc[0]);
        if ( (dimension != 3) and (dimension != 2) ):
            raise NameError('Network that is located in different from 2-d and 3-d dimensions can not be represented');

        from matplotlib.font_manager import FontProperties;
        from matplotlib import rcParams;

        rcParams['font.sans-serif'] = ['Arial'];
        rcParams['font.size'] = 12;

        fig = plt.figure();
        axes = None;
        if (dimension == 2):
            axes = fig.add_subplot(111);
        elif (dimension == 3):
            axes = fig.gca(projection='3d');

        surface_font = FontProperties();
        surface_font.set_name('Arial');
        surface_font.set_size('12');

        for i in range(0, self._num_osc, 1):
            if (dimension == 2):
                axes.plot(self._osc_loc[i][0], self._osc_loc[i][1], 'bo');
                if (self._conn_represent == conn_represent.MATRIX):
                    for j in range(i, self._num_osc, 1):    # draw connection between two points only one time
                        if (self.has_connection(i, j) == True):
                            axes.plot([self._osc_loc[i][0], self._osc_loc[j][0]], [self._osc_loc[i][1], self._osc_loc[j][1]], 'b-', linewidth = 0.5);

                else:
                    for j in self.get_neighbors(i):
                        if ( (self.has_connection(i, j) == True) and (i > j) ):     # draw connection between two points only one time
                            axes.plot([self._osc_loc[i][0], self._osc_loc[j][0]], [self._osc_loc[i][1], self._osc_loc[j][1]], 'b-', linewidth = 0.5);

            elif (dimension == 3):
                axes.scatter(self._osc_loc[i][0], self._osc_loc[i][1], self._osc_loc[i][2], c = 'b', marker = 'o');

                if (self._conn_represent == conn_represent.MATRIX):
                    for j in range(i, self._num_osc, 1):    # draw connection between two points only one time
                        if (self.has_connection(i, j) == True):
                            axes.plot([self._osc_loc[i][0], self._osc_loc[j][0]], [self._osc_loc[i][1], self._osc_loc[j][1]], [self._osc_loc[i][2], self._osc_loc[j][2]], 'b-', linewidth = 0.5);

                else:
                    for j in self.get_neighbors(i):
                        if ( (self.has_connection(i, j) == True) and (i > j) ):     # draw connection between two points only one time
                            axes.plot([self._osc_loc[i][0], self._osc_loc[j][0]], [self._osc_loc[i][1], self._osc_loc[j][1]], [self._osc_loc[i][2], self._osc_loc[j][2]], 'b-', linewidth = 0.5);

        plt.grid();
        plt.show();


Instruction:
Can you implement a function in Python 3 that
calculates the new states of each oscillator in the network. Returns only excitatory states of oscillators in the network.

Response:
def _calculate_states(self, solution, t, step, int_step):
        """!
        @brief Caclculates new state of each oscillator in the network. Returns only excitatory state of oscillators.

        @param[in] solution (solve_type): Type solver of the differential equations.
        @param[in] t (double): Current time of simulation.
        @param[in] step (uint): Step of solution at the end of which states of oscillators should be calculated.
        @param[in] int_step (double): Differentiation step that is used for solving differential equation.

        @return (list) New states of membrance potentials for peripheral oscillators and for cental elements as a list where
                the last two values correspond to central element 1 and 2.

        """

        next_membrane           = [0.0] * self._num_osc;
        next_active_sodium      = [0.0] * self._num_osc;
        next_inactive_sodium    = [0.0] * self._num_osc;
        next_active_potassium   = [0.0] * self._num_osc;

        # Update states of oscillators
        for index in range (0, self._num_osc, 1):
            result = odeint(self.hnn_state,
                            [ self._membrane_potential[index], self._active_cond_sodium[index], self._inactive_cond_sodium[index], self._active_cond_potassium[index] ],
                            numpy.arange(t - step, t, int_step),
                            (index , ));

            [ next_membrane[index], next_active_sodium[index], next_inactive_sodium[index], next_active_potassium[index] ] = result[len(result) - 1][0:4];

        next_cn_membrane            = [0.0, 0.0];
        next_cn_active_sodium       = [0.0, 0.0];
        next_cn_inactive_sodium     = [0.0, 0.0];
        next_cn_active_potassium    = [0.0, 0.0];

        # Update states of central elements
        for index in range(0, len(self._central_element)):
            result = odeint(self.hnn_state,
                            [ self._central_element[index].membrane_potential, self._central_element[index].active_cond_sodium, self._central_element[index].inactive_cond_sodium, self._central_element[index].active_cond_potassium ],
                            numpy.arange(t - step, t, int_step),
                            (self._num_osc + index , ));

            [ next_cn_membrane[index], next_cn_active_sodium[index], next_cn_inactive_sodium[index], next_cn_active_potassium[index] ] = result[len(result) - 1][0:4];

        # Noise generation
        self._noise = [ 1.0 + 0.01 * (random.random() * 2.0 - 1.0) for i in range(self._num_osc)];

        # Updating states of PNs
        self.__update_peripheral_neurons(t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium);

        # Updation states of CN
        self.__update_central_neurons(t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium);

        return (next_membrane, next_cn_membrane);


Instruction:
How would you explain what the following Python 3 function does
def __update_central_neurons(self, t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium):

        for index in range(0, len(self._central_element)):
            self._central_element[index].membrane_potential = next_cn_membrane[index];
            self._central_element[index].active_cond_sodium = next_cn_active_sodium[index];
            self._central_element[index].inactive_cond_sodium = next_cn_inactive_sodium[index];
            self._central_element[index].active_cond_potassium = next_cn_active_potassium[index];

            if (self._central_element[index].pulse_generation is False):
                if (self._central_element[index].membrane_potential >= 0.0):
                    self._central_element[index].pulse_generation = True;
                    self._central_element[index].pulse_generation_time.append(t);
            elif (self._central_element[index].membrane_potential < 0.0):
                self._central_element[index].pulse_generation = False;

Response: Updates the central neurons in line with new values of current in channels and new in activations.


Instruction:
How would you code a function in Python 3 to
return the new values of excitatory and inhibitory parts of oscillator and potential of oscillator.

Response:
def hnn_state(self, inputs, t, argv):
        """!
        @brief Returns new values of excitatory and inhibitory parts of oscillator and potential of oscillator.

        @param[in] inputs (list): States of oscillator for integration [v, m, h, n] (see description below).
        @param[in] t (double): Current time of simulation.
        @param[in] argv (tuple): Extra arguments that are not used for integration - index of oscillator.

        @return (list) new values of oscillator [v, m, h, n], where:
                v - membrane potantial of oscillator,
                m - activation conductance of the sodium channel,
                h - inactication conductance of the sodium channel,
                n - activation conductance of the potassium channel.

        """

        index = argv;

        v = inputs[0]; # membrane potential (v).
        m = inputs[1]; # activation conductance of the sodium channel (m).
        h = inputs[2]; # inactivaton conductance of the sodium channel (h).
        n = inputs[3]; # activation conductance of the potassium channel (n).

        # Calculate ion current
        # gNa * m[i]^3 * h * (v[i] - vNa) + gK * n[i]^4 * (v[i] - vK) + gL  (v[i] - vL)
        active_sodium_part = self._params.gNa * (m ** 3) * h * (v - self._params.vNa);
        inactive_sodium_part = self._params.gK * (n ** 4) * (v - self._params.vK);
        active_potassium_part = self._params.gL * (v - self._params.vL);

        Iion = active_sodium_part + inactive_sodium_part + active_potassium_part;

        Iext = 0.0;
        Isyn = 0.0;
        if (index < self._num_osc):
            # PN - peripheral neuron - calculation of external current and synaptic current.
            Iext = self._stimulus[index] * self._noise[index];    # probably noise can be pre-defined for reducting compexity

            memory_impact1 = 0.0;
            for i in range(0, len(self._central_element[0].pulse_generation_time)):
                memory_impact1 += self.__alfa_function(t - self._central_element[0].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);

            memory_impact2 = 0.0;
            for i in range(0, len(self._central_element[1].pulse_generation_time)):
                memory_impact2 += self.__alfa_function(t - self._central_element[1].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);

            Isyn = self._params.w2 * (v - self._params.Vsyninh) * memory_impact1 + self._link_weight3[index] * (v - self._params.Vsyninh) * memory_impact2;
        else:
            # CN - central element.
            central_index = index - self._num_osc;
            if (central_index == 0):
                Iext = self._params.Icn1;   # CN1

                memory_impact = 0.0;
                for index_oscillator in range(0, self._num_osc):
                    for index_generation in range(0, len(self._pulse_generation_time[index_oscillator])):
                        memory_impact += self.__alfa_function(t - self._pulse_generation_time[index_oscillator][index_generation], self._params.alfa_excitatory, self._params.betta_excitatory);

                Isyn = self._params.w1 * (v - self._params.Vsynexc) * memory_impact;

            elif (central_index == 1):
                Iext = self._params.Icn2;   # CN2
                Isyn = 0.0;

            else:
                assert 0;

        # Membrane potential
        dv = -Iion + Iext - Isyn;

        # Calculate variables
        potential = v - self._params.vRest;
        am = (2.5 - 0.1 * potential) / (math.exp(2.5 - 0.1 * potential) - 1.0);
        ah = 0.07 * math.exp(-potential / 20.0);
        an = (0.1 - 0.01 * potential) / (math.exp(1.0 - 0.1 * potential) - 1.0);

        bm = 4.0 * math.exp(-potential / 18.0);
        bh = 1.0 / (math.exp(3.0 - 0.1 * potential) + 1.0);
        bn = 0.125 * math.exp(-potential / 80.0);

        dm = am * (1.0 - m) - bm * m;
        dh = ah * (1.0 - h) - bh * h;
        dn = an * (1.0 - n) - bn * n;

        return [dv, dm, dh, dn];


Instruction:
Can you generate the documentation for the following Python 3 function
def __alfa_function(self, time, alfa, betta):

        return alfa * time * math.exp(-betta * time);

Response: Calculates the value of the alfa - function for the given time and alfa and betta parameters.


Instruction:
How would you explain what the following Python 3 function does
def show_grid(cells, data):
        dimension = cells[0].dimensions

        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])
            clique_visualizer.__draw_cells(ax, cells, pairs[index])
            clique_visualizer.__draw_two_dimension_data(ax, data, pairs[index])

        plt.show()

Response: Show the CLIQUE blocks in data space.


Instruction:
Can you create a Python 3 function that
displays CLIQUE clustering results.

Response:
def show_clusters(data, clusters, noise=None):
        """!
        @brief Display CLIQUE clustering results.

        @param[in] data (list): Data that was used for clustering.
        @param[in] clusters (array_like): Clusters that were allocated by the algorithm.
        @param[in] noise (array_like): Noise that were allocated by the algorithm.

        """
        visualizer = cluster_visualizer()
        visualizer.append_clusters(clusters, data)
        visualizer.append_cluster(noise or [], data, marker='x')
        visualizer.show()


Instruction:
Given the following Python 3 function, write the documentation
def __draw_two_dimension_data(ax, data, pair):
        ax.set_xlabel("x%d" % pair[0])
        ax.set_ylabel("x%d" % pair[1])

        for point in data:
            if len(data[0]) > 1:
                ax.plot(point[pair[0]], point[pair[1]], color='red', marker='.')
            else:
                ax.plot(point[pair[0]], 0, color='red', marker='.')
                ax.yaxis.set_ticklabels([])

Response: Draws data in two - dimensional canvas.


Instruction:
Write a Python 3 script to
return a list of logical locations that are neighbors of the given CLIQUE block.

Response:
def get_location_neighbors(self, edge):
        """!
        @brief Forms list of logical location of each neighbor for this particular CLIQUE block.

        @param[in] edge (uint): Amount of intervals in each dimension that is used for clustering process.

        @return (list) Logical location of each neighbor for this particular CLIQUE block.

        """
        neighbors = []

        for index_dimension in range(len(self.__logical_location)):
            if self.__logical_location[index_dimension] + 1 < edge:
                position = self.__logical_location[:]
                position[index_dimension] += 1
                neighbors.append(position)

            if self.__logical_location[index_dimension] - 1 >= 0:
                position = self.__logical_location[:]
                position[index_dimension] -= 1
                neighbors.append(position)

        return neighbors


Instruction:
Write a Python 3 function that can
increment the logical location of the next block.

Response:
def increment(self):
        """!
        @brief Forms logical location for next block.

        """
        for index_dimension in range(self.__dimension):
            if self.__coordiate[index_dimension] + 1 < self.__intervals:
                self.__coordiate[index_dimension] += 1
                return
            else:
                self.__coordiate[index_dimension] = 0

        self.__coordiate = None


Instruction:
Can you tell what is the following Python 3 function doing
def __process_by_ccore(self):
        (self.__clusters, self.__noise, block_logical_locations, block_max_corners, block_min_corners, block_points) = \
            wrapper.clique(self.__data, self.__amount_intervals, self.__density_threshold)

        amount_cells = len(block_logical_locations)
        for i in range(amount_cells):
            self.__cells.append(clique_block(block_logical_locations[i],
                                             spatial_block(block_max_corners[i], block_min_corners[i]),
                                             block_points[i],
                                             True))

Response: This method is used by default by default by default by default by default by default by default.


Instruction:
Can you create a Python 3 function that
checks input arguments of CLIQUE algorithm and if they are not correct then appropriate exception is thrown.

Response:
def __validate_arguments(self):
        """!
        @brief Check input arguments of CLIQUE algorithm and if one of them is not correct then appropriate exception
                is thrown.

        """

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

        if self.__amount_intervals <= 0:
            raise ValueError("Incorrect amount of intervals '%d'. Amount of intervals value should be greater than 0." % self.__amount_intervals)

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


Instruction:
How would you code a function in Python 3 to
allocate clusters for all cells in the CLIQUE block.

Response:
def __allocate_clusters(self):
        """!
        @brief Performs cluster analysis using formed CLIQUE blocks.

        """
        for cell in self.__cells:
            if cell.visited is False:
                self.__expand_cluster(cell)


Instruction:
Can you generate the documentation for the following Python 3 function
def __expand_cluster(self, cell):
        cell.visited = True

        if len(cell.points) <= self.__density_threshold:
            if len(cell.points) > 0:
                self.__noise.extend(cell.points)

            return

        cluster = cell.points[:]
        neighbors = self.__get_neighbors(cell)

        for neighbor in neighbors:
            if len(neighbor.points) > self.__density_threshold:
                cluster.extend(neighbor.points)
                neighbors += self.__get_neighbors(neighbor)

            elif len(neighbor.points) > 0:
                self.__noise.extend(neighbor.points)

        self.__clusters.append(cluster)

Response: Expands a cluster from a given CLIQUE block.


Instruction:
How would you code a function in Python 3 to
return a list of neighbors for the specified CLIQUE block.

Response:
def __get_neighbors(self, cell):
        """!
        @brief Returns neighbors for specified CLIQUE block as clique_block objects.

        @return (list) Neighbors as clique_block objects.

        """
        neighbors = []
        location_neighbors = cell.get_location_neighbors(self.__amount_intervals)

        for i in range(len(location_neighbors)):
            key = self.__location_to_key(location_neighbors[i])
            candidate_neighbor = self.__cell_map[key]

            if not candidate_neighbor.visited:
                candidate_neighbor.visited = True
                neighbors.append(candidate_neighbor)

        return neighbors


Instruction:
Create a Python 3 function to
create a CLIQUE grid that consists of CLIQUE blocks for clustering process.

Response:
def __create_grid(self):
        """!
        @brief Creates CLIQUE grid that consists of CLIQUE blocks for clustering process.

        """
        data_sizes, min_corner, max_corner = self.__get_data_size_derscription()
        dimension = len(self.__data[0])

        cell_sizes = [dimension_length / self.__amount_intervals for dimension_length in data_sizes]

        self.__cells = [clique_block() for _ in range(pow(self.__amount_intervals, dimension))]
        iterator = coordinate_iterator(dimension, self.__amount_intervals)

        point_availability = [True] * len(self.__data)
        self.__cell_map = {}
        for index_cell in range(len(self.__cells)):
            logical_location = iterator.get_coordinate()
            iterator.increment()

            self.__cells[index_cell].logical_location = logical_location[:]

            cur_max_corner, cur_min_corner = self.__get_spatial_location(logical_location, min_corner, max_corner, cell_sizes)
            self.__cells[index_cell].spatial_location = spatial_block(cur_max_corner, cur_min_corner)

            self.__cells[index_cell].capture_points(self.__data, point_availability)

            self.__cell_map[self.__location_to_key(logical_location)] = self.__cells[index_cell]


Instruction:
Can you implement a function in Python 3 that
calculates the spatial location for the specified CLIQUE block with logical coordinates defined by logical_location.

Response:
def __get_spatial_location(self, logical_location, min_corner, max_corner, cell_sizes):
        """!
        @brief Calculates spatial location for CLIQUE block with logical coordinates defined by logical_location.

        @param[in] logical_location (list): Logical location of CLIQUE block for that spatial location should be calculated.
        @param[in] min_corner (list): Minimum corner of an input data.
        @param[in] max_corner (list): Maximum corner of an input data.
        @param[in] cell_sizes (list): Size of CLIQUE block in each dimension.

        @return (list, list): Maximum and minimum corners for the specified CLIQUE block.

        """
        cur_min_corner = min_corner[:]
        cur_max_corner = min_corner[:]
        dimension = len(self.__data[0])
        for index_dimension in range(dimension):
            cur_min_corner[index_dimension] += cell_sizes[index_dimension] * logical_location[index_dimension]

            if logical_location[index_dimension] == self.__amount_intervals - 1:
                cur_max_corner[index_dimension] = max_corner[index_dimension]
            else:
                cur_max_corner[index_dimension] = cur_min_corner[index_dimension] + cell_sizes[index_dimension]

        return cur_max_corner, cur_min_corner


Instruction:
Can you generate the documentation for the following Python 3 function
def __get_data_size_derscription(self):
        min_corner = self.__data[0][:]
        max_corner = self.__data[0][:]

        dimension = len(self.__data[0])

        for index_point in range(1, len(self.__data)):
            for index_dimension in range(dimension):
                coordinate = self.__data[index_point][index_dimension]
                if coordinate > max_corner[index_dimension]:
                    max_corner[index_dimension] = coordinate

                if coordinate < min_corner[index_dimension]:
                    min_corner[index_dimension] = coordinate

        data_sizes = [0.0] * dimension
        for index_dimension in range(dimension):
            data_sizes[index_dimension] = max_corner[index_dimension] - min_corner[index_dimension]

        return data_sizes, min_corner, max_corner

Response: Calculates the data size in each dimension minimum and maximum corners.


Instruction:
Can you implement a function in Python 3 that
returns a list of clusters and local_centers that are used for k - means clustering.

Response:
def __improve_parameters(self, centers, available_indexes = None):
        """!
        @brief Performs k-means clustering in the specified region.

        @param[in] centers (list): Centers of clusters.
        @param[in] available_indexes (list): Indexes that defines which points can be used for k-means clustering, if None - then all points are used.

        @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data.

        """

        if available_indexes and len(available_indexes) == 1:
            index_center = available_indexes[0]
            return [ available_indexes ], self.__pointer_data[index_center]

        local_data = self.__pointer_data
        if available_indexes:
            local_data = [ self.__pointer_data[i] for i in available_indexes ]

        local_centers = centers
        if centers is None:
            local_centers = kmeans_plusplus_initializer(local_data, 2, kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE).initialize()

        kmeans_instance = kmeans(local_data, local_centers, tolerance=self.__tolerance, ccore=False)
        kmeans_instance.process()

        local_centers = kmeans_instance.get_centers()

        clusters = kmeans_instance.get_clusters()
        if available_indexes:
            clusters = self.__local_to_global_clusters(clusters, available_indexes)

        return clusters, local_centers


Instruction:
Given the following Python 3 function, write the documentation
def __local_to_global_clusters(self, local_clusters, available_indexes):

        clusters = []
        for local_cluster in local_clusters:
            current_cluster = []
            for index_point in local_cluster:
                current_cluster.append(available_indexes[index_point])

            clusters.append(current_cluster)

        return clusters

Response: Converts local clusters in specific region define by available_indexes to global clusters.


Instruction:
Make a summary of the following Python 3 code
def __improve_structure(self, clusters, centers):

        allocated_centers = []
        amount_free_centers = self.__kmax - len(centers)

        for index_cluster in range(len(clusters)):
            # solve k-means problem for children where data of parent are used.
            (parent_child_clusters, parent_child_centers) = self.__improve_parameters(None, clusters[index_cluster])

            # If it's possible to split current data
            if len(parent_child_clusters) > 1:
                # Calculate splitting criterion
                parent_scores = self.__splitting_criterion([ clusters[index_cluster] ], [ centers[index_cluster] ])
                child_scores = self.__splitting_criterion([ parent_child_clusters[0], parent_child_clusters[1] ], parent_child_centers)

                split_require = False

                # Reallocate number of centers (clusters) in line with scores
                if self.__criterion == splitting_type.BAYESIAN_INFORMATION_CRITERION:
                    if parent_scores < child_scores: split_require = True

                elif self.__criterion == splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH:
                    # If its score for the split structure with two children is smaller than that for the parent structure,
                    # then representing the data samples with two clusters is more accurate in comparison to a single parent cluster.
                    if parent_scores > child_scores: split_require = True;

                if (split_require is True) and (amount_free_centers > 0):
                    allocated_centers.append(parent_child_centers[0])
                    allocated_centers.append(parent_child_centers[1])

                    amount_free_centers -= 1
                else:
                    allocated_centers.append(centers[index_cluster])

            else:
                allocated_centers.append(centers[index_cluster])

        return allocated_centers

Response: This method is used to improve the best structure for each cluster.


Instruction:
How would you explain what the following Python 3 function does
def __splitting_criterion(self, clusters, centers):

        if self.__criterion == splitting_type.BAYESIAN_INFORMATION_CRITERION:
            return self.__bayesian_information_criterion(clusters, centers)

        elif self.__criterion == splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH:
            return self.__minimum_noiseless_description_length(clusters, centers)

        else:
            assert 0;

Response: Calculates the splitting criterion for the given clusters and centers.


Instruction:
Can you implement a function in Python 3 that
calculates the minimum noiseless description length criterion for input clusters and centers.

Response:
def __minimum_noiseless_description_length(self, clusters, centers):
        """!
        @brief Calculates splitting criterion for input clusters using minimum noiseless description length criterion.

        @param[in] clusters (list): Clusters for which splitting criterion should be calculated.
        @param[in] centers (list): Centers of the clusters.

        @return (double) Returns splitting criterion in line with bayesian information criterion.
                Low value of splitting cretion means that current structure is much better.

        @see __bayesian_information_criterion(clusters, centers)

        """

        scores = float('inf')

        W = 0.0
        K = len(clusters)
        N = 0.0

        sigma_sqrt = 0.0

        alpha = 0.9
        betta = 0.9

        for index_cluster in range(0, len(clusters), 1):
            Ni = len(clusters[index_cluster])
            if Ni == 0:
                return float('inf')

            Wi = 0.0
            for index_object in clusters[index_cluster]:
                # euclidean_distance_square should be used in line with paper, but in this case results are
                # very poor, therefore square root is used to improved.
                Wi += euclidean_distance(self.__pointer_data[index_object], centers[index_cluster])

            sigma_sqrt += Wi
            W += Wi / Ni
            N += Ni

        if N - K > 0:
            sigma_sqrt /= (N - K)
            sigma = sigma_sqrt ** 0.5

            Kw = (1.0 - K / N) * sigma_sqrt
            Ks = ( 2.0 * alpha * sigma / (N ** 0.5) ) * ( (alpha ** 2.0) * sigma_sqrt / N + W - Kw / 2.0 ) ** 0.5

            scores = sigma_sqrt * (2 * K)**0.5 * ((2 * K)**0.5 + betta) / N + W - sigma_sqrt + Ks + 2 * alpha**0.5 * sigma_sqrt / N

        return scores


Instruction:
How would you code a function in Python 3 to
calculate the splitting criterion for input clusters using bayesian information criterion.

Response:
def __bayesian_information_criterion(self, clusters, centers):
        """!
        @brief Calculates splitting criterion for input clusters using bayesian information criterion.

        @param[in] clusters (list): Clusters for which splitting criterion should be calculated.
        @param[in] centers (list): Centers of the clusters.

        @return (double) Splitting criterion in line with bayesian information criterion.
                High value of splitting criterion means that current structure is much better.

        @see __minimum_noiseless_description_length(clusters, centers)

        """

        scores = [float('inf')] * len(clusters)     # splitting criterion
        dimension = len(self.__pointer_data[0])

        # estimation of the noise variance in the data set
        sigma_sqrt = 0.0
        K = len(clusters)
        N = 0.0

        for index_cluster in range(0, len(clusters), 1):
            for index_object in clusters[index_cluster]:
                sigma_sqrt += euclidean_distance_square(self.__pointer_data[index_object], centers[index_cluster]);

            N += len(clusters[index_cluster])

        if N - K > 0:
            sigma_sqrt /= (N - K)
            p = (K - 1) + dimension * K + 1

            # in case of the same points, sigma_sqrt can be zero (issue: #407)
            sigma_multiplier = 0.0
            if sigma_sqrt <= 0.0:
                sigma_multiplier = float('-inf')
            else:
                sigma_multiplier = dimension * 0.5 * log(sigma_sqrt)

            # splitting criterion
            for index_cluster in range(0, len(clusters), 1):
                n = len(clusters[index_cluster])

                L = n * log(n) - n * log(N) - n * 0.5 * log(2.0 * numpy.pi) - n * sigma_multiplier - (n - K) * 0.5

                # BIC calculation
                scores[index_cluster] = L - p * 0.5 * log(N)

        return sum(scores)


Instruction:
Here you have a function in Python 3, explain what it does
def show_clusters(sample, clusters, representatives, **kwargs):

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

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

        for cluster_index in range(len(clusters)):
            visualizer.append_cluster_attribute(offset, cluster_index, [representatives[cluster_index]], '*', 10)

        return visualizer.show(figure=figure, display=display)

Response: Displays the clusters of the given sample and representatives.


Instruction:
Here you have a function in Python 3, explain what it does
def _find_nearest_cluster(self, point):
        index_cluster = -1;
        nearest_distance = float('inf');

        for index in range(len(self._representatives)):
            distance = self._metric(point, self._representatives[index]);
            if distance < nearest_distance:
                index_cluster = index;
                nearest_distance = distance;

        return index_cluster, nearest_distance;

Response: Find nearest cluster to the specified point.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _update_representative(self, index_cluster, point):
        length = len(self._clusters[index_cluster]);
        rep = self._representatives[index_cluster];

        for dimension in range(len(rep)):
            rep[dimension] = ( (length - 1) * rep[dimension] + point[dimension] ) / length;

Response: Update the cluster representative in line with new cluster size and added point to it.


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

        second_layer_analysers = analyser.get_second_layer_analysers();
        analysers_sequence = [ object_segment_analyser['analyser'] for object_segment_analyser in second_layer_analysers ]

        sync_visualizer.show_output_dynamics(analysers_sequence);

Response: Show the dynamic output of the second layer.


Instruction:
Make a summary of the following Python 3 code
def allocate_colors(self, eps = 0.01, noise_size = 1):

        segments = self.__color_analyser.allocate_clusters(eps);
        real_segments = [cluster for cluster in segments if len(cluster) > noise_size];
        return real_segments;

Response:
!
        @brief Allocates color segments.

        @param[in] eps (double): Tolerance level that define maximal difference between phases of oscillators in one segment.
        @param[in] noise_size (uint): Threshold that defines noise - segments size (in pixels) that is less then the threshold is considered as a noise.

        @return (list) Color segments where each color segment consists of indexes of pixels that forms color segment.


Instruction:
Can you write a function in Python 3 where it
allocates objects from the object segments in the system.

Response:
def allocate_objects(self, eps = 0.01, noise_size = 1):
        """!
        @brief Allocates object segments.

        @param[in] eps (double): Tolerance level that define maximal difference between phases of oscillators in one segment.
        @param[in] noise_size (uint): Threshold that defines noise - segments size (in pixels) that is less then the threshold is considered as a noise.

        @return (list) Object segments where each object segment consists of indexes of pixels that forms object segment.

        """

        if (self.__object_segment_analysers is None):
            return [];

        segments = [];
        for object_segment_analyser in self.__object_segment_analysers:
            indexes = object_segment_analyser['color_segment'];
            analyser = object_segment_analyser['analyser'];

            segments += analyser.allocate_clusters(eps, indexes);

        real_segments = [segment for segment in segments if len(segment) > noise_size];
        return real_segments;


Instruction:
Can you generate a brief explanation for the following Python 3 code
def process(self, image_source, collect_dynamic = False, order_color = 0.9995, order_object = 0.999):

        self.__order_color  = order_color
        self.__order_object = order_object

        data = read_image(image_source)
        color_analyser = self.__analyse_colors(data, collect_dynamic)

        if self.__object_radius is None:
            return syncsegm_analyser(color_analyser, None)

        object_segment_analysers = self.__analyse_objects(image_source, color_analyser, collect_dynamic)
        return syncsegm_analyser(color_analyser, object_segment_analysers)

Response: This method is used to process the image file and return an Analyser object.


Instruction:
How would you explain what the following Python 3 function does
def __analyse_colors(self, image_data, collect_dynamic):

        network = syncnet(image_data, self.__color_radius, initial_phases = initial_type.RANDOM_GAUSSIAN, ccore = self.__ccore);
        analyser = network.process(self.__order_color, solve_type.FAST, collect_dynamic);

        return analyser;

Response: Analyse the colors of the first layer of the image.


Instruction:
Given the following Python 3 function, write the documentation
def __analyse_objects(self, image_source, color_analyser, collect_dynamic):

        # continue analysis
        pointer_image = Image.open(image_source);
        image_size = pointer_image.size;

        object_analysers = [];

        color_segments = color_analyser.allocate_clusters();

        for segment in color_segments:
            object_analyser = self.__analyse_color_segment(image_size, segment, collect_dynamic);
            if (object_analyser is not None):
                object_analysers.append( { 'color_segment': segment, 'analyser': object_analyser } );

        pointer_image.close();
        return object_analysers;

Response: Analyse objects in the second layer of the network.


Instruction:
Write a Python 3 script for
analysing a single color segment of a single image.

Response:
def __analyse_color_segment(self, image_size, color_segment, collect_dynamic):
        """!
        @brief Performs object segmentation of separate segment.

        @param[in] image_size (list): Image size presented as a [width x height].
        @param[in] color_segment (list): Image segment that should be processed.
        @param[in] collect_dynamic (bool): If 'True' then whole dynamic of the second layer of the network is collected.

        @return (syncnet_analyser) Analyser of object segmentation results of the second layer.

        """
        coordinates = self.__extract_location_coordinates(image_size, color_segment);

        if (len(coordinates) < self.__noise_size):
            return None;

        network = syncnet(coordinates, self.__object_radius, initial_phases = initial_type.EQUIPARTITION, ccore = True);
        analyser = network.process(self.__order_object, solve_type.FAST, collect_dynamic);

        return analyser;


Instruction:
Given the following Python 3 function, write the documentation
def __extract_location_coordinates(self, image_size, color_segment):
        coordinates = [];
        for index in color_segment:
            y = floor(index / image_size[0]);
            x = index - y * image_size[0];

            coordinates.append([x, y]);

        return coordinates;

Response: Returns a list of coordinates of each pixel in color_segment that are located in image_size.