Example #1
0
    def _find_best_offer(
            self, all_offers: List[Tuple[str, Dict]]) -> Tuple[List, float]:
        """
        Find the offer that maximize the global gain of both partners in
        the given offers and for the given partner.

        Parameters
        ----------
        all_offers: list
            a list of couples (offerer_name, offer) where offer is a dictionary of
            offers {(partner_val, my_val): partner_gain} Mgm2OfferMessage

        Returns
        -------
        list:
            list of best offers (i.ee with the best gain)
        best_gain:
            gain for the best offers.
        """
        bests, best_gain = [], 0

        for partner, offers in all_offers:
            partial_asgt = self._neighbors_values.copy()
            current_partner = self._neighbor_var(partner)

            # Filter out the constraints linking those two variables to avoid
            # counting their cost twice.
            shared = find_dependent_relations(current_partner,
                                              self._constraints)
            concerned = [rel for rel in self._constraints if rel not in shared]

            for (val_p, my_offer_val), partner_local_gain in offers.items():
                partial_asgt.update({
                    partner: val_p,
                    self.variable.name: my_offer_val
                })

                # Then we evaluate the agent constraint's for the offer
                # and add the partner's local gain.
                cost = assignment_cost(partial_asgt, concerned)
                global_gain = self.current_cost - cost + partner_local_gain

                if (global_gain > best_gain
                        and self._mode == "min") or (global_gain < best_gain
                                                     and self._mode == "max"):
                    bests = [(val_p, my_offer_val, partner)]
                    best_gain = global_gain
                elif global_gain == best_gain:
                    bests.append((val_p, my_offer_val, partner))

        return bests, best_gain
Example #2
0
def build_computation_graph(
    dcop: Optional[DCOP] = None,
    variables: Iterable[Variable] = None,
    constraints: Iterable[Constraint] = None,
) -> OrderedConstraintGraph:
    computations = []
    if dcop is not None:
        if constraints or variables is not None:
            raise ValueError("Cannot use both dcop and constraints / "
                             "variables parameters")
        for v in dcop.variables.values():
            var_constraints = find_dependent_relations(
                v, dcop.constraints.values())
            computations.append(VariableComputationNode(v, var_constraints))
    else:
        if constraints is None or variables is None:
            raise ValueError(
                "Constraints AND variables parameters must be "
                "provided when not building the graph from a dcop")
        for v in variables:
            var_constraints = find_dependent_relations(v, constraints)
            computations.append(VariableComputationNode(v, var_constraints))

    return OrderedConstraintGraph(computations)
Example #3
0
def build_computation_graph(dcop: DCOP,
                            variables: Iterable[Variable]=None,
                            constraints: Iterable[Constraint]=None,
                            )-> ComputationsFactorGraph:
    """Build a Factor graph computation graph for a DCOP.


    Parameters
    ----------
    dcop: DCOP
        a DCOP objects containing variables and constraints
    variables: iterable of Variables objects
        The variables to build the computation graph from. When this
        parameter is used, the `constraints` parameter MUST also be given.
    constraints: iterable of Constraints objects
        The constraints to build the computation graph from. When this
        parameter is used, the `variables` parameter MUST also be given.

    """

    # TODO : external variables computation ?
    if dcop is not None:
        if constraints or variables is not None:
            raise ValueError('Cannot use both dcop and constraints / '
                             'variables parameters')
        variables = dcop.variables.values()
        constraints = dcop.constraints.values()
    elif constraints is None or variables is None:
            raise ValueError('Constraints AND variables parameters must be '
                             'provided wgen not building the graph from a dcop')

    var_nodes = []
    for v in variables:
        dep = find_dependent_relations(v, constraints)
        var_nodes.append(VariableComputationNode(
            v, constraints_names=[d.name for d in dep]))

    factor_nodes = []
    for c in constraints:
        n = FactorComputationNode(c)
        factor_nodes.append(n)

    fg = ComputationsFactorGraph(var_nodes, factor_nodes)
    return fg
