def directory_discovery():
    # Agent hosting the directory
    agt_dir = Agent('agt_dir', InProcessCommunicationLayer())
    directory = Directory(agt_dir.discovery)
    agt_dir.add_computation(directory.directory_computation)
    agt_dir.discovery.use_directory('agt_dir', agt_dir.address)
    agt_dir.start()
    agt_dir.run(directory.directory_computation.name)

    # standard agents
    agt1 = Agent('agt1', InProcessCommunicationLayer())
    agt1.discovery.use_directory('agt_dir', agt_dir.address)
    agt1.start()

    agt2 = Agent('agt2', InProcessCommunicationLayer())
    agt2.discovery.use_directory('agt_dir', agt_dir.address)
    agt2.start()

    yield agt_dir, agt1, agt2

    for c in agt1.computations():
        agt1.remove_computation(c.name)
    for c in agt1.discovery.agent_computations(agt1.name):
        agt1.discovery.unregister_computation(c)

    for c in agt2.computations():
        agt2.remove_computation(c.name)
    for c in agt2.discovery.agent_computations(agt2.name):
        agt2.discovery.unregister_computation(c)
    wait_run()

    agt1.stop()
    agt2.stop()
    agt_dir.stop()
Пример #2
0
    def test_sendRevievedFrom(self):

        comm = InProcessCommunicationLayer()
        a1 = infrastructure.Agent('a1', comm)
        a2 = infrastructure.Agent('a2', comm)
        comm.register(a1.name, a1)
        comm.register(a2.name, a2)

        # use monkey patching on instance to set the _on_start method on a1
        # simply send a message to a2
        def a1_start(self):
            print('starting a1')
            print('sending msg to ')
            self.send_msg('a1', 'a2', 'msg')

        a1._on_start = types.MethodType(a1_start, a1)

        # Monkey patching a2 to check for message arrival
        a2.received_from = None

        def handle_message(self, sender, dest, msg):
            print('Receiving message from {} : {}'.format(sender, msg))
            self.received_from = sender
        a2._handle_message = types.MethodType(handle_message, a2)

        # Running the test
        a1.start()
        a2.start()
        time.sleep(0.1)

        self.assertEqual(a2.received_from, 'a1')

        a1.stop()
        a2.stop()
Пример #3
0
    def test_raise_when_sending_to_unknown_agent_fail_on_send(self):
        comm1 = InProcessCommunicationLayer()
        comm1.discovery = Discovery('a1', comm1)

        full_msg = ('c1', 'c2', 'msg')
        with pytest.raises(UnknownAgent):
            comm1.send_msg('a1', 'a2', full_msg, on_error='fail')
Пример #4
0
    def test_received_msg_is_delivered_to_messaging_queue(self):

        comm1 = InProcessCommunicationLayer()
        Messaging('a1', comm1)
        comm1.messaging.post_msg = MagicMock()

        comm1.receive_msg('a2', 'a1', ('c2', 'c1', 'msg', MSG_MGT))

        comm1.messaging.post_msg.assert_called_with('c2', 'c1', 'msg', 10)
Пример #5
0
    def test_retry_when_sending_to_unknown_agent_retry_on_send(self):
        comm1 = InProcessCommunicationLayer(None)
        comm1.discovery = Discovery('a1', comm1)

        full_msg = ('c1', 'c2', 'msg')
        assert not comm1.send_msg('a1', 'a2', full_msg, on_error='retry')

        comm2 = create_autospec(InProcessCommunicationLayer)
        comm1.discovery.register_agent('a2', comm2)

        comm2.receive_msg.assert_called_with('a1', 'a2', full_msg)
Пример #6
0
def distribute_agents(var_facts):
    comm = InProcessCommunicationLayer()

    dcop_agents = []
    factors = [f for _, f in var_facts]

    i = 0
    for v, f in var_facts:

        # Algorithm for variable
        # build the list of factors that depend on this variable
        f_for_variable = [
            f.name for f in factors
            if v.name in [i.name for i in f.dimensions]
        ]
        v_a = amaxsum.VariableAlgo(v, f_for_variable)

        # Algorithm for the factor
        f_a = amaxsum.FactorAlgo(f)

        # Agent hosting the factor and variable
        a = Agent('a_' + str(i), comm)
        a.add_computation(v_a)
        a.add_computation(f_a)
        i += 1

        dcop_agents.append(a)

    return dcop_agents, comm
