Check validity of supplied k-break and then applies it to current :class:`BreakpointGraph`

        Only :class:`bg.kbreak.KBreak` (or its heirs) instances are allowed as ``kbreak`` argument.
        KBreak must correspond to the valid kbreak and, since some changes to its internals might have been done since its creation, a validity check in terms of starting/resulting edges is performed.
        All vertices in supplied KBreak (except for paired infinity vertices) must be present in current :class:`BreakpointGraph`.
        For all supplied pairs of vertices (except for paired infinity vertices), there must be edges between such pairs of vertices, at least one of which must contain a multicolor matching a multicolor of supplied kbreak.

        Edges of specified in kbreak multicolor are deleted between supplied pairs of vertices in kbreak.start_edges (except for paired infinity vertices).
        New edges of specified in kbreak multicolor are added between all pairs of vertices in kbreak.result_edges (except for paired infinity vertices).
        If after the kbreak application there is an infinity vertex, that now has no edges incident to it, it is deleted form the current :class:`BreakpointGraph`.

        :param kbreak: a k-break to be applied to current :class:`BreakpointGraph`
        :type kbreak: `bg.kbreak.KBreak`
        :param merge: a flag to indicate on how edges, that will be created by a k-break, will be added to current :class:`BreakpointGraph`
        :type merge: ``Boolean``
        :return: nothing, performs inplace changes
        :rtype: ``None``
        :raises: ``ValueError``, ``TypeError``

def apply_kbreak(self, kbreak, merge=True):
        """ Check validity of supplied k-break and then applies it to current :class:`BreakpointGraph`

        Only :class:`bg.kbreak.KBreak` (or its heirs) instances are allowed as ``kbreak`` argument.
        KBreak must correspond to the valid kbreak and, since some changes to its internals might have been done since its creation, a validity check in terms of starting/resulting edges is performed.
        All vertices in supplied KBreak (except for paired infinity vertices) must be present in current :class:`BreakpointGraph`.
        For all supplied pairs of vertices (except for paired infinity vertices), there must be edges between such pairs of vertices, at least one of which must contain a multicolor matching a multicolor of supplied kbreak.

        Edges of specified in kbreak multicolor are deleted between supplied pairs of vertices in kbreak.start_edges (except for paired infinity vertices).
        New edges of specified in kbreak multicolor are added between all pairs of vertices in kbreak.result_edges (except for paired infinity vertices).
        If after the kbreak application there is an infinity vertex, that now has no edges incident to it, it is deleted form the current :class:`BreakpointGraph`.

        :param kbreak: a k-break to be applied to current :class:`BreakpointGraph`
        :type kbreak: `bg.kbreak.KBreak`
        :param merge: a flag to indicate on how edges, that will be created by a k-break, will be added to current :class:`BreakpointGraph`
        :type merge: ``Boolean``
        :return: nothing, performs inplace changes
        :rtype: ``None``
        :raises: ``ValueError``, ``TypeError``
        """
        ############################################################################################################
        #
        # k-break must ba valid to be applied
        #
        ############################################################################################################
        vertices = {}
        edge_data = {}
        if not isinstance(kbreak, KBreak):
            raise TypeError("Only KBreak and derivatives are allowed as kbreak argument")
        if not KBreak.valid_kbreak_matchings(kbreak.start_edges, kbreak.result_edges):
            raise ValueError("Supplied KBreak is not valid form perspective of starting/resulting sets of vertices")
        for vertex1, vertex2 in kbreak.start_edges:

            if vertex1.is_infinity_vertex and vertex2.is_infinity_vertex:
                ############################################################################################################
                #
                # when we encounter a fully infinity edge (both vertices are infinity vertices)
                # we shall not check if they are present in the current graph, because hat portion of a kbreak is artificial
                #
                ############################################################################################################
                continue
            if vertex1 not in self.bg or vertex2 not in self.bg:
                raise ValueError("Supplied KBreak targets vertices (`{v1}` and `{v2}`) at least one of which "
                                 "does not exist in current BreakpointGraph"
                                 "".format(v1=vertex1.name, v2=vertex2.name))
        for vertex1, vertex2 in kbreak.start_edges:
            if vertex1.is_infinity_vertex and vertex2.is_infinity_vertex:
                continue
            for bgedge in self.__edges_between_two_vertices(vertex1=vertex1, vertex2=vertex2):
                ############################################################################################################
                #
                # at least one edge between supplied pair of vertices must contain a multicolor that is specified for the kbreak
                #
                ############################################################################################################
                if kbreak.multicolor <= bgedge.multicolor:
                    break
            else:
                raise ValueError("Some targeted by kbreak edge with specified multicolor does not exists")
        for vertex1, vertex2 in kbreak.start_edges:
            if vertex1.is_infinity_vertex and vertex2.is_infinity_vertex:
                continue
            v1 = self.__get_vertex_by_name(vertex_name=vertex1.name)
            vertices[v1] = v1
            v2 = self.__get_vertex_by_name(vertex_name=vertex2.name)
            vertices[v2] = v2
            bgedge = BGEdge(vertex1=v1, vertex2=v2, multicolor=kbreak.multicolor)
            candidate_data, candidate_id, candidate_score = self.__determine_most_suitable_edge_for_deletion(
                bgedge=bgedge)
            data = candidate_data["attr_dict"]["data"]
            edge_data[v1] = data
            edge_data[v2] = data
            self.__delete_bgedge(bgedge=bgedge, keep_vertices=True)
        for vertex_set in kbreak.start_edges:
            for vertex in vertex_set:
                if vertex.is_infinity_vertex and vertex in self.bg:
                    ############################################################################################################
                    #
                    # after the first portion of a kbreak is performed one must make sure we don't leave any infinity vertices
                    # that have edges going to them, as infinity vertex is a special artificial vertex
                    #  and it has meaning only if there are edges going to / from it
                    #
                    ############################################################################################################
                    if len(list(self.get_edges_by_vertex(vertex=vertex))) == 0:
                        self.bg.remove_node(vertex)
        for vertex1, vertex2 in kbreak.result_edges:
            if vertex1.is_infinity_vertex and vertex2.is_infinity_vertex:
                ############################################################################################################
                #
                # if we encounter a pair of infinity vertices in result edges set, we shall not add them
                # as at least a part of kbreak corresponded to fusion
                # and those infinity edges on their own won't have any meaning
                #
                ############################################################################################################
                continue
            origin = kbreak.data.get("origin", None)
            v1 = vertices.get(vertex1, vertex1)
            v2 = vertices.get(vertex2, vertex2)
            bg_edge = BGEdge(vertex1=v1, vertex2=v2, multicolor=kbreak.multicolor)
            if "origin" in bg_edge.data:
                bg_edge.data["origin"] = origin
            if kbreak.is_a_fusion:
                edge1_data = edge_data[v1]
                edge2_data = edge_data[v2]
                merged_edge_fragment_data = merge_fragment_edge_data(edge1_data["fragment"], edge2_data["fragment"])
                result_edge_data = {}
                recursive_dict_update(result_edge_data, edge1_data)
                recursive_dict_update(result_edge_data, edge2_data)
                recursive_dict_update(result_edge_data, {"fragment": merged_edge_fragment_data})
                recursive_dict_update(bg_edge.data, result_edge_data)
            self.__add_bgedge(bg_edge, merge=merge)