Example #4
0
    def _find_best_offer(self, all_offers):
        """
        Find the offer that maximize the global gain of both partners in
        the given offers and for the given partner.
        :param all_offers: a list of couples (offerer_name, offer) where
        offer is a dictionary of offers {(partner_val, my_val): partner_gain}
        Mgm2OfferMessage
        :return: (list of best offers, global_gain)
        """
        bests, best_gain = [], 0

        for partner, offers in all_offers:
            partial_asgt = self._neighbors_values.copy()
            current_partner = self._neighbor_var(partner)

            # Filter out the constraints linking those two variables to avoid
            # counting their cost twice.
            shared = find_dependent_relations(current_partner,
                                              self._constraints)
            concerned = [rel for rel in self._constraints if rel not in shared]

            for (val_p, my_offer_val), partner_local_gain in offers.items():
                partial_asgt.update({
                    partner: val_p,
                    self.variable.name: my_offer_val
                })

                # Then we evaluate the agent constraint's for the offer
                # and add the partner's local gain.
                cost = self._compute_cost(partial_asgt, concerned)
                global_gain = self.current_cost - cost + partner_local_gain

                if (global_gain > best_gain and self._mode == 'min') \
                        or (global_gain < best_gain and self._mode == 'max'):
                    bests = [(val_p, my_offer_val, partner)]
                    best_gain = global_gain
                elif global_gain == best_gain:
                    bests.append((val_p, my_offer_val, partner))

        return bests, best_gain
def dmaxsum_external_variable():

    domain = VariableDomain('colors', 'color', ['R', 'G', 'B'])
    # RW Variables
    v1 = VariableNoisyCostFunc('v1', domain, prefer_color('R'))
    v2 = VariableNoisyCostFunc('v2', domain, prefer_color('B'))
    v3 = VariableNoisyCostFunc('v3', domain, prefer_color('B'))
    v4 = VariableNoisyCostFunc('v4', domain, prefer_color('R'))

    # External Variable
    domain_e = VariableDomain('boolean', 'abstract', [False, True])
    e1 = ExternalVariable('e1', domain_e, False)

    def r1(v1_, v2_, v3_):
        if v1_ != v2_ and v2_ != v3_ and v1_ != v3_:
            return 0
        return 100

    condition = NAryFunctionRelation(lambda x: x, [e1], name='r1_cond')
    relation_if_true = NAryFunctionRelation(r1, [v1, v2, v3], name='r1')
    r1 = ConditionalRelation(condition, relation_if_true)

    def r2(v2_, v4_):
        if v2_ != v4_:
            return 0
        return 100

    r2 = NAryFunctionRelation(r2, [v2, v4], name='r2')

    def r3(v3_, v4_):
        if v3_ != v4_:
            return 0
        return 100

    r3 = NAryFunctionRelation(r3, [v3, v4], name='r3')

    r1_computation = DynamicFactorComputation(r1, name='r1')
    r2_computation = DynamicFactorComputation(r2)
    r3_computation = DynamicFactorComputation(r3)

    e1_computation = ExternalVariableComputation(e1)

    # MUST only consider current relation when building computation objects !!
    # When a relation uses external variable, these must be sliced out.
    current_r1 = r1.slice({e1.name: e1.value})
    relations = [current_r1, r2, r3]
    v1_computation = \
        DynamicFactorVariableComputation(
            v1,
            [r.name for r in find_dependent_relations(v1, relations)])
    v2_computation = \
        DynamicFactorVariableComputation(
            v2,
            [r.name for r in find_dependent_relations(v2, relations)])
    v3_computation = \
        DynamicFactorVariableComputation(
            v3,
            [r.name for r in find_dependent_relations(v3, relations)])
    v4_computation = \
        DynamicFactorVariableComputation(
            v4,
            [r.name for r in find_dependent_relations(v4, relations)])

    # Prepare the agents
    comm = InProcessCommunicationLayer()
    a1 = Agent('a1', comm)
    a1.add_computation(v1_computation)
    a1.add_computation(r1_computation)

    a2 = Agent('a2', comm)
    a2.add_computation(v2_computation)
    a1.add_computation(r2_computation)

    a3 = Agent('a3', comm)
    a3.add_computation(v3_computation)
    a3.add_computation(v4_computation)
    a3.add_computation(r3_computation)

    a4 = Agent('a4', comm)
    a4.add_computation(e1_computation)

    agents = [a1, a2, a3, a4]
    runner = AgentsRunner(agents)
    runner.run_agents()

    # Now change a factor function every two seconds
    fail = False
    for i in range(5):
        time.sleep(2)
        current_value = e1_computation.current_value
        print('###  Iteration {} - function {}'.format(i, current_value))
        print(runner.status_string())
        results = runner.variable_values()
        if current_value:
            c = r1(filter_assignment_dict(results, r1.dimensions)) + \
                r2(filter_assignment_dict(results, r2.dimensions)) + \
                r3(filter_assignment_dict(results, r3.dimensions))
            if c != 0:
                print('Error on results for {} : \nGot {}  !'.format(
                    current_value, results))
                fail = True
                break
        else:
            c = r2(filter_assignment_dict(results, r2.dimensions)) + \
                r3(filter_assignment_dict(results, r3.dimensions))
        if c != 0:
            print('Error on results for {} : \nGot {} !'.format(
                current_value, results))
            fail = True
            break

        new_val = not current_value
        print('## Changing e1 value to {}'.format(new_val))
        e1_computation.change_value(new_val)

    print('Finished, stopping agents')
    runner.request_stop_agents(wait_for_stop=True)

    if fail:
        print('Failed !')
        return 1
    else:
        print('Success !')
        return 0