def orchestrated_agent():
    a1_def = AgentDef('a1')
    agt = OrchestratedAgent(a1_def, InProcessCommunicationLayer(),
                            'fake_address')
    # As we don't create an orchestrator, catch message sending
    agt._messaging.post_msg = MagicMock()
    yield agt
    agt.stop()
Пример #8
0
def test_create():
    comm = InProcessCommunicationLayer()
    agent = Agent('agt1', comm)

    assert agent.name == 'agt1'
    assert not agent.computations()
    assert not agent.is_running
    assert agent.communication == comm
    assert agent.address == comm.address
Пример #9
0
    def test_msg_to_another_agent(self):

        comm1 = InProcessCommunicationLayer()
        Messaging('a1', comm1)
        comm1.discovery = Discovery('a1', comm1)

        comm2 = InProcessCommunicationLayer()
        Messaging('a2', comm2)
        comm2.discovery = Discovery('a2', comm2)
        comm2.receive_msg = MagicMock()

        comm1.discovery.register_agent('a2', comm2)

        full_msg = ('c1', 'c2', 'msg')
        comm1.send_msg('a1', 'a2', full_msg)

        comm2.receive_msg.assert_called_with('a1', 'a2', full_msg)
Пример #10
0
def maxsum_equality_noise():
    """
    This sample demonstrates the use of noise to break ties between variables.
    """

    l1 = VariableNoisyCostFunc('l1', list(range(10)), lambda x: x)
    l2 = VariableNoisyCostFunc('l2', list(range(10)), lambda x: x)

    # Scene action
    y1 = VariableWithCostFunc('y1', list(range(10)), lambda x: 10 * abs(5 - x))

    @AsNAryFunctionRelation(l1, l2, y1)
    def scene_rel(x, y, z):
        if z == x + y:
            return 0
        return 10000

    # Create computation for factors and variables
    # Light 1
    algo_l1 = VariableAlgo(l1, [scene_rel.name])

    # Light 2
    algo_l2 = VariableAlgo(l2, [scene_rel.name])

    # Scene
    algo_y1 = VariableAlgo(y1, [scene_rel.name])
    algo_scene = FactorAlgo(scene_rel)

    comm = InProcessCommunicationLayer()

    a1 = Agent('A1', comm)
    a1.add_computation(algo_l1)

    a2 = Agent('A2', comm)
    a2.add_computation(algo_l2)

    a3 = Agent('A3', comm)
    a3.add_computation(algo_y1)
    a3.add_computation(algo_scene)
    dcop_agents = [a1, a2, a3]

    results, _, _ = synchronous_single_run(dcop_agents, 5)

    print(results)

    if results['y1'] == 5 and results['l1'] + results['l2'] == 5:
        logging.info('SUCCESS !! ')
        return 0
    else:
        logging.info('invalid result found, needs some debugging ...' +
                     str(results))
        return 1
Пример #11
0
def agents():
    # Agent hosting the directory
    agt_dir = Agent('agt_dir', InProcessCommunicationLayer())
    directory = Directory(agt_dir.discovery)
    agt_dir.add_computation(directory.directory_computation)
    agt_dir.discovery.use_directory('agt_dir', agt_dir.address)
    agt_dir.start()
    agt_dir.run(directory.directory_computation.name)

    # standard agents
    agt1 = Agent('agt1', InProcessCommunicationLayer())
    agt1.discovery.use_directory('agt_dir', agt_dir.address)
    agt1.start()

    agt2 = Agent('agt2', InProcessCommunicationLayer())
    agt2.discovery.use_directory('agt_dir', agt_dir.address)
    agt2.start()

    yield agt_dir, agt1, agt2

    agt1.stop()
    agt2.stop()
    agt_dir.stop()
