コード例 #1
0
class User_model:
    def __init__(self, is_gen_task, n_alter_dev_per_func):
        self.is_gen_task = is_gen_task
        self.n_alter_dev_per_func = n_alter_dev_per_func
        self.task_dict = {}
        # BN
        self.BN_node_orders = []
        self.devices = None
        self.nodes = None
        self.func_alter_devices = None

    def build_model(self, req_task_len):
        # 1,2 are based on montcarlo experimnet for tasklen(2 to 10)
        # which return a DAG with less than 100 triels.
        #1-req_task_len is 20% of total fucntions.
        n_nodes = 5 * req_task_len
        #2- edges three times the task len
        n_edges = req_task_len * 3
        min_dev_caps = 2

        # number of funcitons for each device
        self.devices, self.nodes, self.func_alter_devices = get_dev_funcs(n_nodes, \
                min_dev_caps, self.n_alter_dev_per_func )
        # pprint(self.func_alter_devices,width=1 )

        rand_dag = RandomDAG(self.nodes, n_edges)

        DAG, child_parent = rand_dag.get_custom_DAG(req_task_len)
        # print("Child_parents returns by custom DAG: ")
        # pprint(child_parent, width=1)

        for f in rand_dag.dag_longest_path(DAG):
            self.task_dict[f] = ''

        # check if we get the task length the at we want
        for f in self.task_dict.keys():
            func_devices = self.func_alter_devices[f]
            self.task_dict[f] = random.choice(func_devices)
        self.task_fucs = self.task_dict.keys()
        # print(self.task_dict)

        self.network = self.get_BN(DAG, child_parent)
        self.network.bake()

    def get_score(self, cand_list):
        can_dev = self.build_BN_query(cand_list)
        # try:
        return self.network.probability(can_dev),

    def build_BN_query(self, cand_list):
        # first cand_list for first func in task
        can_dev = [None for f in self.nodes]

        # the order of nodes and cand_list should be same
        for f, d in zip(self.task_fucs, cand_list):
            f_idx = self.BN_node_orders.index(f)
            can_dev[f_idx] = d

        return can_dev

    def get_nodes_prob_dist(self, node_without_parents, child_parent):
        node_prob_dict = {}

        for node in node_without_parents:
            n_alters = len(self.func_alter_devices[node])
            dist = {}

            # node not in the user preference nodes
            # give random probability for all
            if node not in self.task_dict.keys():
                p = np.random.random(n_alters)
                p /= p.sum()
                # now the sum of p is 1
                # randomly map p to alter devices
                dist = dict(zip(self.func_alter_devices[node], p))

            else:  # set max prob to the perfered alter
                pref_alter = self.task_dict[node]
                x = 1.7 / n_alters
                y = 1.0 / len(self.task_dict)
                maxp_for_best_alter = pow(x, y)
                dist[pref_alter] = maxp_for_best_alter

                alt_list = list(self.func_alter_devices[node])
                alt_list.remove(pref_alter)

                # generate random prob for the rest of alter
                if n_alters == 2:
                    dist.update(dict(zip(alt_list, [1 - maxp_for_best_alter])))
                    # print([1.0-maxp_for_best_alter])
                else:
                    rand_rest = np.random.random(n_alters - 1)
                    # to make the maxp+sum(rand_rest) = 1
                    rand_prob = [
                        e / sum(rand_rest) * maxp_for_best_alter
                        for e in rand_rest
                    ]
                    #np.delete(p, np.amax(p))
                    dist.update(dict(zip(alt_list, rand_prob)))
            # save node with its prob
            node_prob_dict[node] = dist

        # these nodes have parents, generate CPT for them
        for node, parent_lst in child_parent.items():
            # parents + this node condProbTable
            condProbTable = self.getCondProbTable(node, parent_lst)
            # save node with its prob
            node_prob_dict[node] = condProbTable
        # print("child node: ", node, " table:", condProbTable)

        return node_prob_dict

    def get_BN(self, DAG, child_parent):

        #1. get DAG structure as an arguments
        ################################################
        node_without_parents = [
            e for e in self.nodes if e not in child_parent.keys()
        ]

        # 2 Build BN probability model
        # 2.1 get probabilityDist or conditional prob table
        # bais the prob to task_dict choices
        node_prob_dict = self.get_nodes_prob_dist(node_without_parents,
                                                  child_parent)
        self.npd = node_prob_dict
        # 2.2 Create nodes linked to its parent, parent should be processed first.
        # all node state saved to be added to the BN later
        nodes_state = {}
        # all node dist or CPT saved to link child to parents when building child CPT
        nodes_dist = {}

        # start with root nodes (don't have parents then link child to them)
        # list the list to copy it, otherwise it will point to the self.nodes
        remaining_nodes_list = list(self.nodes)

        for node in node_without_parents:
            prob_dist = node_prob_dict[node]
            # print("Parent", node, prob_dist)
            node_dist = DiscreteDistribution(prob_dist)
            nodes_dist[node] = node_dist
            nodes_state[node] = State(node_dist, name=node)
            # remove from nodes_list
            remaining_nodes_list.remove(node)

        # rest of the node should have parents
        while len(remaining_nodes_list) > 0:
            for node, parent_lst in child_parent.items():
                # if node's parents already created then it can be created now
                if set(parent_lst).issubset(nodes_state.keys()) and \
                    node in remaining_nodes_list:
                    # print("parent child", parent_lst, node, node_prob_dict[node])
                    node_dist = ConditionalProbabilityTable(node_prob_dict[node], \
                                    [nodes_dist[i] for i in parent_lst])

                    nodes_dist[node] = node_dist
                    nodes_state[node] = State(node_dist, name=node)
                    # remove from the node_list
                    remaining_nodes_list.remove(node)

        # 3 Create BN and add the nodes_state
        self.network = BayesianNetwork("User_pref")
        for node, state in nodes_state.items():
            self.network.add_node(state)
            #print("node ", node, " is added!")
            self.BN_node_orders.append(node)

        # 4 Link nodes with edges using nodes_state and DAG.edge
        for a, bs in DAG.edge.items():
            for b in bs.keys():
                self.network.add_edge(nodes_state[a], nodes_state[b])
                # print("Netwoerk:", a, b)
        #       print("Network has ", self.network.node_count() , " nodes and ", self.network.edge_count(), " edges")
        return self.network

    def get_permutation_groups(self, parent_node_lst):
        # print("Parents,node", parent_node_lst)
        alter_dev = []
        for n in parent_node_lst:
            alter_dev.append(self.func_alter_devices[n])
            # list(range(n_att))
        # print("dev for all ", alter_dev)
        alter_perm = itertools.product(*alter_dev)
        # print("alter_perm:", alter_perm)
        permutation = list(dict(zip(parent_node_lst, x)) for x in alter_perm)
        # print("permutation")
        # print(permutation)

        # Gruop the permutation of node alter node
        n_func_dev = len(self.func_alter_devices[parent_node_lst[-1]])
        n_prob_groups = int(len(permutation) / n_func_dev)
        perm_groups = [[] for i in range(n_prob_groups)]
        c = 0
        for perm in permutation:
            # add to the begining
            perm_groups[c // n_func_dev].append(perm)
            c += 1

        return perm_groups

    def getCondProbTable(self, node, parent_lst):
        parent_node_lst = []
        parent_node_lst.extend(parent_lst)
        parent_node_lst.append(node)

        perm_groups_prob = self.get_permutation_groups(parent_node_lst)

        condProbTable = []

        n_func_dev = len(self.func_alter_devices[node])
        #p^(1/N)
        maxp_for_best_alter = pow(1.7 / n_func_dev, 1 / len(self.task_dict))
        if maxp_for_best_alter < 0.2:
            maxp_for_best_alter = 0.2

        if self.is_gen_task:
            # check if this child_parent or indp node are in the user prefered devices
            intersect_dict = {k: v for k, v in self.task_dict.items() \
                if k in parent_node_lst}
            #print("intersect_dict:", intersect_dict)

        # for each permutation generate prob such that the sum of each node CDP is = 1
        for perm_group_prob in perm_groups_prob:
            if self.is_gen_task and len(intersect_dict) > 1 and \
                    [True for j in range(n_func_dev) \
                        if intersect_dict.items() <= perm_group_prob[j].items()]:

                # print(intersect_dict)
                # generate p such that one value is
                rem_alt = n_func_dev - 1
                rest_prob = np.random.random(rem_alt)
                rest_prob /= sum(rest_prob)
                rest_prob *= (1 - maxp_for_best_alter)

                # the sum of maxp_for_best_alter and rest_prob = 1
                for j in range(n_func_dev):
                    # alter_idx = i * n_att + j
                    condProbRow = list(perm_group_prob[j].values())
                    if intersect_dict.items() <= perm_group_prob[j].items():
                        # print("Best candidate ", perm_group_prob[j], " prob:", maxp_for_best_alter)
                        condProbRow.append(maxp_for_best_alter)
                    else:
                        rem_alt -= 1
                        #print("NOT  candidate ", perm_group_prob[j], " prob:", rest_prob[rem_alt])
                        condProbRow.append(rest_prob[rem_alt])

                    condProbTable.append(condProbRow)

            else:
                # to gurantee best alter, no others should have prob> maxp
                a = np.random.random(n_func_dev)
                a /= a.sum()
                while self.is_gen_task and np.amax(a) >= maxp_for_best_alter:
                    a = np.random.random(n_func_dev)
                    a /= a.sum()

                # to make sum of alter prob = 1
                for j in range(n_func_dev):
                    condProbRow = list(perm_group_prob[j].values())
                    condProbRow.append(a[j])
                    #print(condProbRow)
                    condProbTable.append(condProbRow)
        return condProbTable
コード例 #2
0
ファイル: BN.py プロジェクト: alshaboti/HeuristicOptimization
    def get_BN(self, n_nodes, n_alters, n_edges):

        # 1 Build BN DAG structure
        DAG, child_parent = RandomDAG().random_dag(n_nodes, n_edges)

        for a, bs in DAG.edge.items():
            for b in bs.keys():
                print(a, "->", b)
        print("Key node, value: parents",child_parent)

        # 2 Build BN probability model
        # 2.1 get probabilityDist or conditional prob table
        node_prob_dict = {}
        # these nodes have parents, generate CPT for them
        for node, parent_lst in child_parent.items():
            # parents + this node condProbTable
            condProbTable = self.getCondProbTable(len(parent_lst)+1, n_alters)
            # save node with its prob
            node_prob_dict[str(node)] = condProbTable
            #print("Conditional Probability Table: \n", condProbTable)

        nodes_list = list(range(n_nodes))
        node_with_parent_lst = child_parent.keys()
        node_without_parents = [e for e in nodes_list if e not in node_with_parent_lst]

        # these nodes have no parents so create random prob for them only no conditional here
        for node in node_without_parents:
            p = np.random.random(n_alters)
            p /= p.sum()
            dist = {}
            for j in range(n_alters):
                dist[j] = p[j]
            # save node with its prob
                node_prob_dict[str(node)] = dist
            #print("Root node: ", node, " dist: ", dist)

        # 2.2 Create nodes linked to its parent, parent should be processed first.
        # all node state saved to be added to the BN later
        nodes_state = {}
        # all node dist or CPT saved to link child to parents when building child CPT
        nodes_dist = {}

        # start with root nodes (don't have parents then link child to them)
        for node in node_without_parents:
            prob_dist = node_prob_dict[str(node)]
            node_dist = DiscreteDistribution(prob_dist)
            nodes_dist[node] = node_dist
            nodes_state[node] = State(node_dist, name = str(node))
            # remove from nodes_list
            nodes_list.remove(node)


        # rest of the node should have parents
        count = 100
        while len(nodes_list) > 0 and count > 0:
            count -= 1
            for node, parent_lst in child_parent.items():
                # if node's parents already created then it can be created now
                if set(parent_lst).issubset(nodes_state.keys()) and node in nodes_list:

                    node_dist = ConditionalProbabilityTable(node_prob_dict[str(node)] \
                                                      , [nodes_dist[i] for i in parent_lst ])
                    nodes_dist[node] = node_dist
                    nodes_state[node] = State(node_dist, name = str(node))
                    # remove from the node_list
                    nodes_list.remove(node)
        if not nodes_list:
            print("States created for all nodes!")

        # 3 Create BN and add the nodes_state
        network = BayesianNetwork("User_pref")
        for node, state in nodes_state.items():
            network.add_node(state)
        print("Network has ", network.node_count() , " nodes")

        # 4 Link nodes with edges using nodes_state and DAG.edge
        for a, bs in DAG.edge.items():
            for b in bs.keys():
                network.add_edge(nodes_state[a], nodes_state[b])
        print("Network has ", network.edge_count(), " edges")
        return network