Guest User

Untitled

a guest
Dec 6th, 2017
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.65 KB | None | 0 0
  1. import time
  2. import numpy as np
  3. import sys
  4.  
  5. def main():
  6.     t0 = time.time()
  7.     vlans, requests = load_files()
  8.     total = len(requests)
  9.     no_redundancy = len(requests[requests[:,1] == 0])
  10.     with_redundancy = total - no_redundancy
  11.     output_rows = no_redundancy + with_redundancy * 2
  12.  
  13.     # allocate enough memory big enough for the output data, once.
  14.     out = [np.zeros(output_rows, dtype=int) for i in range(4)]
  15.  
  16.     # sort the vlan info first by vlan id and then by device id, since the target
  17.     # is to always use the lowest available of both, in that order.
  18.     # mergesort used because it is the only stable one, according to the doc,
  19.     # which is important when sorting by multiple fields
  20.     # 'view' is used to 1. not copy the data, but instead simply have a different representation
  21.     #                   2. add 'fN' fields to easily sort by in a specified order
  22.     by_vlan_id = np.sort(vlans.view('int, int, int'), kind='mergesort', order=['f2', 'f0'], axis=0)
  23.  
  24.     # The idea is to only traverse the vlan array once, thus we keep track of the index
  25.     # to start looking for a free vlan/device for a request at.
  26.     no_red_start = 0
  27.     with_red_start = 0
  28.     # output line index
  29.     idx = 0
  30.     t1 = time.time()
  31.     for req in requests:
  32.         if req[1]:
  33.             # find the next closest available primary port
  34.             dev_id, vlan_id, with_red_start = next_with_redundancy(by_vlan_id, with_red_start)
  35.             out[0][idx:idx+2] = req[0]
  36.             out[1][idx:idx+2] = dev_id
  37.             out[3][idx:idx+2] = vlan_id
  38.             out[2][idx] = 0
  39.             out[2][idx+1] = 1
  40.             idx += 2
  41.         else:
  42.             # find the next closest available primary/secondary port pair.
  43.             dev_id, vlan_id, no_red_start = next_no_redundancy(by_vlan_id, no_red_start)
  44.             out[0][idx] = req[0]
  45.             out[1][idx] = dev_id
  46.             out[2][idx] = 1
  47.             out[3][idx] = vlan_id
  48.             idx += 1
  49.     t2 = time.time()
  50.    
  51.     # convert output list to numpy array (four rows, may columns) and transpose (four columns, may rows)
  52.     # to write in the correct format
  53.     np.savetxt('output_np2.csv', np.array(out).transpose(), fmt="%d", delimiter=",", newline="\n", header='request_id,device_id,primary_port,vlan_id', comments="")
  54.     t3 = time.time()   
  55.     print("%.2fsec: reading: %dms, processing: %dms, writing: %dms" % (
  56.         t3 - t0, (t1 - t0) * 1000, (t2 - t1) * 1000, (t3 - t2) * 1000))
  57.  
  58. def next_no_redundancy(vlan_info, start):
  59.     # Requests with no redundancy are straightforward:
  60.     # Starting from where we left off previously, find the first
  61.     # available vlan_id attached to a primary port.
  62.     # Due to earlier sort, it will be the lowest vlan_id
  63.     # and device_id, no extra work needed.
  64.     for idx, info in enumerate(vlan_info[start:]):
  65.         # Because of the 'view' of an original array made earlier for sorting by field,
  66.         # each row has been wrapped into an ndarray, so we unwrap it here to get to the
  67.         # data values
  68.         info = info[0]
  69.         # vlan_id cannot be zero. If it is, the data row has been cleared, implying
  70.         # the "reserved" status, skip.
  71.         if not info[2]:
  72.             continue
  73.         if info[1]:
  74.             # store the ids
  75.             dev_id = info[0]
  76.             vlan_id = info[2]
  77.             # mark the device port as used. simply null the whole data row, hence the bytes literal
  78.             # this is needed because no_red_start and with_red_start are independent and would
  79.             # otherwise reserve the same port.
  80.             vlan_info[start + idx] = b'\x00'
  81.             # return the ids and the index to start searching from for the next request
  82.             return dev_id, vlan_id, start + idx + 1
  83.     raise ValueError("No free devices for a no-redundancy request! Need more moneyz!")
  84.  
  85. def next_with_redundancy(vlan_info, start):
  86.     # init to None. Could be init'ed to vlan_info[start] data,
  87.     # but then the 'is reserved' checks would need to be duplicated here.
  88.     # That's ugly, so no.
  89.     dev_id, vlan_id, primary, secondary = [None, None, None, None
  90.     for idx, info in enumerate(vlan_info[start:]):
  91.         info = info[0]
  92.         if not info[2]:
  93.             continue
  94.         # make sure that both primary and secondary have the same vlan_id on the same device.
  95.         # 'dev_id is None' is actually redundant (info[0] is never None, so the second condition
  96.         # would also be True), but for this particular data set this yields a performance
  97.         # increase: most of the time a device is found within a few elements, but
  98.         # 'is None' is much quicker than access to info[0] for the comparison, so removing
  99.         # one info[0] access from the 3-5 checks that are made saves a lot more than
  100.         # extra 'is None' check the other 2-4 times (dev_id can be (and always is) None
  101.         # only during the first iteration.
  102.         if dev_id is None or info[0] != dev_id or info[2] != vlan_id:
  103.             dev_id = info[0]
  104.             vlan_id = info[2]
  105.             # if dev_id and/or vlan_id have changed, reset the previously prepared ports,
  106.             # because we need a pair with the same dev/vlan id
  107.             primary, secondary = None, None
  108.         if info[1]:
  109.             # this serve double purpose:
  110.             # 1. stores the row index to be nullified later to be marked as "reserved"
  111.             # 2. flags that the current vlan/dev id pair's primary port is up for
  112.             #    reservation
  113.             primary = start + idx
  114.         else:
  115.             # same as above, for the secondary port
  116.             secondary = start + idx
  117.         # if we have found a vlan/dev pair with both port available, reserve them and return
  118.         if primary is not None and secondary is not None:
  119.             # nullify the "reserved" vlan ids on a device
  120.             vlan_info[primary] = b'\x00'
  121.             vlan_info[secondary] = b'\x00'
  122.             # same as in no-redundancy
  123.             return dev_id, vlan_id, start + idx + 1
  124.     raise ValueError("No free devices for a request with redundancy! Need funding!")
  125.  
  126. def load_files():
  127.     vlans = np.loadtxt(open('vlans.csv', 'rb'), delimiter=",", skiprows=1, dtype=int)
  128.     requests = np.loadtxt(open('requests.csv', 'rb'), delimiter=",", skiprows=1, dtype=int)
  129.     return vlans, requests
  130.  
  131. if __name__ == "__main__":
  132.     main()
Add Comment
Please, Sign In to add comment