Пример #12
0
def dpop_unary_constraint():
    x0 = Variable('x0', ['a', 'b', 'c'])
    x1 = Variable('x1', ['a', 'b', 'c'])

    # Unary constraint on x0
    @relations.AsNAryFunctionRelation(x0)
    def unary_x1(x):
        if x == 'a':
            return 8
        if x == 'b':
            return 2
        if x == 'c':
            return 5

    @relations.AsNAryFunctionRelation(x0, x1)
    def prefer_different(x, y):
        if x == y:
            return 0
        else:
            return 10

    al0 = DpopAlgo(x0)
    al1 = DpopAlgo(x1)

    # Distribution: two agents
    comm = InProcessCommunicationLayer()
    a0 = Agent('a0', comm)
    a0.add_computation(al0)
    a1 = Agent('a1', comm)
    a1.add_computation(al1)

    al0.set_parent(x1)
    al0.add_relation(prefer_different)
    al1.add_child(x0)

    # we represent the unary constraint as a variable having itself as
    # pseudo-parent
    al0.add_relation(unary_x1)

    results, _, _ = synchronous_single_run([a0, a1])

    if results == {'x0': 'a', 'x1': 'b'} or \
       results == {'x0': 'a', 'x1': 'c'}:
        logging.info('SUCCESS !! ')
        return 0
    else:
        logging.info('invalid result found, needs some debugging ...' + str(
            results))
        return 1
Пример #13
0
    def test_addresses_are_not_shared_accross_instances(self):
        comm1 = InProcessCommunicationLayer()
        comm1.discovery = Discovery('a1', 'addr1')

        comm2 = InProcessCommunicationLayer()
        comm2.discovery = Discovery('a2', 'addr2')

        comm1.discovery.register_agent('a1', comm1)

        with pytest.raises(UnknownAgent):
            comm2.discovery.agent_address('a1')
Пример #14
0
def distribute_agents(var_facts, variant, probability):
    comm = InProcessCommunicationLayer()

    dcop_agents = []
    factors = [f for _, f in var_facts]

    i = 0
    for v, f in var_facts:
        # Algorithm for variable
        # build the list of factors that depend on this variable
        f_for_variable = [
            f for f in factors if v.name in [i.name for i in f.dimensions]
        ]
        v_a = dsa.DsaComputation(v, f_for_variable, variant='A')

        # Agent hosting computation
        a = Agent('a_' + str(i), comm)
        a.add_computation(v_a)
        i += 1

        dcop_agents.append(a)

    return dcop_agents, comm
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 test_fix_delayed_message_on_start():
    """
    Test case for bug fix:

    c1 send a message to c2 during its `on_start` handler. If c2 is not started yet
    at that point, the message is stored and injected once c2 starts.

    Sometime, when c2 starts in a2, it does not receive the pending message from c1.
    This is timing dependent and most of the time, the bug does not happens, especially
    if the on_start handlers contain log statements.

    The problem is due to the fact that start, and hence, the on_start handler and
    pending messages injection, might be done on the main thread, while message reception
    (and thus storage of th pending messages) is performed on the agent's thread.

    Everything that happens in an agent MUST run on the agent thread, including startup !

    To start a computation (on a started agent), one may call the `agt.run()` method,
    from any thread, in which case the computation is also started from that thread,
    and not from the agent thread.

    Currently (10/2019), there are only two ways for avoiding this:
    * use an orcherstrated agent, and start computation by sending it messages.
      However this also means using an orchestrator, which is not convenient during test
      and when working on non-dcop algorithm (the orchestrator is heavily biased
      toward DCOPs)
    * start all computations when starting the agent,
      using `a.start(run_computations=True)`, which is the workaround tested here.
    """
    class TestComputation1(MessagePassingComputation):
        def __init__(self):
            super().__init__("c1")

        def on_start(self):
            # self.logger.info("Starting c1, send to c2")
            self.post_msg("c2", Message("foo"))

    class TestComputation2(MessagePassingComputation):
        def __init__(self):
            super().__init__("c2")
            self.received = False

        # def on_start(self):
        #     # self.logger.info("Starting c2")
        #     pass

        @register("foo")
        def on_foo(self, sender, msg, t):
            self.logger.info(f"Receiving message {msg} from {sender}")
            self.received = True

    c1 = TestComputation1()
    c2 = TestComputation2()

    a1 = Agent("a1", InProcessCommunicationLayer())
    a1.add_computation(c1)
    a2 = Agent("a2", InProcessCommunicationLayer())
    a2.add_computation(c2)

    a1.discovery.register_computation("c2", "a2", a2.address)
    a2.discovery.register_computation("c1", "a1", a1.address)

    agts = [a1, a2]
    for a in agts:
        a.start(run_computations=True)

    sleep(0.5)

    for a in agts:
        a.stop()
    for a in agts:
        a.join()

    # Check that c2 really received the message
    assert c2.received
Пример #17
0
def local_messaging():
    comm = InProcessCommunicationLayer()
    comm.discovery = Discovery('a1', 'addr1')
    messaging = Messaging('a1', comm)
    return messaging
