Guest User

Untitled

a guest
Jun 8th, 2023
236
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.39 KB | Source Code | 0 0
  1. import pandas as pd
  2. import ast
  3. import networkx as nx
  4. from networkx.algorithms.community.lukes import lukes_partitioning
  5. from networkx.algorithms.community.modularity_max import greedy_modularity_communities
  6. import os
  7. import pickle
  8. import matplotlib.pyplot as plt
  9. import math
  10. import random
  11. import heapq
  12. import numpy as np
  13. import statistics
  14. import datetime
  15.  
  16. GPICKLE = "graph.gpickle"
  17.  
  18. class BalancedPartitioner:
  19.  
  20.     def __init__(self, graph, classes = 52):
  21.         self.G = graph
  22.         nx.set_node_attributes(self.G, None, "colour")
  23.         self.classes = classes
  24.         self.coloured_count = 0
  25.         self.neighbour_ques = [[] for _ in range(classes)]
  26.         self.total_weights = [0 for _ in range(classes)]
  27.         self.emptied_ques = [False for _ in range(classes)]
  28.  
  29.         # assign colour to highest degrees
  30.         sorted_nodes = sorted(self.G.degree, key=lambda x: x[1], reverse=True)
  31.         # instead use sample
  32.        
  33.         node_sample = random.sample(sorted(self.G.nodes), classes)
  34.         self.target = len(sorted_nodes)
  35.  
  36.         # or node attributes
  37.         # easier to check if a node has been coloured
  38.         # harder to convert to a partition list (probably not an issue)
  39.         if classes > self.target:
  40.             print("Classes > graph size")
  41.             quit()
  42.  
  43.         for index in range(classes):
  44.             # node = sorted_nodes[index][0]
  45.             node = node_sample[index]
  46.             self.colour_node(node, index)
  47.        
  48.         self.que_clean_up()
  49.        
  50.         while self.coloured_count < self.target:
  51.             # print("{} of {}".format(self.coloured_count, self.target))
  52.             # figure out which combination of queed nodes and class weights generates the minimum total weight
  53.             # candidates = [self.total_weights[i] + self.neighbour_ques[i][0][0] for i in range(classes)]
  54.             # print(candidates)
  55.             min_colour = self.get_next_candidate()
  56.  
  57.             # add node node node to colour
  58.             chosen_node = heapq.heappop(self.neighbour_ques[min_colour])[1]
  59.             self.colour_node(chosen_node, min_colour)
  60.  
  61.             # run que clean up
  62.             self.que_clean_up()
  63.        
  64.  
  65.     def get_next_candidate(self):
  66.         minimum = None
  67.         min_colour = 0
  68.         for i in range(self.classes):
  69.             if not self.emptied_ques[i]:
  70.                 weight_sum = self.total_weights[i] + self.neighbour_ques[i][0][0]
  71.                 if (minimum is None) or (weight_sum < minimum) :
  72.                     min_colour = i
  73.                     minimum = weight_sum
  74.        
  75.         return min_colour
  76.  
  77.     def colour_node(self, node, colour):
  78.         # colour node and track neighbours
  79.         if self.G.nodes[node]["colour"] is not None:
  80.             print("problem")
  81.             print(node)
  82.             print(self.G.nodes[node])
  83.             quit()
  84.  
  85.         self.G.nodes[node]["colour"] = colour
  86.         self.total_weights[colour] += self.G.nodes[node]["weight"]
  87.         self.coloured_count += 1
  88.         # que up neighbouring uncoloured nodes
  89.         for neighbour in self.G.neighbors(node):
  90.             attributes = self.G.nodes[neighbour]
  91.             heapq.heappush(self.neighbour_ques[colour], (attributes["weight"], neighbour))
  92.  
  93.  
  94.     def que_clean_up(self):
  95.         # check if ques have uncoloured node at head and clean up ques if empty
  96.         for colour in range(self.classes):
  97.             if self.emptied_ques[colour]:
  98.                 continue
  99.  
  100.             # check for valid nodes
  101.             while True:
  102.                 try:
  103.                     next_neighbour = self.neighbour_ques[colour][0][1]
  104.                     if self.G.nodes[next_neighbour]["colour"] is None:
  105.                         # valid option so break
  106.                         break
  107.                     else:
  108.                         # already coloured so pop object
  109.                         thing = heapq.heappop(self.neighbour_ques[colour])
  110.                 except:
  111.                     # track emptied que
  112.                     self.emptied_ques[colour] = True
  113.                     # print("Emptied candidates for colour : {}".format(colour))
  114.                     break
  115.  
  116.             # colour += 1
  117.  
  118. def monte_carlo_partitioner(G, classes = 52, repetitions = 100000):
  119.     best_partition = []
  120.     smallest_weight_std = None
  121.     for repeat_count in range(repetitions):
  122.         print("Repetition {} of {}".format(repeat_count, repetitions))
  123.         working_G = G.copy()
  124.         balanced_part = BalancedPartitioner(working_G, classes = classes)
  125.         partition = [[] for _ in range(52)]
  126.         weights = [0 for _ in range(52)]
  127.         for node in working_G.nodes:
  128.             node_atr = working_G.nodes[node]
  129.             partition[node_atr["colour"]].append(node)
  130.             weights[node_atr["colour"]] += node_atr["weight"]
  131.  
  132.         weight_std = statistics.stdev(weights)
  133.         print(weight_std)
  134.         if smallest_weight_std is None or weight_std < smallest_weight_std:
  135.             best_partition = partition
  136.             smallest_weight_std = weight_std
  137.    
  138.     print(smallest_weight_std)
  139.     return best_partition
  140.  
  141.  
  142. if __name__ == '__main__':
  143.     G = nx.Graph()
  144.  
  145.     with open(GPICKLE, 'rb') as f:
  146.         G = pickle.load(f)
  147.  
  148.     start_time = datetime.datetime.now()
  149.     partition = monte_carlo_partitioner(G, classes = 52)
  150.     end_time = datetime.datetime.now()
  151.     print("Time : {}".format(end_time - start_time))
Advertisement
Add Comment
Please, Sign In to add comment