def test_dcop_add_agents_from_list(): dcop = DCOP() a1 = AgentDef('a1') a2 = AgentDef('a2') dcop.add_agents([a1, a2]) assert dcop.agent('a1').name == 'a1' assert dcop.agent('a2').name == 'a2'
def setUp(self): c1 = ComputationNode('c1', 'dummy_type', neighbors=['c2']) c2 = ComputationNode('c2', 'dummy_type', neighbors=['c1']) self.cg = ComputationGraph(graph_type='test', nodes=[c1, c2]) self.agents = [AgentDef('a1'), AgentDef('a2')]
def test_respect_must_host_all_computation_invalid(self): f1 = relation_from_str('f1', 'v1 * 0.5', [v1]) cv1 = VariableComputationNode(v1, ['f1']) cf1 = FactorComputationNode(f1) cg = ComputationsFactorGraph([cv1], [cf1]) a1 = AgentDef("a1", capacity=200, default_hosting_cost=1, hosting_costs={ "f1": 0, "v1": 0 }) a2 = AgentDef("a2", capacity=200, default_hosting_cost=1) # These hints lead to an impossible distribution, as ilp-fgdp requires # each agent to host at least one computation. Here Both # computations are hosted on a1 and there is no computation # available for a2 ! self.assertRaises(ImpossibleDistributionException, distribute, cg, [a1, a2], hints=None, computation_memory=ms.computation_memory, communication_load=ms.communication_load)
def test_respect_must_host_all_computation_fixed(self): f1 = relation_from_str('f1', 'v1 * 0.5 + v2', [v1, v2]) cv1 = VariableComputationNode(v1, ['f1']) cv2 = VariableComputationNode(v2, []) cf1 = FactorComputationNode(f1) cg = ComputationsFactorGraph([cv1, cv2], [cf1]) a1 = AgentDef("a1", capacity=200, default_hosting_cost=1, hosting_costs={ "f1": 0, "v1": 0 }) a2 = AgentDef("a2", capacity=200, default_hosting_cost=1, hosting_costs={"v2": 0}) agent_mapping = distribute(cg, [a1, a2], hints=None, computation_memory=ms.computation_memory, communication_load=ms.communication_load) self.assertEqual(agent_mapping.agent_for('f1'), 'a1') self.assertEqual(agent_mapping.agent_for('v1'), 'a1') self.assertEqual(agent_mapping.agent_for('v2'), 'a2')
def test_comm_not_enough_place(self): f1 = relation_from_str('f1', 'v1 * 0.5 + v2 + v3', [v1, v2, v3]) cv1 = VariableComputationNode(v1, ['f1']) cv2 = VariableComputationNode(v2, ['f1']) cv3 = VariableComputationNode(v3, ['f1']) cf1 = FactorComputationNode(f1) cg = ComputationsFactorGraph([cv1, cv2, cv3], [cf1]) a1 = AgentDef("a1", capacity=200, default_hosting_cost=1, hosting_costs={ "v1": 0, "v2": 0 }) a2 = AgentDef("a2", capacity=200, default_hosting_cost=1) a1.capacity = 15 agent_mapping = distribute(cg, [a1, a2], hints=None, computation_memory=ms.computation_memory, communication_load=ms.communication_load) # As there is enough not capacity on a1, factor f1 and variable v3 # must go on a2 self.assertEqual(agent_mapping.agent_for('f1'), 'a2') self.assertEqual(agent_mapping.agent_for('v3'), 'a2')
def test_comm(self): f1 = relation_from_str('f1', 'v1 * 0.5 + v2 + v3', [v1, v2, v3]) cv1 = VariableComputationNode(v1, ['f1']) cv2 = VariableComputationNode(v2, ['f1']) cv3 = VariableComputationNode(v3, ['f1']) cf1 = FactorComputationNode(f1) cg = ComputationsFactorGraph([cv1, cv2, cv3], [cf1]) a1 = AgentDef("a1", capacity=200, default_hosting_cost=1, hosting_costs={ "v1": 0, "v2": 0 }) a2 = AgentDef("a2", capacity=200, default_hosting_cost=1) a1.capacity = 1000 agent_mapping = distribute(cg, [a1, a2], hints=None, computation_memory=ms.computation_memory, communication_load=ms.communication_load) # As there is enough capacity on a1, factor f1 must go there (where # most of its variable are already hosted) while v3 must go on a2 to # make sure that all agents are used self.assertEqual(agent_mapping.agent_for('f1'), 'a1') self.assertEqual(agent_mapping.agent_for('v3'), 'a2')
def test_with_default_route(): a = AgentDef("a1", default_route=12) assert a.name == "a1" assert a.route("foo") == 12 assert a.route("bar") == 12
def test_with_default_route(self): a = AgentDef('a1', default_route=12) self.assertEqual(a.name, 'a1') self.assertEqual(a.route('foo'), 12) self.assertEqual(a.route('bar'), 12)
def test_with_hosting_cost(self): a = AgentDef('a1', hosting_costs={'foo': 5, 'bar': 7}) self.assertEqual(a.name, 'a1') self.assertEqual(a.hosting_cost('foo'), 5) self.assertEqual(a.hosting_cost('bar'), 7) self.assertEqual(a.hosting_cost('pouet'), 0)
def test_with_routes(): a = AgentDef("a1", routes={"psycho": 5, "killer": 7}) assert a.name == "a1" assert a.route("psycho") == 5 assert a.route("killer") == 7 assert a.route("ahahah") == 1
def test_with_hosting_cost(): a = AgentDef("a1", hosting_costs={"foo": 5, "bar": 7}) assert a.name == "a1" assert a.hosting_cost("foo") == 5 assert a.hosting_cost("bar") == 7 assert a.hosting_cost("pouet") == 0
def test_api_create_agent_with_default_cost(): a1 = AgentDef('a1', default_route=10, default_hosting_cost=5) assert a1.name == 'a1' # Defaults values for route and hosting costs: assert a1.route('a_foo') == 10 assert a1.hosting_cost('computation_bar') == 5
def test_with_routes(self): a = AgentDef('a1', routes={'psycho': 5, 'killer': 7}) self.assertEqual(a.name, 'a1') self.assertEqual(a.route('psycho'), 5) self.assertEqual(a.route('killer'), 7) self.assertEqual(a.route('ahahah'), 1)
def test_api_create_agent_minimal(): # The name is the only mandatory param when creating an agent definition? a1 = AgentDef('a1') assert a1.name == 'a1' # Defaults values for route and hosting costs: assert a1.route('a_foo') == 1 assert a1.hosting_cost('computation_bar') == 0
def setUp(self): global d1, v1, v2, v3, v4, v5, a1, a2 d1 = VariableDomain('d1', '', [1, 2, 3, 5]) v1 = Variable('v1', d1) v2 = Variable('v2', d1) v3 = Variable('v3', d1) v4 = Variable('v4', d1) v5 = Variable('v5', d1) a1 = AgentDef('a1', capacity=200) a2 = AgentDef('a2', capacity=200)
def test_no_hints(self): d1 = VariableDomain('d1', '', [1, 2, 3, 5]) v1 = Variable('v1', d1) f1 = relation_from_str('f1', 'v1 * 0.5', [v1]) cv1 = VariableComputationNode(v1, ['f1']) cf1 = FactorComputationNode(f1) cg = ComputationsFactorGraph([cv1], [cf1]) agents = [AgentDef('a1', capacity=100), AgentDef('a2', capacity=100)] agent_mapping = distribute(cg, agents, hints=None, computation_memory=lambda x: 10) self.assertTrue(agent_mapping.is_hosted(['v1', 'f1']))
def setUp(self): variables = list( create_variables('v', ['1', '2', '3'], Domain('d', '', [1, 2])).values()) all_diff = constraint_from_str('all_diff', 'v1 + v2 + v3 ', variables) v1, v2, v3 = variables c1 = VariableComputationNode(v1, [all_diff]) c2 = VariableComputationNode(v2, [all_diff]) c3 = VariableComputationNode(v3, [all_diff]) nodes = [c1, c2, c3] # links = [ConstraintLink('all_diff', ['c1', 'c2', 'c3'])] self.cg = ComputationConstraintsHyperGraph(nodes) self.agents = [AgentDef('a1'), AgentDef('a2'), AgentDef('a3')]
def test_with_various_attr(): a = AgentDef("a1", foo=15, bar="bar") assert a.name == "a1" assert a.foo == 15 assert a.bar == "bar"
def run_cmd(args): o_addr, o_port = args.orchestrator.split(':') o_port = int(o_port) a_port = args.port u_port = args.uiport for a in args.names: if u_port: logger.info( 'Starting agent {} on port {} with ui-server on {}'.format( a, a_port, u_port)) else: logger.info( 'Starting agent {} on port {} without ui-server '.format( a, a_port)) comm = HttpCommunicationLayer(('127.0.0.1', a_port)) agt_def = AgentDef(a) agent = OrchestratedAgent(agt_def, comm, (o_addr, o_port), ui_port=u_port) agent.start() a_port += 1 if u_port: u_port += 1
def test_with_various_attr(self): a = AgentDef('a1', foo=15, bar='bar') self.assertEqual(a.name, 'a1') self.assertEqual(a.foo, 15) self.assertEqual(a.bar, 'bar')
def test_rule_with_model(self): hints = DistributionHints(must_host={ 'a1': ['v1'], 'a3': ['v2'] }, host_with={'m1': ['mf1']}) agents = [ AgentDef('a{}'.format(i), capacity=100) for i in range(1, 11) ] agent_mapping = distribute(self.cg, agents, hints, computation_memory=lambda x: 10) # rule should be hosted either with model m1 or variable v2 # print(agent_mapping.agent_for('m1'), agent_mapping.agent_for('mf1'), # agent_mapping.agent_for('v1'), agent_mapping.agent_for('v2'), # agent_mapping.agent_for('r1')) self.assertTrue( agent_mapping.agent_for('r1') == agent_mapping.agent_for('v2') or agent_mapping.agent_for('m1') == agent_mapping.agent_for('r1')) self.assertTrue(is_all_hosted(self.cg, agent_mapping))
def test_host_on_highest_dependent_agent(self): d1 = VariableDomain('d1', '', [1, 2, 3, 5]) v1 = Variable('v1', d1) v2 = Variable('v2', d1) v3 = Variable('v3', d1) f1 = relation_from_str('f1', 'v1 + v2', [v1, v2]) f2 = relation_from_str('f2', 'v1 - v2 + v3', [v1, v2, v3]) cv1 = VariableComputationNode(v1, ['f1', 'f2']) cv2 = VariableComputationNode(v2, ['f1', 'f2']) cv3 = VariableComputationNode(v3, ['f2']) cf1 = FactorComputationNode(f1) cf2 = FactorComputationNode(f2) cg = ComputationsFactorGraph([cv1, cv2, cv3], [cf1, cf2]) hints = DistributionHints(must_host={'a1': ['v1'], 'a2': ['v2', 'v3']}) # we must set the capacity to make sure that a2 cannot take f1 agents = [AgentDef('a{}'.format(i), capacity=41) for i in range(1, 11)] agent_mapping = distribute(cg, agents, hints, computation_memory=lambda x: 10) print(agent_mapping) self.assertEqual(agent_mapping.agent_for('f1'), 'a1') self.assertEqual(agent_mapping.agent_for('f2'), 'a2') self.assertTrue(is_all_hosted(cg, agent_mapping))
def test_must_host_one(self): d1 = VariableDomain('d1', '', [1, 2, 3, 5]) v1 = Variable('v1', d1) f1 = relation_from_str('f1', 'v1 * 0.5', [v1]) cv1 = VariableComputationNode(v1, ['f1']) cf1 = FactorComputationNode(f1) cg = ComputationsFactorGraph([cv1], [cf1]) hints = DistributionHints({'a1': ['v1']}, None) agents = [AgentDef('a1', capacity=100), AgentDef('a2', capacity=100)] agent_mapping = distribute(cg, agents, hints, computation_memory=lambda x: 10) self.assertIn('v1', agent_mapping.computations_hosted('a1')) self.assertTrue(is_all_hosted(cg, agent_mapping))
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()
def generate_ising( row_count: int, col_count: int, bin_range: float, un_range: float, extensive: bool, no_agents: bool, fg_dist: bool, var_dist: bool, ) -> Tuple[DCOP, Dict, Dict]: grid_graph = nx.grid_2d_graph(row_count, col_count, periodic=True) domain = Domain("var_domain", "binary", [0, 1]) variables = generate_binary_variables(grid_graph, domain) constraints = {} unary_constraints = generate_unary_constraints(variables, un_range, extensive) constraints.update(unary_constraints) binary_constraints = generate_binary_constraints( grid_graph, variables, bin_range, extensive ) constraints.update(binary_constraints) agents = {} fg_mapping = defaultdict(lambda: []) var_mapping = defaultdict(lambda: []) for (row, col) in grid_graph.nodes: agent = AgentDef(f"a_{row}_{col}") agents[agent.name] = agent left = (row - 1) % row_count down = (col + 1) % col_count if var_dist: var_mapping[agent.name].append(f"v_{row}_{col}") if fg_dist: fg_mapping[agent.name].append(f"v_{row}_{col}") fg_mapping[agent.name].append(f"cu_v_{row}_{col}") # Sort coordinate to make sure we build the name in the same order as when # creating the constraints: (r1, c1), (r2, c2) = sorted([(row, col), (left, col)]) fg_mapping[agent.name].append(f"cb_v_{r1}_{c1}_v_{r2}_{c2}") (r1, c1), (r2, c2) = sorted([(row, col), (row, down)]) fg_mapping[agent.name].append(f"cb_v_{r1}_{c1}_v_{r2}_{c2}") name = f"Ising_{row_count}_{col_count}_{bin_range}_{un_range}" if no_agents: agents = {} dcop = DCOP( name, domains={"var_domain": domain}, variables={v.name: v for v in variables.values()}, agents=agents, constraints=constraints, ) return dcop, dict(var_mapping), dict(fg_mapping)
def test_simple_fg(self): d1 = VariableDomain('d1', '', [1, 2, 3, 5]) v1 = Variable('v1', d1) f1 = relation_from_str('f1', 'v1 * 0.5', [v1]) cv1 = VariableComputationNode(v1, ['f1']) cf1 = FactorComputationNode(f1) cg = ComputationsFactorGraph([cv1], [cf1]) agents= [AgentDef('a1'), AgentDef('a2')] distribution = distribute(cg, agents) self.assertEqual(len(distribution.agents), 2) self.assertEqual(len(distribution.computations), 2) self.assertEqual(len(distribution.computations_hosted('a1')), 1) self.assertEqual(len(distribution.computations_hosted('a2')), 1) self.assertNotEqual(distribution.computations_hosted('a2'), distribution.computations_hosted('a1'))
def build_agents(lights_vars, lights_costs, capacity=None): agents = {} for light_var, light_cost in zip(lights_vars, lights_costs): hosting_costs = {light_var: 0, light_cost: 0} logger.debug(f"Creating agent for {light_var} with hosting {hosting_costs}") if capacity: agt = AgentDef( "a{}".format(light_var), hosting_costs=hosting_costs, capacity=capacity, default_hosting_cost=100, ) else: agt = AgentDef( "a{}".format(light_var), hosting_costs=hosting_costs, default_hosting_cost=100, ) agents[agt.name] = agt return agents
def test_raise_when_not_enough_agents(self): d1 = VariableDomain('d1', '', [1, 2, 3, 5]) v1 = Variable('v1', d1) f1 = relation_from_str('f1', 'v1 * 0.5', [v1]) cv1 = VariableComputationNode(v1, ['f1']) cf1 = FactorComputationNode(f1) cg = ComputationsFactorGraph([cv1], [cf1]) self.assertRaises(ImpossibleDistributionException, distribute, cg, [AgentDef('a1')])
def start_agents(names: List[str], o_addr, o_port, u_port, a_port): """ Start orchestrated agents. Each agent will run in its own thread, in the same process. They are orchestrated by an orchestrator running in another process (which must be launched separately). Parameters ---------- names: list of strings the names of the agents u_port: int start port for ui a_port: int start port for agents (messages) o_addr orchestrator address o_port orchestrator port Returns ------- agents the list of orchestrated agents started """ started_agents = [] for a in names: if u_port: logger.info( 'Starting agent {} on port {} with ui-server on {}'.format( a, a_port, u_port)) else: logger.info( 'Starting agent {} on port {} without ui-server '.format( a, a_port)) comm = HttpCommunicationLayer(('127.0.0.1', a_port)) agt_def = AgentDef(a) agent = OrchestratedAgent(agt_def, comm, (o_addr, o_port), ui_port=u_port) agent.start() started_agents.append(agent) a_port += 1 if u_port: u_port += 1 logger.info("All %s agents started", len(names)) return started_agents
def test_rule_with_light(self): hints = DistributionHints(must_host={'a1': ['v1'], 'a3': ['v2']}, host_with={'m1': ['mf1']}) agents = [AgentDef('a{}'.format(i), capacity=100) for i in range(1, 11)] agent_mapping = distribute(self.cg, agents, hints, computation_memory=lambda x: 10) # rule r2 only depends on v3, it must be hosted on the same agent self.assertEqual(agent_mapping.agent_for('v3'), agent_mapping.agent_for('r2')) self.assertTrue(is_all_hosted(self.cg, agent_mapping))