def dpop_nonbinaryrelation_4vars():

    x0 = Variable('x0', list(range(10)))
    x1 = Variable('x1', list(range(10)))
    x2 = Variable('x2', list(range(10)))
    x3 = Variable('x3', list(range(10)))

    @relations.AsNAryFunctionRelation(x0)
    def x0_prefs(x):
        if x > 3:
            return 0
        return 10

    @relations.AsNAryFunctionRelation(x1)
    def x1_prefs(x):
        if 2 < x < 7:
            return 0
        return 10

    @relations.AsNAryFunctionRelation(x2)
    def x2_prefs(x):
        if x < 5:
            return 0
        return 10

    @relations.AsNAryFunctionRelation(x3)
    def x3_prefs(x):
        if 0 < x < 5:
            return 0
        return 10

    @relations.AsNAryFunctionRelation(x0, x1, x2, x3)
    def four_ary_relation(a, b, c, d):
        return abs(10 - (a + b + c + d))

    def neutral_relation(x, y):
        return 0

    comm = InProcessCommunicationLayer()

    al0 = DpopAlgo(x0, mode='min')
    al1 = DpopAlgo(x1, mode='min')
    al2 = DpopAlgo(x2, mode='min')
    al3 = DpopAlgo(x3, mode='min')

    # unary relation for preferences
    al0.add_relation(x0_prefs)
    al1.add_relation(x1_prefs)
    al2.add_relation(x2_prefs)
    al3.add_relation(x3_prefs)

    # The 4-ary relation must be introduced only once, in the lowest node in
    # the DFS tree (in our case, a3).
    # We still need to add relation between the
    # We use neutral relation between two variables that are present in the
    # tree but that do not share a real constraint : in reality with the
    # current implementation, these neutral relation are not needed any-more,
    #  I just keep them here for historical reasons.

    al0.add_child(x1)
    al1.set_parent(x0)
    al1.add_relation(relations.NAryFunctionRelation(neutral_relation,
                                                    [x0, x1]))

    al1.add_child(x2)
    al2.set_parent(x1)
    al2.add_relation(relations.NAryFunctionRelation(neutral_relation,
                                                    [x1, x2]))

    al2.add_child(x3)
    al3.set_parent(x2)
    al3.add_relation(relations.NAryFunctionRelation(neutral_relation,
                                                    [x2, x3]))

    al3.add_relation(four_ary_relation)

    a0 = Agent('a0', comm)
    a0.add_computation(al0)
    a1 = Agent('a1', comm)
    a1.add_computation(al1)
    a2 = Agent('a2', comm)
    a2.add_computation(al2)
    a3 = Agent('a3', comm)
    a3.add_computation(al3)

    results, _, _ = synchronous_single_run([a0, a1, a2, a3])

    if results == {'x0': 4, 'x2': 0, 'x1': 3, 'x3': 3}:
        logging.info('SUCCESS !! ' + str(results))
        return 0
    else:
        logging.info('invalid result found, needs some debugging ...' +
                     str(results))
        return 1
Пример #19
0
    def test_ignore_when_sending_to_unknown_agent_ignore_on_send(self):
        comm1 = InProcessCommunicationLayer()
        comm1.discovery = Discovery('a1', comm1)

        full_msg = ('c1', 'c2', 'msg')
        assert comm1.send_msg('a1', 'a2', full_msg, on_error='ignore')
