def obtain_sub_problem_es(self, edge_selections):
        """
        Calculate the optimization goal of sub-problem $\mathcal{P}_2^{es}$.

        :param edge_selections: the edge selection decisions for all mobile devices
        :return: the optimization goal of $\mathcal{P}_2^{es}$
        """
        parameter = self.get_parameter()
        optimization_func_value = 0
        for i in range(parameter.get_user_num()):
            division = int(sum(edge_selections[i]))
            if division:
                energy_consumes = parameter.get_local_exe_energy() + \
                                  ToolFunction.obtain_transmit_energy(division, edge_selections[i], parameter,
                                                                      parameter.get_connectable_gains()[i])
                negative_part = self.__virtual_energy_levels[
                    i] * energy_consumes
            else:
                if self.__battery_energy_levels[
                        i] < parameter.get_local_exe_energy():
                    negative_part = 0
                else:
                    negative_part = self.__virtual_energy_levels[
                        i] * parameter.get_local_exe_energy()
            optimization_func_value -= negative_part
        optimization_func_value += parameter.get_v(
        ) * self.obtain_overall_costs(edge_selections)
        return optimization_func_value
    def generate_random_ins(self):
        """
        Generate random instance for those dimensions whose labels are True. In this version, we check whether the two
        constraints can be satisfied. (Actually, we first generate random edge_selections, and then convert it to an
        instance.)

        :return: a feasible instance
        """
        parameter = self.get_parameter()
        assignable_nums = np.repeat(parameter.get_max_assign(),
                                    parameter.get_server_num())
        edge_selections = self.greedy_sample(assignable_nums)
        ins_features = []
        for i in range(parameter.get_user_num()):
            if parameter.get_task_requests()[i] == 1:
                division = int(sum(edge_selections[i]))
                if division:
                    times = self.obtain_time_consumption(
                        division, edge_selections[i],
                        parameter.get_connectable_gains()[i])
                    energys = ToolFunction.obtain_transmit_energy(
                        division, edge_selections[i], parameter,
                        parameter.get_connectable_gains()[i])
                    # satisfy the constraint
                    if times >= parameter.get_ddl(
                    ) or energys > self.__battery_energy_levels[i]:
                        edge_selections[i] = np.zeros(len(edge_selections[i]))
                else:
                    pass
                for j in range(len(edge_selections[i])):
                    ins_features.append(edge_selections[i][j])
        dimension = Dimension(parameter.get_dim_size())
        instance = Instance(dimension)
        instance.set_features(ins_features)
        return instance
    def update_energy_levels(self):
        """
        ============================= [copy from offloading_common.py] =============================
        Update the cost & virtual energy levels according to the involution expression \eqref{10}.

        :return: no return
        """
        parameter = self.get_parameter()
        for i in range(parameter.get_user_num()):
            division = int(sum(self.__edge_selections[i]))
            if division:
                self.__battery_energy_levels[i] = self.__battery_energy_levels[i] + \
                    self.__harvested_energys[i] - ToolFunction.obtain_transmit_energy(
                    division, self.__edge_selections[i], parameter, parameter.get_connectable_gains()[i]) - \
                    parameter.get_local_exe_energy()
            else:
                # check whether need to minus local_exe_energys
                # if self.__battery_energy_levels[i] < parameter.get_local_exe_energy():
                #     self.__battery_energy_levels[i] = self.__battery_energy_levels[i] + self.__harvested_energys[i]
                # else:
                #     self.__battery_energy_levels[i] = self.__battery_energy_levels[i] + \
                #         self.__harvested_energys[i] - parameter.get_local_exe_energy()
                self.__battery_energy_levels[i] = self.__battery_energy_levels[
                    i] + self.__harvested_energys[i]
            self.__virtual_energy_levels[i] = self.__battery_energy_levels[
                i] - parameter.get_perturbation_para()
