def greedySolve(NodesA, NodesB, Edges, verbose = False): mtx = np.zeros((NodesA, NodesB)) for j in range(NodesA): mtx[j, 0] = 1.0 for j in range(1, NodesB): mtx[0, j] = 1.0 mtx[1,1] = 1.0 EdgesLeft = (int)(round(Edges - NodesA - (NodesB - 1) -1)) [MT, Fill, deg_min, neg_delta, sums] = tb.init_nodf(mtx) nproc = multiprocessing.cpu_count() for i in tqdm(range(EdgesLeft)): potentialPositions = mtxSearch3(mtx) myarg = [mtx, MT, Fill, deg_min, neg_delta, sums, potentialPositions] res_list = test_multiplePositions(myarg) opt_nodf = -100 opt_pos = [-1, -1] for pos, nodf in res_list: if(nodf > opt_nodf): opt_pos = pos opt_nodf = nodf elif(nodf == opt_nodf): score_old = (opt_pos[0] / NodesA) + (opt_pos[1] / NodesB) score_new = (pos[0] / NodesA) + (pos[1] / NodesB) if(score_new < score_old): opt_pos = pos opt_nodf = nodf #print("--->" + str(opt_pos + 1)) a, sums = tb.nodf_one_link_added(mtx, MT, Fill, deg_min, neg_delta, sums, opt_pos) return mtx
def greedySolveAdaptive(NodesA, NodesB, Edges, R = 2, verbose = False): Steplimit = max(NodesA, NodesB) mtx = np.zeros((NodesA, NodesB)) for j in range(NodesA): mtx[j, 0] = 1.0 for j in range(1, NodesB): mtx[0, j] = 1.0 mtx[1,1] = 1.0 EdgesLeft = (int)(round(Edges - NodesA - NodesB)) [MT, Fill, deg_min, neg_delta, sums] = tb.init_nodf(mtx) old_nodf = -100.0 for i in tqdm(range(EdgesLeft)): potentialPositions = mtxSearch3(mtx) newNODFList = [] opt_nodf = -100 opt_pos = [-1, -1] for pos in potentialPositions: nodf = tb.test_nodf_one_link_added(mtx, MT, Fill, deg_min, neg_delta,sums, pos) # print(pos[0] + 1, pos[1] + 1, nodf) if(nodf> opt_nodf): opt_pos = pos opt_nodf = nodf elif(nodf == opt_nodf): score_old = ((opt_pos[0] / NodesA)**2) + ((opt_pos[1] / NodesB)**2) score_new = ((pos[0] / NodesA)**2) + ((pos[1] / NodesB)**2) if(score_new < score_old): opt_pos = pos opt_nodf = nodf nodf, sums = tb.nodf_one_link_added(mtx, MT, Fill, deg_min, neg_delta, sums,opt_pos) if(verbose): print(nodf) return mtx
def hill_climb_test_positions(mtx, posSwapList): MT, F, DM, ND, S = tb.init_nodf(mtx) opt_mtx = np.copy(mtx) opt_nodf = tb.nodf(mtx) for oPos, zPos in posSwapList: n1, S = tb.nodf_one_link_removed(mtx, MT, F, DM, ND, S, oPos) n1, S = tb.nodf_one_link_added(mtx, MT, F, DM, ND, S, zPos) if (n1 > opt_nodf): # Update the optimal matrix and params opt_mtx = np.copy(mtx) opt_nodf = n1 n1, S = tb.nodf_one_link_removed(mtx, MT, F, DM, ND, S, zPos) a, S = tb.nodf_one_link_added(mtx, MT, F, DM, ND, S, oPos) return opt_mtx, opt_nodf
def sim_anneal_step(mtx, temp, iters): """ One step of the simmulated annealing algorithm. Supply a initial solution and nodf meta-data. Output will be the optimal matrix found in this process along with it's cost """ # Do the reqired dice rolls for this algorithm vectorised and in advance: decision = np.random.rand(iters) MT, F, DM, ND, S = tb.init_nodf(mtx) opt_mtx = np.copy(mtx) opt_cost = cost(tb.nodf(mtx)) old_cost = opt_cost ones = tb.get_valid_ones(mtx) zeros = tb.get_promising_zeros(mtx) opt_time = -1 for i in range(iters): o_idx = np.random.randint(len(ones)) z_idx = np.random.randint(len(zeros)) o_pos = ones[o_idx] z_pos = zeros[z_idx] # compute the new new_nodf, S = neighbor_nodf(mtx, MT, F, DM, ND, S, o_pos, z_pos) new_cost = cost(new_nodf) if(new_cost < opt_cost): opt_cost = new_cost opt_mtx = np.copy(mtx) opt_time = i acc_prob = tb.acceptProb(old_cost, new_cost, temp) if(decision[i] <= acc_prob): # accept the new solution by not changing it back old_cost = new_cost # modify the zero and ones list accordingly: # ones = tb.get_valid_ones(mtx) ones = tb.get_valid_ones(mtx) zeros[z_idx] = o_pos else: # reject the new solution by reverting back a, S = neighbor_nodf(mtx, MT, F, DM, ND, S, z_pos, o_pos) # old_cost will not be updated! return [opt_mtx, opt_cost, S]
def greedy_remove_link(mtx): """ Removes a link to maximize the nodf metric. Return: The new nodf metric and if the matrix has changed return opt_mtx """ print("Greedy remove link") NodesA, NodesB = mtx.shape opt_mtx = np.zeros((NodesA, NodesB)) opt_nodf = -100.0 oList = tb.get_valid_ones(mtx) MT, F, DM, ND, S = tb.init_nodf(mtx) # Highly optimised but awkward for pos in oList: # Compute new NODF new_nodf, S = tb.nodf_one_link_removed(mtx, MT, F, DM, ND, S, pos) if (new_nodf > opt_nodf): opt_mtx = np.copy(mtx) opt_nodf = new_nodf x, S = tb.nodf_one_link_added(mtx, MT, F, DM, ND, S, pos) return opt_mtx
def greedy_gen(params): """ Generate an initial graph with the intention of using it later in a more sophisticated algorithm like simmulated annealing or a genetic algorithm. This function is not deterministic. It rather tests all potential positions for a new entry and then adds one using the nodf values to create a probability distribution. """ NodesA, NodesB, Edges = params #Initial fill mtx = np.zeros((NodesA, NodesB)) mtx[0,:] = 1.0 mtx[:,0] = 1.0 mtx[1,1] = 1.0 edges_left = Edges - NodesA - NodesB MT, F, DM, ND, S = tb.init_nodf(mtx) for i in range(edges_left): #greedy add a link greedyAddLink(mtx, MT, F, DM, ND, S, edges_left - i) return mtx