Пример #20
0
def test_api_cg_creation_mgm2():
    # This time we solve the same graph coloring problem with the MGM2
    # algorithm.
    # As you can see, the only difference is the creation of the AlgorithmDef
    # instance with 'mgm2'
    d = Domain('color', '', ['R', 'G'])
    v1 = Variable('v1', d)
    v2 = Variable('v2', d)
    v3 = Variable('v3', d)

    # We need to define all agents first, because we will need their address
    # when registering neighbors computation
    agt1 = Agent('a1', InProcessCommunicationLayer())
    agt2 = Agent('a2', InProcessCommunicationLayer())
    agt3 = Agent('a3', InProcessCommunicationLayer())

    # Agent 1 with Variable v1
    cost_v1 = constraint_from_str('cv1', '-0.1 if v1 == "R" else 0.1 ', [v1])
    diff_v1_v2 = constraint_from_str('c1', '1 if v1 == v2 else 0', [v1, v2])

    node_v1 = chg.VariableComputationNode(v1, [cost_v1, diff_v1_v2])
    comp_def = ComputationDef(node_v1,
                              AlgorithmDef.build_with_default_param('mgm2'))
    v1_computation = build_computation(comp_def)

    agt1.add_computation(v1_computation)
    # We need to register manually as we are not using the directory hosted by
    # the orchestrator.
    agt1.discovery.register_computation('v2', 'a2', agt2.address)

    # Agent 2 with Variable v2
    cost_v2 = constraint_from_str('cv2', '-0.1 if v2 == "G" else 0.1 ', [v2])
    diff_v2_v3 = constraint_from_str('c2', '1 if v2 == v3 else 0', [v2, v3])

    node_v2 = chg.VariableComputationNode(v2, [cost_v2, diff_v2_v3, diff_v1_v2])
    comp_def_v2 = ComputationDef(node_v2,
                                 AlgorithmDef.build_with_default_param('mgm2'))
    v2_computation = build_computation(comp_def_v2)

    agt2.add_computation(v2_computation)
    agt2.discovery.register_computation('v1', 'a1', agt1.address)
    agt2.discovery.register_computation('v3', 'a3', agt3.address)

    # Agent 3 with Variable v3
    cost_v3 = constraint_from_str('cv3', '-0.1 if v3 == "G" else 0.1 ', [v3])

    node_v3 = chg.VariableComputationNode(v3, [cost_v3, diff_v2_v3])
    comp_def_v3 = ComputationDef(node_v3,
                                 AlgorithmDef.build_with_default_param('mgm2'))
    v3_computation = build_computation(comp_def_v3)

    agt3.add_computation(v3_computation)
    agt3.discovery.register_computation('v2', 'a2', agt2.address)

    # Start and run the 3 agents manually:
    agts = [agt1, agt2, agt3]
    for a in agts:
        a.start()
    for a in agts:
        a.run()
    sleep(1)  # let the system run for 1 second
    for a in agts:
        a.stop()

    # As we do not have an orchestrator, we need to collect results manually.
    # As with MGM, MGM2 does not necessarily find the optimal solution,
    # depending on the start affectation (which may require a 3-coordinated
    # change and thus is not possible with mgm2), so we just check the
    # hard constraints
    assert agt1.computation('v1').current_value != \
        agt2.computation('v2').current_value
    assert agt3.computation('v3').current_value != \
        agt2.computation('v2').current_value
Пример #21
0
def test_api_cg_creation_dsa():
    # creating a computation graph from API, without relying on a full
    # description of the DCOP.
    # Two API level
    #  * DCOP : create a dcop
    #  * Computation graph:

    # DCOP
    # works when using an orchestrator that can transform a dcop into a
    # computation graph and distribute the computation on the set of agents.
    # Efficient and simple solution when there is a single deployement of the
    # system at startup.

    # Computation Graph
    # create the computations directly
    # Necessary when there is no central place where the full dcop could be
    # created. Each agent build the computation it will run, for example when
    # the definition of the dcop changes at run time or when a new dcop must be
    # created and solve completely dynamically and runtime without relying on a
    # central element like an orchestrator.

    # to create a computation instance, one need:
    # of course, variable(s) and constraint(s) like for the dcop.
    # but also
    # an algo_def : given as input
    # a comp_node : depends of the type of computation graph, requires a
    # variable and  or constraints

    # Here we define a simple graph coloring problem with 3 variables:
    d = Domain('color', '', ['R', 'G'])
    v1 = Variable('v1', d)
    v2 = Variable('v2', d)
    v3 = Variable('v3', d)

    # We need to define all agents first, because we will need their address
    # when registering neighbors computation
    agt1 = Agent('a1', InProcessCommunicationLayer())
    agt2 = Agent('a2', InProcessCommunicationLayer())
    agt3 = Agent('a3', InProcessCommunicationLayer())

    # Agent 1 with Variable v1
    # Constraints in which v1 is involved
    cost_v1 = constraint_from_str('cv1', '-0.1 if v1 == "R" else 0.1 ', [v1])
    diff_v1_v2 = constraint_from_str('c1', '1 if v1 == v2 else 0', [v1, v2])
    # Computation node for the variable with these constraints
    node_v1 = chg.VariableComputationNode(v1, [cost_v1, diff_v1_v2])
    comp_def = ComputationDef(node_v1, AlgorithmDef.build_with_default_param('dsa'))
    v1_computation = build_computation(comp_def)
    # and register the computation and the agents for the neighboring
    # computations.
    agt1.add_computation(v1_computation)
    agt1.discovery.register_computation('v2', 'a2', agt2.address)

    # Agent 2 with Variable v2
    cost_v2 = constraint_from_str('cv2', '-0.1 if v2 == "G" else 0.1 ', [v2])
    diff_v2_v3 = constraint_from_str('c2', '1 if v2 == v3 else 0', [v2, v3])

    node_v2 = chg.VariableComputationNode(v2, [cost_v2, diff_v2_v3, diff_v1_v2])
    comp_def_v2 = ComputationDef(node_v2,
                                 AlgorithmDef.build_with_default_param('dsa'))
    v2_computation = build_computation(comp_def_v2)

    agt2.add_computation(v2_computation)
    agt2.discovery.register_computation('v1', 'a1', agt1.address)
    agt2.discovery.register_computation('v3', 'a3', agt3.address)

    # Agent 3 with Variable v3
    cost_v3 = constraint_from_str('cv3', '-0.1 if v3 == "G" else 0.1 ', [v3])

    node_v3 = chg.VariableComputationNode(v3, [cost_v3, diff_v2_v3])
    comp_def_v3 = ComputationDef(node_v3,
                                 AlgorithmDef.build_with_default_param('dsa'))
    v3_computation = build_computation(comp_def_v3)

    agt3.add_computation(v3_computation)
    agt3.discovery.register_computation('v2', 'a2', agt2.address)

    # Start and run the 3 agents manually:
    agts = [agt1, agt2, agt3]
    for a in agts:
        a.start()
    for a in agts:
        a.run()
    sleep(1)  # let the system run for 1 second
    for a in agts:
        a.stop()

    # As we do not have an ochestrator, we need to collect results manually:
    assert agt1.computation('v1').current_value != \
        agt2.computation('v2').current_value
    assert agt3.computation('v3').current_value != \
        agt2.computation('v2').current_value
