Advertisement
999ms

Untitled

Jul 26th, 2020
1,736
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.69 KB | None | 0 0
  1. import ipaddress
  2. from random import randint
  3. from random import shuffle
  4. import time
  5.  
  6.  
  7. #############################################################
  8. class BinaryTrie():
  9.     def __init__(self):
  10.         self.MASK = (1 << 31) - 1
  11.         self.nodes = [0 for _ in range(64)]
  12.         self.empty_nodes = [63 - i for i in range(63)]
  13.  
  14.     def __sizeof__(self):
  15.         return self.nodes.__sizeof__() + self.empty_nodes.__sizeof__()
  16.  
  17.     def _get_left(self, value):
  18.         return (value >> 1) & self.MASK
  19.  
  20.     def _get_right(self, value):
  21.         return value >> (31 + 1)
  22.  
  23.     def _get_type(self, value):
  24.         return value & 1
  25.  
  26.     def _create_node(self):
  27.         if len(self.empty_nodes) == 0:
  28.             self.empty_nodes = [31 + len(self.nodes) - i for i in range(32)]
  29.             self.nodes += [0 for _ in range(32)]
  30.         index = self.empty_nodes.pop()
  31.         return index
  32.  
  33.     def _remove_nodes(self, node):
  34.         if node == 0:
  35.             return
  36.         self.empty_nodes.append(node)
  37.         left_node = self._get_left(self.nodes[node])
  38.         self._remove_nodes(left_node)
  39.         right_node = self._get_right(self.nodes[node])
  40.         self._remove_nodes(right_node)
  41.         self.nodes[node] = 0
  42.  
  43.     def add(self, address):
  44.         value, size = self.change_format(address)
  45.         current_node = 0
  46.         for i in range(size):
  47.             bit = 31 - i
  48.             if self._get_type(self.nodes[current_node]) == 1:  # leaf
  49.                 return
  50.             if (value >> bit) & 1 == 0:
  51.                 current_left = self._get_left(self.nodes[current_node])
  52.                 if current_left == 0:
  53.                     current_left = self._create_node()
  54.                     self.nodes[current_node] |= current_left << 1
  55.                 current_node = current_left
  56.             else:
  57.                 current_right = self._get_right(self.nodes[current_node])
  58.                 if current_right == 0:
  59.                     current_right = self._create_node()
  60.                     self.nodes[current_node] |= current_right << (31 + 1)
  61.                 current_node = current_right
  62.  
  63.         current_left = self._get_left(self.nodes[current_node])  # delete children if a vertex added
  64.         current_right = self._get_right(self.nodes[current_node])
  65.  
  66.         self._remove_nodes(current_left)
  67.         self._remove_nodes(current_right)
  68.  
  69.         self.nodes[current_node] = 1  # leaf
  70.  
  71.     def __contains__(self, address):
  72.         value, size = self.change_format(address)
  73.         current_node = 0
  74.         for i in range(size):
  75.             bit = 31 - i
  76.             if self._get_type(self.nodes[current_node]) == 1:
  77.                 return True
  78.             if (value >> bit) & 1 == 0:
  79.                 current_left = self._get_left(self.nodes[current_node])
  80.                 if current_left == 0:
  81.                     return False
  82.                 current_node = current_left
  83.             else:
  84.                 current_right = self._get_right(self.nodes[current_node])
  85.                 if current_right == 0:
  86.                     return False
  87.                 current_node = current_right
  88.         return self._get_type(self.nodes[current_node]) == 1
  89.  
  90.     def change_format(self, address):
  91.         if '/' in address:
  92.             address, routing_prefix = address.split('/')
  93.             size = 32 - int(routing_prefix)
  94.         else:
  95.             size = 0
  96.  
  97.         address = list(map(int, address.split('.')))
  98.  
  99.         value = 0
  100.         for item in address:
  101.             value <<= 8
  102.             value ^= item
  103.  
  104.         value >>= size
  105.         value <<= size
  106.         return value, 32 - size
  107.  
  108.  
  109. ##############################################################
  110. def add_set(subnet):
  111.     try:
  112.         addresses_set.add(ipaddress.ip_network(subnet))
  113.     except Exception:
  114.         subnet = ipaddress.ip_interface(subnet)
  115.         addresses_set.add(subnet.network)
  116.  
  117.  
  118. def contains_set(address):
  119.     address = ipaddress.ip_address(address)
  120.     for subnet in addresses_set:
  121.         if address in subnet:
  122.             return True
  123.     return False
  124.  
  125.  
  126. def add_list(subnet):
  127.     try:
  128.         addresses_list.append(ipaddress.ip_network(subnet))
  129.     except Exception:
  130.         subnet = ipaddress.ip_interface(subnet)
  131.         addresses_list.append(subnet.network)
  132.  
  133.  
  134. def contains_list(address):
  135.     address = ipaddress.ip_address(address)
  136.     for subnet in addresses_list:
  137.         if address in subnet:
  138.             return True
  139.     return False
  140.  
  141.  
  142. #### TEST PART ####
  143.  
  144. def get_rand_address(N):
  145.     mask = [str(randint(1, 255)) + '.' + str(randint(1, 255)) + '.' + str(randint(1, 255)) + '.' + str(randint(1, 255))
  146.             for i in range(N)]
  147.     submask = [mask[i] + '/' + str(j) for i in range(N) for j in range(8, 32)]
  148.     shuffle(submask)
  149.     return submask
  150.  
  151.  
  152. def test_add(N):
  153.     addresses = get_rand_address(N)
  154.     times = [[] for _ in range(3)]
  155.     memories = [[] for _ in range(3)]
  156.  
  157.     for i in range(0, N, 100):
  158.         current_addresses = [addresses[i + j] for j in range(100)]
  159.         start = time.time()
  160.         for address in current_addresses:
  161.             add_set(address)
  162.         time_set = time.time() - start
  163.         times[0].append(time_set + (times[0][-1] if len(times[0]) else 0))
  164.         memories[0].append(addresses_set.__sizeof__())
  165.  
  166.         start = time.time()
  167.         for address in current_addresses:
  168.             add_list(address)
  169.         time_list = time.time() - start
  170.         times[1].append(time_list + (times[1][-1] if len(times[1]) else 0))
  171.         memories[1].append(addresses_list.__sizeof__())
  172.  
  173.         start = time.time()
  174.         for address in current_addresses:
  175.             binaryTrie.add(address)
  176.         time_SUPERTREE = time.time() - start
  177.         times[2].append(time_SUPERTREE + (times[2][-1] if len(times[2]) else 0))
  178.         memories[2].append(binaryTrie.__sizeof__())
  179.  
  180.     return [times, memories]
  181.  
  182.  
  183. check1 = []
  184. check2 = []
  185. check3 = []
  186.  
  187.  
  188. def test_contains(N):
  189.     addresses = get_rand_address(N)
  190.  
  191.     for i in range(len(addresses)):
  192.         if '/' in addresses[i]:
  193.             pref, suf = addresses[i].split('/')
  194.             addresses[i] = pref
  195.  
  196.     times = [[] for _ in range(3)]
  197.     for i in range(0, N, 100):
  198.         current_addresses = [addresses[i + j] for j in range(100)]
  199.  
  200.         start = time.time()
  201.         for address in current_addresses:
  202.             check1.append(contains_set(address))
  203.         time_set = time.time() - start
  204.         times[0].append(time_set + (times[0][-1] if len(times[0]) else 0))
  205.  
  206.         start = time.time()
  207.         for address in current_addresses:
  208.             check2.append(contains_list(address))
  209.         time_list = time.time() - start
  210.         start = time.time()
  211.         times[1].append(time_list + (times[1][-1] if len(times[1]) else 0))
  212.  
  213.         for address in current_addresses:
  214.             check3.append(binaryTrie.__contains__(address))
  215.         time_SUPERTREE = time.time() - start
  216.         times[2].append(time_SUPERTREE + (times[2][-1] if len(times[2]) else 0))
  217.  
  218.     return times
  219.  
  220.  
  221. addresses_set = set()
  222. addresses_list = []
  223. binaryTrie = BinaryTrie()
  224. import matplotlib.pyplot as plt
  225.  
  226. N = 100000
  227. print(N)
  228. times_add, memories = test_add(N)
  229. for i in range(len(times_add)):
  230.     for j in range(len(times_add[0])):
  231.         times_add[i][j] *= 1000
  232. print('test_add done')
  233. ox = [i for i in range(0, N, 100)]
  234.  
  235. fig, axes = plt.subplots(nrows=1, ncols=1)
  236. axes.plot(ox, times_add[0], color='#00dd00', label="Set")
  237. axes.plot(ox, times_add[1], color='#dd0000', label="List")
  238. axes.plot(ox, times_add[2], color='#0000dd', label="Trie")
  239. axes.legend(loc="upper left")
  240. axes.set_xlabel("Количество подсетей")
  241. axes.set_ylabel("Время работы add")
  242. fig.set_size_inches(10, 7)
  243. plt.show()
  244.  
  245. fig, axes = plt.subplots(nrows=1, ncols=1)
  246. axes.plot(ox, memories[0], color='#00dd00', label="Set")
  247. axes.plot(ox, memories[1], color='#dd0000', label="List")
  248. axes.plot(ox, memories[2], color='#0000dd', label="Trie")
  249. axes.legend(loc="upper left")
  250. axes.set_xlabel("Количество подсетей")
  251. axes.set_ylabel('Memory')
  252. fig.set_size_inches(10, 7)
  253. plt.show()
  254.  
  255. N = 1000
  256. ox = [i for i in range(0, N, 100)]
  257. times_contains = test_contains(N)
  258. for i in range(len(times_contains)):
  259.     for j in range(len(times_contains[0])):
  260.         times_contains[i][j] *= 1000
  261. print('test contains done')
  262. fig, axes = plt.subplots(nrows=1, ncols=1)
  263. axes.plot(ox, times_contains[0], color='#00dd00', label="Set")
  264. axes.plot(ox, times_contains[1], color='#dd0000', label="List")
  265. axes.plot(ox, times_contains[2], color='#0000dd', label="Trie")
  266. axes.legend(loc="upper left")
  267. axes.set_xlabel("Количество подсетей")
  268. axes.set_ylabel("Время работы contains")
  269. fig.set_size_inches(10, 7)
  270. plt.show()
  271.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement