找到路由器放置的最佳位置

时间:2018-05-21 16:21:22

标签: python algorithm optimization text-files

我正在寻找一种优化算法,该算法采用0s,1s和-1s编码的文本文件:

  • 1表示需要Wi-Fi覆盖的目标小区
  • 0表示作为墙壁的单元格
  • 1表示无效的单元格(不需要Wi-Fi覆盖)

文本文件示例:
Example of text file

我已经创建了一个解决方案函数以及其他辅助函数,但我似乎无法获得要放置的路由器的最佳位置以确保正确覆盖。还有另一个文件用于打印,我正在努力寻找最佳位置。我基本上需要更改get_random_position函数以获得最佳函数,但我不确定如何做到这一点。各种路由器覆盖的区域是:

这是我得到的那种输出:
This is the kind of output I am getting

每个路由器最多覆盖一个方形区域(2S + 1)^ 2

  • 类型1:S = 5;成本= 180
  • 类型2:S = 9;成本= 360
  • 类型3:S = 15;成本= 480

我的代码如下:

import numpy as np
import time

from random import randint

def is_taken(taken, i, j):
    for coords in taken:
        if coords[0] == i and coords[1] == j:
            return True
return False

def get_random_position(floor, taken , nrows, ncols):
  i = randint(0, nrows-1)
  j = randint(0, ncols-1)

  while floor[i][j] == 0 or floor[i][j] == -1 or is_taken(taken, i, j):
      i = randint(0, nrows-1)
      j = randint(0, ncols-1)

  return (i, j)

def solution(floor):
  start_time = time.time()
  router_types = [1,2,3]

  nrows, ncols = floor.shape
  ratio = 0.1
  router_scale = int(nrows*ncols*0.0001)
  if router_scale == 0:
     router_scale = 1
row_ratio = int(nrows*ratio)
col_ratio = int(ncols*ratio)

print('Row  : ',nrows, ', Col: ', ncols, ', Router scale :', router_scale)

global_best = [0, ([],[],[])]
taken = []
while True:
    found_better = False
    best = [global_best[0], (list(global_best[1][0]), list(global_best[1][1]), list(global_best[1][2]))]  
    for times in range(0, row_ratio+col_ratio):
        if time.time() - start_time > 27.0:
            print('Time ran out! Using what I got : ', time.time() - start_time)
            return global_best[1]

        fit = []
        for rtype in router_types:
            interim = (list(global_best[1][0]), list(global_best[1][1]), list(global_best[1][2]))

            for i in range(0, router_scale):
                pos = get_random_position(floor, taken, nrows, ncols)
                interim[0].append(pos[0])
                interim[1].append(pos[1])

                interim[2].append(rtype)

            fit.append((fitness(floor, interim), interim))

        highest_fitness = fit[0]
        for index in range(1, len(fit)):
            if fit[index][0] > highest_fitness[0]:
                highest_fitness = fit[index]

        if highest_fitness[0] > best[0]:
            best[0] = highest_fitness[0]
            best[1] = (highest_fitness[1][0],highest_fitness[1][1], highest_fitness[1][2])
            found_better = True
            global_best = best
            taken.append((best[1][0][-1],best[1][1][-1]))
            break


    if found_better == False:
        break

print('Best:')        
print(global_best)                

end_time = time.time()
run_time = end_time - start_time
print("Run Time:", run_time)


return global_best[1]

def available_cells(floor):
    available = 0
    for i in range(0, len(floor)):
        for j in range(0, len(floor[i])):
            if floor[i][j] != 0:
                available += 1
   return available            



def fitness(building, args):
    render = np.array(building, dtype=int, copy=True)
    cov_factor = 220
    cost_factor = 22
    router_types = {  # type: [coverage, cost]
        1: {'size' : 5, 'cost' : 180},
        2: {'size' : 9, 'cost' : 360},
        3: {'size' : 15, 'cost' : 480},
    }
    routers_used = args[-1]

for r, c, t in zip(*args):
    size = router_types[t]['size']
    nrows, ncols = render.shape
    rows = range(max(0, r-size), min(nrows, r+size+1))
    cols = range(max(0, c-size), min(ncols, c+size+1))

    walls = []
    for ri in rows:
        for ci in cols:
            if building[ri, ci] == 0:
                walls.append((ri, ci))

    def blocked(ri, ci):
        for w in walls:
            if min(r, ri) <= w[0] and max(r, ri) >= w[0]:
                if min(c, ci) <= w[1] and max(c, ci) >= w[1]:
                    return True
        return False

    for ri in rows:
        for ci in cols:
            if blocked(ri, ci):
                continue
            if render[ri, ci] == 2:
                render[ri, ci] = 4
            if render[ri, ci] == 1:
                render[ri, ci] = 2

    render[r, c] = 5

return (
        cov_factor * np.sum(render > 1) - 
        cost_factor * np.sum([router_types[x]['cost'] for x in routers_used])
    )

1 个答案:

答案 0 :(得分:1)

以下是关于如何解决问题的建议;但是我并不确认这是最好的方法,而且肯定不是唯一的方法。

主要想法

您的问题可以建模为weighted minimum set cover problem

好消息,这是众所周知的优化问题:

  • 很容易找到近似解的算法描述
  • 在网上快速搜索显示了Python中的许多近似算法实现。

坏消息,这是NP-hard optimization problem

  • 如果您需要一个精确的解决方案:算法只适用于&#34; small&#34;在合理的时间内纠正问题(在您的情况下:问题的大小&lt; =&gt;&#34; 1&#34;单元格的数量)。
  • 近似(a.k.a贪婪)算法在计算要求之间进行权衡,在某些情况下风险确实远远不是最优解。

请注意,以下部分证明您的问题是NP难的。一般的最小集合覆盖问题是NP难的。在您的情况下,子集具有几个可能有助于设计更好算法的属性。我不知道怎么回事。

转换为封面设置问题

让我们定义一些集合:

  • U:&#34; 1&#34;细胞(需要Wifi)。
  • P(U):U的power set(U的子集)。
  • P:您可以放置​​路由器的单元格集(不确定原始帖子中P = U)。
  • T:路由器类型集(在您的情况下为3个值)。
  • R +:正实数(用于描述价格)。

让我们定义一个函数(伪Python):

# Domain of definition : T,P --> R+,P(U)
# This function takes a router type and a position, and returns
# a tuple containing:
# - the price of a router of the given type.
# - the subset of U containing all the position covered by a router
#   of the given type placed at the given position.
def weighted_subset(routerType, position):
    pass # TODO: implementation

现在,我们定义一个最后一组,作为我们刚才描述的函数的图像:S=weighted_subset(T,P)。该集合的每个元素都是U的子集,由R +中的价格加权。

通过所有这些形式,找到路由器类型&amp;职位:

  1. 覆盖所有理想的位置
  2. 最小化成本
  3. 相当于找到S的子集:

    1. 他们的P(U)的联合等于U
    2. 最小化相关权重的总和
    3. 哪个是加权最小集合覆盖问题。