Пример #22
0
def run_local_thread_dcop(
        algo: AlgoDef,
        cg: ComputationGraph,
        distribution: Distribution,
        dcop: DCOP,
        infinity,  # FIXME : this has nothing to to here, #41
        collector: Queue = None,
        collect_moment: str = 'value_change',
        period=None,
        replication=None) -> Orchestrator:
    """Build orchestrator and agents for running a dcop in threads.

    The DCOP will be run in a single process, using one thread for each agent.

    Parameters
    ----------
    algo: AlgoDef
        Definition of DCOP algorithm, with associated parameters
    cg: ComputationGraph
        The computation graph used to solve the DCOP with the given algorithm
    distribution: Distribution
        Distribution of the computation on the agents
    dcop: DCOP
        The DCOP instance to solve
    infinity:
        FIXME : remove this!
    collector: queue
        optionnal queue, used to collect metrics
    collect_moment: str
        metric collection configuration : 'cycle_change', 'value_change' or
        'period'
    period: float
        period for collecting metrics, only used we 'period' metric collection
    replication
        replication algorithm,  for resilent DCOP.

    Returns
    -------
    orchestator
        An orchestrator agent that bootstrap dcop agents, monitor them and
        collects metrics.

    See Also
    --------
    Orchestrator, OrchestratedAgent
    run_local_process_dcopb


    """
    agents = dcop.agents
    comm = InProcessCommunicationLayer()
    orchestrator = Orchestrator(algo,
                                cg,
                                distribution,
                                comm,
                                dcop,
                                infinity,
                                collector=collector,
                                collect_moment=collect_moment)
    orchestrator.start()

    # Create and start all agents.
    # Each agent will register it-self on the orchestrator
    for a_name in dcop.agents:
        comm = InProcessCommunicationLayer()
        agent = OrchestratedAgent(agents[a_name],
                                  comm,
                                  orchestrator.address,
                                  metrics_on=collect_moment,
                                  metrics_period=period,
                                  replication=replication)
        agent.start()

    # once all agents have started and registered to the orchestrator,
    # computation will be deployed on them and then run.
    return orchestrator