Exemple #4
0
    def obtain_edge_selections(self):
        """
        Obtain the feasible solution with greedy policy on computation.

        :return: edge_selections, every row denotes a mobile device who has task request
        """
        parameter = self.get_parameter()
        # first initialize with zero
        edge_selections = []
        for i in range(parameter.get_user_num()):
            edge_selection = np.repeat(
                0, len(parameter.get_connectable_servers()[i]))
            edge_selections.append(edge_selection)

        # for every edge site, generate a random integer with [0, max_assign], and distribute connections to
        # connectable mobile devices
        for j in range(parameter.get_server_num()):
            assign_num = parameter.get_max_assign()
            connectable_user_num = len(parameter.get_connectable_users()[j])
            if assign_num >= connectable_user_num:
                # every mobile device in it can be chosen
                for i in range(connectable_user_num):
                    user_index = parameter.get_connectable_users()[j][i]
                    edge_index = list.index(
                        parameter.get_connectable_servers()[user_index], j)
                    edge_selections[user_index][edge_index] = 1
            else:
                # randomly choose assign_num users to distribute j's computation capacity
                user_indices = random.sample(
                    parameter.get_connectable_users()[j], assign_num)
                for i in range(len(user_indices)):
                    user_index = user_indices[i]
                    edge_index = list.index(
                        parameter.get_connectable_servers()[user_index], j)
                    edge_selections[user_index][edge_index] = 1

        # set those mobile devices who do not have task request to [0, 0, ..., 0]
        # we can not delete them from the list because every row is the index of the corresponding mobile device
        for i in range(parameter.get_user_num()):
            if parameter.get_task_requests()[i] == 0:
                edge_selections[i] = np.zeros(len(edge_selections[i]))
            else:
                division = int(sum(edge_selections[i]))
                if division:
                    times = self.obtain_time_consumption(
                        division, edge_selections[i],
                        parameter.get_connectable_gains()[i])
                    energys = ToolFunction.obtain_transmit_energy(
                        division, edge_selections[i], parameter,
                        parameter.get_connectable_gains()[i])
                    # satisfy the constraint
                    if times >= parameter.get_ddl(
                    ) or energys > self.get_battery_energy_levels()[i]:
                        edge_selections[i] = np.zeros(len(edge_selections[i]))
        return edge_selections
    def generate_from_pos_ins(self, pos_instance):
        """
        Generate an instance from an exist positive instance.

        :param pos_instance: the exist positive instance
        :return: a feasible instance
        """
        parameter = self.get_parameter()
        assignable_nums = np.repeat(parameter.get_max_assign(),
                                    parameter.get_server_num())
        edge_selections = self.greedy_sample(assignable_nums)
        ins_features = []
        for i in range(parameter.get_user_num()):
            if parameter.get_task_requests()[i] == 1:
                division = int(sum(edge_selections[i]))
                if division:
                    times = self.obtain_time_consumption(
                        division, edge_selections[i],
                        parameter.get_connectable_gains()[i])
                    energys = ToolFunction.obtain_transmit_energy(
                        division, edge_selections[i], parameter,
                        parameter.get_connectable_gains()[i])
                    # satisfy the constraint
                    if times >= parameter.get_ddl(
                    ) or energys > self.__battery_energy_levels[i]:
                        edge_selections[i] = np.zeros(len(edge_selections[i]))
                else:
                    pass
                for j in range(len(edge_selections[i])):
                    ins_features.append(edge_selections[i][j])
        dimension = Dimension(parameter.get_dim_size())
        instance = Instance(dimension)
        instance.set_features(ins_features)

        # update from the chosen positive instance
        for i in range(len(instance.get_features())):
            if self.get_labels()[i]:
                instance.set_feature(i, pos_instance.get_feature(i))

        # re-check whether the maximum assignable nums is satisfied
        edge_selections = self.instance_to_edge_selections(instance)
        for j in range(parameter.get_server_num()):
            if assignable_nums[j] >= len(parameter.get_connectable_users()[j]):
                continue
            connect_users = []
            for i in range(len(parameter.get_connectable_users()[j])):
                user_idx = parameter.get_connectable_users()[j][i]
                edge_idx = list.index(
                    parameter.get_connectable_servers()[user_idx], j)
                if edge_selections[user_idx][edge_idx] == 1:
                    connect_users.append(user_idx)
            if len(connect_users) <= assignable_nums[j]:
                continue
            permitted_connect_users = random.sample(connect_users,
                                                    assignable_nums[j])
            non_permitted = [
                u for u in connect_users if u not in permitted_connect_users
            ]
            for i in range(len(non_permitted)):
                user_idx = non_permitted[i]
                edge_idx = list.index(
                    parameter.get_connectable_servers()[user_idx], j)
                edge_selections[user_idx][edge_idx] = 0

        # re-check whether the ddl and energy consumption are satisfied
        for i in range(parameter.get_user_num()):
            if parameter.get_task_requests()[i] == 1:
                division = int(sum(edge_selections[i]))
                if division:
                    # times = self.obtain_time_consumption(division, edge_selections[i],
                    #                                      parameter.get_connectable_gains()[i])
                    transmit_times = ToolFunction.obtain_transmit_times(
                        division, edge_selections[i], parameter,
                        parameter.get_connectable_gains()[i])
                    edge_exe_times = ToolFunction.obtain_edge_exe_times(
                        division, parameter)
                    edge_times = transmit_times + edge_exe_times
                    times = max(edge_times) + parameter.get_local_exe_time() + \
                        parameter.get_coordinate_cost() * division
                    energys = ToolFunction.obtain_transmit_energy(
                        division, edge_selections[i], parameter,
                        parameter.get_connectable_gains()[i])
                    # satisfy the constraint
                    if times >= parameter.get_ddl(
                    ) or energys > self.__battery_energy_levels[i]:
                        edge_selections[i] = np.zeros(len(edge_selections[i]))
                else:
                    pass

        # get final instance from the new edge_selections
        ins_features = []
        for i in range(parameter.get_user_num()):
            if parameter.get_task_requests()[i] == 1:
                for j in range(len(edge_selections[i])):
                    ins_features.append(edge_selections[i][j])
        instance.set_features(ins_features)
        return instance
    def obtain_edge_selections(self):
        """
        Obtain the feasible solution with greedy policy on communication.

        :return: edge_selections, every row denotes a mobile device who has task request
        """
        parameter = self.get_parameter()
        # deep copy the connectable servers and gains
        shadow_servers, shadow_gains, edge_selections = [], [], []
        for i in range(parameter.get_user_num()):
            tmp_s, tmp_g = [], []
            for j in range(len(parameter.get_connectable_servers()[i])):
                tmp_s.append(parameter.get_connectable_servers()[i][j])
                tmp_g.append(parameter.get_connectable_gains()[i][j])
            shadow_servers.append(tmp_s)
            shadow_gains.append(tmp_g)
            edge_selections.append(np.zeros(len(parameter.get_connectable_servers()[i])))

        best_gains, best_servers = [], []
        for i in range(parameter.get_user_num()):
            best_gain = max(shadow_gains[i])
            best_gains.append(best_gain)

            best_server_idx = shadow_gains[i].index(best_gain)
            best_servers.append(shadow_servers[i][best_server_idx])

        checked = [False] * parameter.get_user_num()
        while False in checked:
            # satisfy the maximum assignment constraint
            for j in range(parameter.get_server_num()):
                connected_users = [idx for idx, server in enumerate(best_servers) if server == j]
                if len(connected_users):
                    # at least one mobile device choose this server
                    connected_gains = [best_gains[i] for i in connected_users]

                    # only the user with the best channel power gains can be chosen
                    lucky_user = connected_users[connected_gains.index(max(connected_gains))]
                    checked[lucky_user] = True

                    # update best connectable information (remove j)
                    for i in range(parameter.get_user_num()):
                        if not checked[i]:
                            if shadow_servers[i].count(j) != 0:
                                server_idx = shadow_servers[i].index(j)
                                shadow_servers[i].pop(server_idx)
                                shadow_gains[i].pop(server_idx)
                else:
                    # this server is not chosen by any mobile device
                    continue
                # re-calculate the best server and gains for each mobile device
                for i in range(parameter.get_user_num()):
                    if len(shadow_gains[i]) != 0:
                        best_gains[i] = max(shadow_gains[i])
                        best_server_index = shadow_gains[i].index(best_gains[i])
                        best_servers[i] = shadow_servers[i][best_server_index]
                    else:
                        checked[i] = True

        # obtain edge_selections from best_servers
        for i in range(parameter.get_user_num()):
            if parameter.get_task_requests()[i] == 1:
                if best_servers[i]:
                    edge_idx = parameter.get_connectable_servers()[i].index(best_servers[i])
                    edge_selections[i][edge_idx] = 1

                # check whether the constraints can be satisfied
                division = int(sum(edge_selections[i]))
                if division:
                    times = self.obtain_time_consumption(division, edge_selections[i],
                                                         parameter.get_connectable_gains()[i])
                    energys = ToolFunction.obtain_transmit_energy(division, edge_selections[i], parameter,
                                                                  parameter.get_connectable_gains()[i])
                    # satisfy the constraint
                    if times >= parameter.get_ddl() or energys > self.get_battery_energy_levels()[i]:
                        edge_selections[i] = np.zeros(len(edge_selections[i]))
        return edge_selections