def dmaxsum_graphcoloring():

    v1 = VariableNoisyCostFunc('v1', d, prefer_color('R'))
    v2 = VariableNoisyCostFunc('v2', d, prefer_color('G'))
    v3 = VariableNoisyCostFunc('v3', d, prefer_color('B'))
    v4 = VariableNoisyCostFunc('v4', d, prefer_color('R'))

    def r1(v1_, v2_, v3_):
        if v1_ != v2_ and v2_ != v3_ and v1_ != v3_:
            return 0
        return 100

    r1 = NAryFunctionRelation(r1, [v1, v2, v3], name='r1')

    def r1_2(v1_, v2_, v4_):
        if v1_ != v2_ and v2_ != v4_ and v1_ != v4_:
            return 0
        return 100

    r1_2 = NAryFunctionRelation(r1_2, [v1, v2, v4], name='r1_2')

    def r2(v2_, v4_):
        if v2_ != v4_:
            return 0
        return 100

    r2 = NAryFunctionRelation(r2, [v2, v4], name='r2')

    def r3(v3_, v4_):
        if v3_ != v4_:
            return 0
        return 100

    r3 = NAryFunctionRelation(r3, [v3, v4], name='r3')

    relations = [r1, r2, r3]
    r1_computation = DynamicFactorComputation(r1, name='r1')
    r2_computation = DynamicFactorComputation(r2)
    r3_computation = DynamicFactorComputation(r3)

    v1_computation = \
        DynamicFactorVariableComputation(
            v1,
            [r.name for r in find_dependent_relations(v1, relations)])
    v2_computation = \
        DynamicFactorVariableComputation(
            v2,
            [r.name for r in find_dependent_relations(v2, relations)])
    v3_computation = \
        DynamicFactorVariableComputation(
            v3,
            [r.name for r in find_dependent_relations(v3, relations)])
    v4_computation = \
        DynamicFactorVariableComputation(
            v4,
            [r.name for r in find_dependent_relations(v4, relations)])

    # Prepare the agents
    comm = InProcessCommunicationLayer()
    a1 = Agent('a1', comm)
    a1.add_computation(v1_computation)
    a1.add_computation(r1_computation)

    a2 = Agent('a2', comm)
    a2.add_computation(v2_computation)
    a1.add_computation(r2_computation)

    a3 = Agent('a3', comm)
    a3.add_computation(v3_computation)
    a3.add_computation(v4_computation)
    a3.add_computation(r3_computation)

    # Expected results to check for success
    expected_results = {
        'r1': {
            'v1': 'R',
            'v2': 'G',
            'v3': 'B',
            'v4': 'R'
        },
        'r1_2': {
            'v1': 'B',
            'v2': 'G',
            'v3': 'B',
            'v4': 'R'
        }
    }
    r1_fcts = [r1, r1_2]

    agents = [a1, a2, a3]

    for a in agents:
        a.start()

    # Now change a factor function every two seconds
    r1_fct, iteration, fail = 0, 0, False
    for _ in range(5):
        iteration += 1
        time.sleep(2)
        print('###  Iteration {} - function {}'.format(iteration,
                                                       r1_fcts[r1_fct].name))
        print(runner.status_string())
        results = runner.variable_values()
        if not results == expected_results[r1_fcts[r1_fct].name]:
            print('Error on results for {} : \nGot {} instead of {}  !'.format(
                r1_fcts[r1_fct].name, results,
                expected_results[r1_fcts[r1_fct].name]))
            fail = True
            break
        r1_fct = (r1_fct + 1) % 2
        print('## Changing to function {}'.format(r1_fcts[r1_fct].name))
        r1_computation.change_factor_function(r1_fcts[r1_fct])

    print('Finished, stopping agents')
    runner.request_stop_agents(wait_for_stop=True)

    if fail:
        print('Failed !')
        return 1
    else:
        print('Success !')
        return 0