def dpop_nonbinaryrelation():

    x0 = Variable('x0', list(range(10)))
    x1 = Variable('x1', list(range(10)))
    x2 = Variable('x2', list(range(10)))

    @relations.AsNAryFunctionRelation(x0)
    def x0_prefs(x):
        if x > 5:
            return 0
        return 10

    @relations.AsNAryFunctionRelation(x1)
    def x1_prefs(x):
        if 2 < x < 7:
            return 0
        return 10

    @relations.AsNAryFunctionRelation(x2)
    def x2_prefs(x):
        if x < 5:
            return 0
        return 10

    @relations.AsNAryFunctionRelation(x0, x1, x2)
    def three_ary_relation(x, y, z):
        return abs(10 - (x+y+z))

    comm = InProcessCommunicationLayer()

    al0 = DpopAlgo(x0, mode='min')
    al1 = DpopAlgo(x1, mode='min')
    al2 = DpopAlgo(x2, mode='min')

    # unary relation for preferences
    al0.add_relation(x0_prefs)
    al1.add_relation(x1_prefs)
    al2.add_relation(x2_prefs)

    al0.add_child(x1)
    al1.add_child(x2)
    al1.set_parent(x0)
    al2.set_parent(x1)
    al2.add_relation(three_ary_relation)

    a0 = Agent('a0', comm)
    a1 = Agent('a1', comm)
    a2 = Agent('a2', comm)

    a0.add_computation(al0)
    a1.add_computation(al1)
    a2.add_computation(al2)

    results, _, _ = synchronous_single_run([a0, a1, a2])

    if results == {'x0': 6, 'x1': 3, 'x2': 1} or \
       results == {'x0': 7, 'x1': 3, 'x2': 0}:
        logging.info('SUCCESS !! ' + str(results))
        return 0
    else:
        logging.info('invalid result found, needs some debugging ...' + str(
            results))
        return 1
Пример #24
0
def agent():
    agt = Agent('agt1', InProcessCommunicationLayer())
    yield agt
    agt.stop()
Пример #25
0
 def test_address(self):
     # for in-process, the address is the object it-self
     comm1 = InProcessCommunicationLayer()
     assert comm1.address == comm1
Пример #26
0
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
Пример #27
0
def dpop_graphcoloring_1():
    x0 = Variable('x0', ['R', 'G', 'B'])
    x1 = Variable('x1', ['R', 'G', 'B'])
    x2 = Variable('x2', ['R', 'G', 'B'])

    # Unary constraint on x0
    @relations.AsNAryFunctionRelation(x0)
    def x0_prefers_r(x):
        if x == 'R':
            return 0
        return 10

    @relations.AsNAryFunctionRelation(x1)
    def x1_prefers_g(x):
        if x == 'G':
            return 0
        return 10

    @relations.AsNAryFunctionRelation(x2)
    def x2_prefers_b(x):
        if x == 'B':
            return 0
        return 10

    def prefer_different(x, y):
        if x == y:
            return 10
        else:
            return 0

    r1_0 = relations.NAryFunctionRelation(prefer_different, [x0, x1])
    r0_2 = relations.NAryFunctionRelation(prefer_different, [x0, x2])
    r1_2 = relations.NAryFunctionRelation(prefer_different, [x1, x2])

    # Create computations objects to solve this problem
    # For this we must define the DFS tree
    # x0 ---> x1 ---> x2
    # preferences are modeled as unary relation, set directly on each variable
    # other constraints are represented by binary relations which are set on
    # the lowest variable in the tree.

    c0 = DpopAlgo(x0, mode='min')
    c0.add_child(x1)
    c0.add_relation(x0_prefers_r)

    c1 = DpopAlgo(x1, mode='min')
    c1.set_parent(x0)
    c1.add_child(x2)
    c1.add_relation(x1_prefers_g)
    c1.add_relation(r1_0)

    c2 = DpopAlgo(x2, mode='min')
    c2.set_parent(x1)
    c2.add_relation(x2_prefers_b)
    c2.add_relation(r0_2)
    c2.add_relation(r1_2)

    # Distribution: 3 agents, one for each variable
    comm = InProcessCommunicationLayer()
    a0 = Agent('a0', comm)
    a1 = Agent('a1', comm)
    a2 = Agent('a2', comm)

    a0.add_computation(c0)
    a1.add_computation(c1)
    a2.add_computation(c2)

    results, _, _ = synchronous_single_run([a0, a1, a2])

    if results == {'x0': 'R', 'x1': 'G', 'x2': 'B'}:
        logging.info('SUCCESS !! ')
        return 0
    else:
        logging.info('invalid result found, needs some debugging ...' +
                     str(results))
        return 1