Py下對圖節點洗牌的小程序

NetworkX包中似乎沒有現成的對圖洗牌的函數

寫一個,如下

'''

shuffle_graph - This is a graph shuffling package.

Copyright (C) 2019  sosei

This program is free software: you can redistribute it and/or modify

it under the terms of the GNU Affero General Public License as published

by the Free Software Foundation, either version 3 of the License, or

(at your option) any later version.

This program is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License

along with this program.  If not, see <https://www.gnu.org/licenses/>.

'''

__all__ = ['calculate_number_of_shuffles_required_under_default_random_function', 'shuffle_graph']

def calculate_number_of_shuffles_required_under_default_random_function(node_number: int) -> int:

    '''

        Python's random number function USES the Mersenne Twister algorithm, which has a period of 2**19937-1.If the total permutation of graph nodes is larger than the random function period, the card cannot be shuffled only once.

        The total permutation of a graph node is "factorial of the number of nodes".The number of binary digits of the total number of permutations can be calculated by Stirling's formula.


        >>> calculate_number_of_shuffles_required_under_default_random_function(1000)

        1

        >>> calculate_number_of_shuffles_required_under_default_random_function(10000)

        6

    '''


    import math

    if node_number > 0:

        bit_length_of_permutation_number = math.ceil(math.log2(2*math.pi*node_number)/2 + math.log2(node_number/math.e)*node_number)  #圖節點的全排列量是“節點數的階乘”。而全排列量的二進制位數可用Stirling公式算出

        shuffle_number = math.ceil(bit_length_of_permutation_number/19937)  #Python的隨機數函數使用Mersenne Twister算法,它週期爲2**19937-1。圖節點全排列量大於隨即發生函數週期的話就不能只洗牌一遍

    else:

        shuffle_number = 0

    return shuffle_number

def shuffle_graph(data_graph: 'NetworkXGraphObject', shuffle_number: int, seed: int = None) -> 'NetworkXGraphObject':

    '''

        Returns a new graph, shuffling the order of the nodes in the input data_graph, but the relationship between the nodes remains the same. The data_graph doesn't change.


        Parameters

        ----------

        data_graph : NetworkXGraphObject

            A NetworkX graph object.


        shuffle_number : integer

            Set the number of shuffles.


        seed : integer, random_state, or None (default)

            Indicator of random number generation state.


        Returns

        -------

        new_order_data_graph : NetworkXGraphObject

            Returns a new graph that shuffles the order of nodes but keeps the relationships between them the same.


        Examples

        --------

        >>> from networkx.classes.graph import Graph

        >>> G = Graph({0: {1: {}}, 1: {0: {}, 2: {}}, 2: {1: {}, 3: {}}, 3: {2: {}, 4: {}}, 4: {3: {}}})

        >>> shuffle_graph(G, 1, 65535).adj  #Set seed to make the results repeatable.

        AdjacencyView({3: {2: {}, 4: {}}, 4: {3: {}}, 1: {0: {}, 2: {}}, 2: {3: {}, 1: {}}, 0: {1: {}}})

    '''


    import random

    from networkx.classes.graph import Graph

    from networkx.classes.digraph import DiGraph

    from networkx.classes.multigraph import MultiGraph

    from networkx.classes.multidigraph import MultiDiGraph

    from networkx.convert import from_dict_of_dicts


    random.seed(seed)


    list_of_nodes = list(data_graph.nodes)

    for _i in range(shuffle_number):

        random.shuffle(list_of_nodes)

    new_order_data_graph = dict()

    for node in list_of_nodes:

        new_order_data_graph.update({node: data_graph[node]})

    if data_graph.is_directed():

        if data_graph.is_multigraph():

            new_order_data_graph = from_dict_of_dicts(new_order_data_graph, create_using = MultiDiGraph, multigraph_input = True)

        else:

            new_order_data_graph = from_dict_of_dicts(new_order_data_graph, create_using = DiGraph)

    else:

        if data_graph.is_multigraph():

            new_order_data_graph = from_dict_of_dicts(new_order_data_graph, create_using = MultiGraph, multigraph_input = True)

        else:

            new_order_data_graph = from_dict_of_dicts(new_order_data_graph, create_using = Graph)

    return new_order_data_graph

對圖的洗牌就是改變圖數據結構中節點的順序,節點間的邊關係不變

>>> from networkx.classes.graph import Graph

>>> G = Graph({0: {1: {}}, 1: {0: {}, 2: {}}, 2: {1: {}, 3: {}}, 3: {2: {}, 4: {}}, 4: {3: {}}})

>>> shuffle_graph(G, 1).adj

AdjacencyView({1: {0: {}, 2: {}}, 4: {3: {}}, 2: {1: {}, 3: {}}, 3: {4: {}, 2: {}}, 0: {1: {}}})

這樣的

已經發布到了PyPI上,可以很方便的安裝分發了

pip install shuffle-graph

程序裏引用:

from shuffle_graph_package import *

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章