def build_computation_graph(
    dcop: DCOP = None,
    variables: Iterable[Variable] = None,
    constraints: Iterable[Constraint] = None,
) -> ComputationConstraintsHyperGraph:
    """
    Build a computation hyper graph for the DCOP.

    A computation graph is generally built from a DCOP, however it is also
    possible to build a sub-graph of the computation graph by simply passing
    the variables and constraints.

    Parameters
    ----------
    dcop: DCOP
        DCOP object to build the computation graph from.When this
        parameter is used, the `constraints` and `variables` parameters MUST
        NOT be used.
    variables: iterable of Variables objects
        The variables to build the computation graph from. When this
        parameter is used, the `constraints` parameter MUST also be given.
    constraints: iterable of Constraints objects
        The constraints to build the computation graph from. When this
        parameter is used, the `variables` parameter MUST also be given.

    Returns
    -------
    ComputationConstraintsHyperGraph
        In hyper-graph for the variables and constraints

    Raises
    ------
    ValueError
        If both `dcop` and one of the `variables` or `constraints` arguments
        have been used.

    """
    computations = []
    if dcop is not None:
        if constraints or variables is not None:
            raise ValueError(
                "Cannot use both dcop and constraints / " "variables parameters"
            )
        for v in dcop.variables.values():
            var_constraints = find_dependent_relations(v, dcop.constraints.values())
            computations.append(VariableComputationNode(v, var_constraints))
    else:
        if constraints is None or variables is None:
            raise ValueError(
                "Constraints AND variables parameters must be "
                "provided when not building the graph from a dcop"
            )
        for v in variables:
            var_constraints = find_dependent_relations(v, constraints)
            computations.append(VariableComputationNode(v, var_constraints))

    # links = []
    # for r in dcop.constraints.values():
    #     in_scope = (v.name for v in r.dimensions)
    #     links.append(ConstraintLink(r.name, in_scope))

    return ComputationConstraintsHyperGraph(computations)