def test_value_all_neighbors_received(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable('x2', list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            return x1_ + x2_

        computation = Mgm2Computation(x1, [phi],
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())
        computation._state = 'value'
        computation.__value__ = 1
        computation._handle_value_message('x2', Mgm2ValueMessage(0))

        self.assertEqual(computation._state, 'offer')
        self.assertEqual(computation._neighbors_values['x2'], 0)
        self.assertEqual(computation._potential_gain, 1)
        self.assertEqual(computation._potential_value, 0)

        computation2 = Mgm2Computation(x1, [phi],
                                       mode='max',
                                       msg_sender=DummySender(),
                                       comp_def=MagicMock())
        computation2._state = 'value'
        computation2.__value__ = 1
        computation2._handle_value_message('x2', Mgm2ValueMessage(0))
        self.assertEqual(computation2._state, 'offer')
        self.assertEqual(computation2._neighbors_values['x2'], 0)
        self.assertEqual(computation2._potential_gain, 0)
        self.assertEqual(computation2._potential_value, 1)
    def test_offer_already_has_partner(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        # Receives a fake offer
        computation = Mgm2Computation(x1, [phi], comp_def=MagicMock())
        computation._state = 'offer'
        computation._is_offerer = True
        computation._handle_offer_msg('x2', Mgm2OfferMessage())
        self.assertEqual(computation._state, 'offer')
        self.assertEqual(computation._offers, [])
        # Received only fake offers
        computation2 = Mgm2Computation(x1, [phi],
                                       msg_sender=DummySender(),
                                       comp_def=MagicMock())
        computation2._state = 'offer'
        computation2.__nb_received_offers__ = 1
        computation2._handle_offer_msg('x2', Mgm2OfferMessage())
        self.assertEqual(computation2._state, 'gain')
        self.assertEqual(computation2._offers, [])
        # receives a real offer
        computation3 = Mgm2Computation(x1, [phi],
                                       msg_sender=DummySender(),
                                       comp_def=MagicMock())
        computation3._state = 'offer'
        computation3._is_offerer = True
        computation3.__cost__ = 15
        computation3._handle_offer_msg(
            'x2', Mgm2OfferMessage({(1, 1): 8}, is_offering=True))
        self.assertEqual(computation3._state, 'offer')
        self.assertEqual(computation3._offers, [])
        self.assertEqual(computation3._potential_gain, 0)
        self.assertIsNone(computation3._potential_value)
        # Receives a real offer which is the last expected one
        computation4 = Mgm2Computation(x1, [phi],
                                       msg_sender=DummySender(),
                                       comp_def=MagicMock())
        computation4._state = 'offer'
        computation4._is_offerer = True
        computation4.__nb_received_offers__ = 1
        computation4._handle_offer_msg(
            'x2', Mgm2OfferMessage({(1, 1): 8}, is_offering=True))
        self.assertEqual(computation4._offers, [])
        self.assertEqual(computation4._state, 'answer?')
        self.assertEqual(computation4._potential_gain, 0)
        self.assertIsNone(computation4._potential_value)
    def test_response_accept(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(x1, [phi, psi],
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())
        computation._state = 'answer?'
        computation._is_offerer = True
        computation._neighbors_values = {'x2': 1, 'x3': 1}
        computation.__value__ = 1
        computation.__cost__ = 9
        computation._potential_gain = 9  # best unilateral move
        computation._potential_value = 2  # best unilateral move
        computation._partner = x3

        computation._handle_response_msg(
            'x3', Mgm2ResponseMessage(True, value=0, gain=10))

        self.assertEqual(computation._state, 'gain')
        self.assertEqual(computation._potential_gain, 10)
        self.assertEqual(computation._potential_value, 0)
    def test_go_reject_no_postponed_value_message(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(x1, [phi, psi],
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())
        computation._neighbors_values = {'x2': 1, 'x3': 1}
        computation.__value__ = 1
        computation._potential_value = 0
        computation._state = 'go?'
        # from Response message or accepted offer

        computation._handle_go_message('x3', Mgm2GoMessage(False))

        self.assertEqual(computation._state, 'value')
        self.assertEqual(computation.__value__, 1)
        self.test_clear_agent()
    def test_gain_not_all_received(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi, psi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()

        computation._state = "gain"
        computation.on_gain_msg("x2", Mgm2GainMessage(5), 1)

        self.assertEqual(computation._neighbors_gains, {"x2": 5})
    def test_offer_has_better_unilateral_move(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        # Receives a real offer from last neighbor
        computation = Mgm2Computation(x1, [phi, psi],
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())
        computation._state = 'offer'
        computation._neighbors_values = {'x2': 1, 'x3': 1}
        computation.__value__ = 1
        computation.__cost__ = 9
        computation._potential_gain = 9  # best unilateral move
        computation._potential_value = 0  # best unilateral move
        computation.__nb_received_offers__ = 1
        computation._handle_offer_msg(
            'x2', Mgm2OfferMessage({(0, 1): 1}, is_offering=True))
        self.assertEqual(computation._offers, [('x2', {(0, 1): 1})])
        self.assertEqual(computation._state, 'gain')
        self.assertEqual(computation._potential_gain, 9)
        self.assertEqual(computation._potential_value, 0)
    def test_go_reject_no_postponed_value_message(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi, psi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()

        computation._neighbors_values = {"x2": 1, "x3": 1}
        computation.__value__ = 1
        computation._potential_value = 0
        computation._state = "go?"
        # from Response message or accepted offer

        computation._handle_go_message("x3", Mgm2GoMessage(False))

        self.assertEqual(computation._state, "value")
        self.assertEqual(computation.__value__, 1)
        self.test_clear_agent()
    def test_enter_offer_state(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2", mode="max"),
            ))
        computation.message_sender = DummySender()

        computation._postponed_msg["offer"] = [
            ("x2", Mgm2OfferMessage({(1, 1): 5}, is_offering=True), 1)
        ]

        computation._enter_state("offer")

        self.assertEqual(computation._state, "offer")
        self.assertEqual(computation._postponed_msg["offer"], [])
        self.assertEqual(computation._offers,
                         [("x2", Mgm2OfferMessage({(1, 1): 5}, True))])
    def test_offer_has_no_partner_yet(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        # Receives a fake offer
        computation = Mgm2Computation(x1, [phi], comp_def=MagicMock())
        computation._state = 'offer'
        computation._handle_offer_msg('x2', Mgm2OfferMessage())
        self.assertEqual(computation._state, 'offer')
        self.assertEqual(computation._offers, [])
        # Received only fake offers
        computation2 = Mgm2Computation(x1, [phi],
                                       msg_sender=DummySender(),
                                       comp_def=MagicMock())
        computation2._state = 'offer'
        computation2.__nb_received_offers__ = 1
        computation2._handle_offer_msg('x2', Mgm2OfferMessage())
        self.assertEqual(computation2._state, 'gain')
        self.assertEqual(computation2._offers, [])
        # Receives a real offer (but still expects other OfferMessages)
        computation3 = Mgm2Computation(x1, [phi], comp_def=MagicMock())
        computation3._state = 'offer'
        computation3._handle_offer_msg(
            'x2', Mgm2OfferMessage({(1, 1): 8}, is_offering=True))
        self.assertEqual(computation3._state, 'offer')
        self.assertEqual(computation3._offers, [('x2', {(1, 1): 8})])
        # Receives a real offer and is the last expected OfferMessage
        computation4 = Mgm2Computation(x1, [phi],
                                       msg_sender=DummySender(),
                                       comp_def=MagicMock())
        computation4._state = 'offer'
        computation4._neighbors_values = {'x2': 0, 'x3': 1}
        computation4.__value__ = 0
        computation4.__cost__ = 1
        computation4.__nb_received_offers__ = 1
        computation4._handle_offer_msg(
            'x2', Mgm2OfferMessage({(1, 1): 8}, is_offering=True))
        self.assertEqual(computation4._offers, [('x2', {(1, 1): 8})])
        self.assertEqual(computation4._state, 'gain')
        self.assertEqual(computation4._potential_gain, 9)
        self.assertEqual(computation4._potential_value, 1)
    def test_go_accept_with_postponed_value_message(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi, psi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()

        computation._neighbors_values = {"x2": 1, "x3": 1}
        computation.__value__ = 1
        computation.__cost__ = 9
        computation._state = "go?"
        computation._postponed_msg["value"] = [("x2", Mgm2ValueMessage(1), 1)]
        # from Response message or accepted offer
        computation._potential_gain = 10
        computation._potential_value = 0

        computation.on_go_msg("x3", Mgm2GoMessage(True), 1)
        # Common tests
        self.assertEqual(computation._state, "value")
        self.assertEqual(computation._potential_gain, 0)
        self.assertIsNone(computation._potential_value)
        self.assertEqual(computation._neighbors_values, {"x2": 1})
        self.assertEqual(computation._neighbors_gains, dict())
        self.assertEqual(computation._offers, [])
        self.assertIsNone(computation._partner)
        self.assertEqual(computation.__nb_received_offers__, 0)
        self.assertFalse(computation._committed)
        self.assertFalse(computation._is_offerer)
        self.assertFalse(computation._can_move)

        # If cannot move
        self.assertEqual(computation.current_value, 1)
        # If can move
        computation._can_move = True
        computation._state = "go?"
        computation._potential_value = 0
        computation.on_go_msg("x3", Mgm2GoMessage(True), 1)
        self.assertEqual(computation.current_value, 0)
    def test_clear_agent(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi, psi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()

        computation._neighbors_values = {"x2": 1, "x3": 1}
        computation.__value__ = 1
        computation.__nb_received_offers__ = 2
        computation._partner = x3
        computation._state = "go?"
        computation._potential_gain = 10
        computation._potential_value = 10
        computation._neighbors_values = {"x2": 1, "x3": 0}
        computation._neighbors_gains = {"x2": 5, "x3": 1}
        computation._offers = [(1, 1, "x2")]
        computation._committed = True
        computation._is_offerer = True
        computation._can_move = True

        computation._clear_agent()

        self.assertEqual(computation._potential_gain, 0)
        self.assertEqual(computation._neighbors_values, dict())
        self.assertEqual(computation._neighbors_gains, dict())
        self.assertEqual(computation._offers, [])
        self.assertIsNone(computation._partner)
        self.assertEqual(computation.__nb_received_offers__, 0)
        self.assertFalse(computation._committed)
        self.assertFalse(computation._is_offerer)
        self.assertFalse(computation._can_move)
        self.assertIsNone(computation._potential_value)
        self.assertIsNotNone(computation.current_value)
    def test_go_accept_with_postponed_value_message(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(x1, [phi, psi],
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())
        computation._neighbors_values = {'x2': 1, 'x3': 1}
        computation.__value__ = 1
        computation.__cost__ = 9
        computation._state = 'go?'
        computation._postponed_msg['value'] = [('x2', Mgm2ValueMessage(1))]
        # from Response message or accepted offer
        computation._potential_gain = 10
        computation._potential_value = 0

        computation._handle_go_message('x3', Mgm2GoMessage(True))
        # Common tests
        self.assertEqual(computation._state, 'value')
        self.assertEqual(computation._potential_gain, 0)
        self.assertIsNone(computation._potential_value)
        self.assertEqual(computation._neighbors_values, {'x2': 1})
        self.assertEqual(computation._neighbors_gains, dict())
        self.assertEqual(computation._offers, [])
        self.assertIsNone(computation._partner)
        self.assertEqual(computation.__nb_received_offers__, 0)
        self.assertFalse(computation._committed)
        self.assertFalse(computation._is_offerer)
        self.assertFalse(computation._can_move)

        #If cannot move
        self.assertEqual(computation.current_value, 1)
        #If can move
        computation._can_move = True
        computation._state = 'go?'
        computation._potential_value = 0
        computation._handle_go_message('x3', Mgm2GoMessage(True))
        self.assertEqual(computation.current_value, 0)
    def test_value_all_neighbors_received(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable("x2", list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            return x1_ + x2_

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()
        computation._state = "value"
        computation.__value__ = 1
        computation.on_value_msg("x2", Mgm2ValueMessage(0), 1)

        self.assertEqual(computation._state, "offer")
        self.assertEqual(computation._neighbors_values["x2"], 0)
        self.assertEqual(computation._potential_gain, 1)
        self.assertEqual(computation._potential_value, 0)

        computation2 = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2", mode="max"),
            ))
        computation2.message_sender = DummySender()
        computation2._state = "value"
        computation2.__value__ = 1
        computation2.on_value_msg("x2", Mgm2ValueMessage(0), 1)
        self.assertEqual(computation2._state, "offer")
        self.assertEqual(computation2._neighbors_values["x2"], 0)
        self.assertEqual(computation2._potential_gain, 0)
        self.assertEqual(computation2._potential_value, 1)
    def test_clear_agent(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(x1, [phi, psi],
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())
        computation._neighbors_values = {'x2': 1, 'x3': 1}
        computation.__value__ = 1
        computation.__nb_received_offers__ = 2
        computation._partner = x3
        computation._state = 'go?'
        computation._potential_gain = 10
        computation._potential_value = 10
        computation._neighbors_values = {'x2': 1, 'x3': 0}
        computation._neighbors_gains = {'x2': 5, 'x3': 1}
        computation._offers = [(1, 1, 'x2')]
        computation._committed = True
        computation._is_offerer = True
        computation._can_move = True

        computation._clear_agent()

        self.assertEqual(computation._potential_gain, 0)
        self.assertEqual(computation._neighbors_values, dict())
        self.assertEqual(computation._neighbors_gains, dict())
        self.assertEqual(computation._offers, [])
        self.assertIsNone(computation._partner)
        self.assertEqual(computation.__nb_received_offers__, 0)
        self.assertFalse(computation._committed)
        self.assertFalse(computation._is_offerer)
        self.assertFalse(computation._can_move)
        self.assertIsNone(computation._potential_value)
        self.assertIsNotNone(computation.current_value)
    def test_enter_offer_state(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        computation = Mgm2Computation(x1, [phi],
                                      mode='max',
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())

        computation._enter_state('go?')

        self.assertEqual(computation._state, 'go?')
    def test_enter_go_state(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2", mode="max"),
            ))
        computation.message_sender = DummySender()

        computation._enter_state("go?")

        self.assertEqual(computation._state, "go?")
    def test_go_accept_no_postponed_value_message(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi, psi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()
        computation._neighbors_values = {"x2": 1, "x3": 1}
        computation.__value__ = 1
        computation.__cost__ = 9
        computation._state = "go?"
        # from Response message or accepted offer
        computation._potential_gain = 10
        computation._potential_value = 0
        # Common behavior: clear agent view
        computation.on_go_msg("x3", Mgm2GoMessage(True), 1)
        self.assertEqual(computation._state, "value")
        self.test_clear_agent()

        # If cannot move
        self.assertEqual(computation.current_value, 1)
        # If can move
        computation._state = "go?"
        computation._can_move = True
        computation._potential_value = 0
        computation.on_go_msg("x3", Mgm2GoMessage(True), 1)
        self.assertEqual(computation.current_value, 0)
    def test_enter_gain_state(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        computation = Mgm2Computation(x1, [phi],
                                      mode='max',
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())

        computation._postponed_msg['gain'] = [('x2', Mgm2GainMessage(3))]

        computation._enter_state('gain')

        self.assertEqual(computation._state, 'gain')
        self.assertEqual(computation._postponed_msg['gain'], [])
        self.assertEqual(computation._neighbors_gains['x2'], 3)
    def test_go_accept_no_postponed_value_message(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(x1, [phi, psi],
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())
        computation._neighbors_values = {'x2': 1, 'x3': 1}
        computation.__value__ = 1
        computation.__cost__ = 9
        computation._state = 'go?'
        # from Response message or accepted offer
        computation._potential_gain = 10
        computation._potential_value = 0
        # Common behavior: clear agent view
        computation._handle_go_message('x3', Mgm2GoMessage(True))
        self.assertEqual(computation._state, 'value')
        self.test_clear_agent()

        # If cannot move
        self.assertEqual(computation.current_value, 1)
        # If can move
        computation._state = 'go?'
        computation._can_move = True
        computation._potential_value = 0
        computation._handle_go_message('x3', Mgm2GoMessage(True))
        self.assertEqual(computation.current_value, 0)
    def test_enter_offer_state(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        computation = Mgm2Computation(x1, [phi],
                                      mode='max',
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())

        computation._postponed_msg['offer'] = \
            [('x2', Mgm2OfferMessage({(1, 1): 5}, is_offering=True))]

        computation._enter_state('offer')

        self.assertEqual(computation._state, 'offer')
        self.assertEqual(computation._postponed_msg['offer'], [])
        self.assertEqual(computation._offers, [('x2', {(1, 1): 5})])
    def test_response_accept(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi, psi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()
        computation._state = "answer?"
        computation._is_offerer = True
        computation._neighbors_values = {"x2": 1, "x3": 1}
        computation.__value__ = 1
        computation.__cost__ = 9
        computation._potential_gain = 9  # best unilateral move
        computation._potential_value = 2  # best unilateral move
        computation._partner = x3

        computation.on_answer_msg("x3",
                                  Mgm2ResponseMessage(True, value=0, gain=10),
                                  1)

        self.assertEqual(computation._state, "gain")
        self.assertEqual(computation._potential_gain, 10)
        self.assertEqual(computation._potential_value, 0)
    def test_enter_gain_state(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2", mode="max"),
            ))
        computation.message_sender = DummySender()

        computation._postponed_msg["gain"] = [("x2", Mgm2GainMessage(3), 1)]

        computation._enter_state("gain")

        self.assertEqual(computation._state, "gain")
        self.assertEqual(computation._postponed_msg["gain"], [])
        self.assertEqual(computation._neighbors_gains["x2"], 3)
    def test_gain_not_all_received(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(x1, [phi, psi],
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())
        computation._state = 'gain'
        computation._handle_gain_message('x2', Mgm2GainMessage(5))

        self.assertEqual(computation._neighbors_gains, {'x2': 5})
    def test_offer_already_has_partner(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        # Receives a fake offer
        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()
        computation._state = "offer"
        computation._is_offerer = True
        computation.on_offer_msg("x2", Mgm2OfferMessage(), 1)
        self.assertEqual(computation._state, "offer")
        # self.assertEqual(computation._offers, [])
        # Received only fake offers
        computation2 = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation2.message_sender = DummySender()
        computation2._state = "offer"
        computation2.__nb_received_offers__ = 1
        computation2.on_offer_msg("x2", Mgm2OfferMessage(), 1)
        self.assertEqual(computation2._state, "gain")
        self.assertEqual(computation2._offers, [("x2", Mgm2OfferMessage())])
        # receives a real offer
        computation3 = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation3.message_sender = DummySender()
        computation3._state = "offer"
        computation3._is_offerer = True
        computation3.__cost__ = 15
        computation3.on_offer_msg(
            "x2", Mgm2OfferMessage({(1, 1): 8}, is_offering=True), 1)
        self.assertEqual(computation3._state, "offer")
        self.assertEqual(2, len(computation3._offers))
        self.assertEqual(computation3._potential_gain, 0)
        self.assertIsNone(computation3._potential_value)
        # Receives a real offer which is the last expected one
        computation4 = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation4.message_sender = DummySender()
        computation4._state = "offer"
        computation4._is_offerer = True
        computation4.__nb_received_offers__ = 1
        computation4.on_offer_msg(
            "x2", Mgm2OfferMessage({(1, 1): 8}, is_offering=True), 1)
        self.assertEqual(len(computation4), 3)
        self.assertEqual(computation4._state, "answer?")
        self.assertEqual(computation4._potential_gain, 0)
        self.assertIsNone(computation4._potential_value)
    def test_offer_has_no_partner_yet(self):
        x1 = Variable("x1", list(range(2)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2, x3)
        def phi(x1_, x2_, x3_):
            return x1_ + x2_ + x3_

        # Receives a fake offer
        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()
        computation._state = "offer"
        computation.on_offer_msg("x2", Mgm2OfferMessage(), 1)
        self.assertEqual(computation._state, "offer")
        self.assertEqual(computation._offers, [])
        # Received only fake offers
        computation2 = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation2.message_sender = DummySender()
        computation2._state = "offer"
        computation2.__nb_received_offers__ = 1
        computation2.on_offer_msg("x2", Mgm2OfferMessage(), 1)
        self.assertEqual(computation2._state, "gain")
        self.assertEqual(computation2._offers, [])

        # Receives a real offer (but still expects other OfferMessages)
        computation3 = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation3.message_sender = DummySender()
        computation3._state = "offer"
        computation3.on_offer_msg(
            "x2", Mgm2OfferMessage({(1, 1): 8}, is_offering=True), 1)
        self.assertEqual(computation3._state, "offer")
        self.assertEqual(computation3._offers, [("x2", {(1, 1): 8})])
        # Receives a real offer and is the last expected OfferMessage
        computation4 = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation4.message_sender = DummySender()
        computation4._state = "offer"
        computation4._neighbors_values = {"x2": 0, "x3": 1}
        computation4.__value__ = 0
        computation4.__cost__ = 1
        computation4.__nb_received_offers__ = 1
        computation4.on_offer_msg(
            "x2", Mgm2OfferMessage({(1, 1): 8}, is_offering=True), 1)
        self.assertEqual(computation4._offers, [("x2", {(1, 1): 8})])
        self.assertEqual(computation4._state, "gain")
        self.assertEqual(computation4._potential_gain, 9)
        self.assertEqual(computation4._potential_value, 1)
    def test_gain_all_received(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable('x2', list(range(2)))
        x3 = Variable('x3', list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(x1, [phi, psi],
                                      msg_sender=DummySender(),
                                      comp_def=MagicMock())
        computation._neighbors_values = {'x2': 1, 'x3': 0}

        # If potential gain is 0
        computation.__value__ = 1
        computation.__cost__ = 1
        computation._potential_value = 0
        computation._potential_gain = 0
        computation._state = 'go?'
        computation._neighbors_gains['x3'] = 2
        computation._handle_gain_message('x2', Mgm2GainMessage(5))
        self.assertEqual(computation.current_value, 1)
        self.assertEqual(computation._state, 'value')
        self.assertEqual(computation.current_cost, 1)
        # If commited and has best gain
        computation._state = 'go?'
        computation.__value__ = 1
        computation.__cost__ = 1
        computation._committed = True
        computation._partner = x3
        computation._potential_gain = 10
        computation._neighbors_gains['x3'] = 10
        computation._potential_value = 0
        computation._handle_gain_message('x2', Mgm2GainMessage(5))
        self.assertEqual(computation.current_value, 1)
        self.assertEqual(computation.current_cost, 1)
        self.assertTrue(computation._can_move)
        self.assertEqual(computation._state, 'go?')
        # If commited and has not best gain
        computation._state = 'go?'
        computation.__value__ = 1
        computation.__cost__ = 1
        computation._committed = True
        computation._partner = x3
        computation._potential_gain = 1
        computation._neighbors_gains['x3'] = 1
        computation._potential_value = 0
        computation._handle_gain_message('x2', Mgm2GainMessage(5))
        self.assertEqual(computation.current_value, 1)
        self.assertEqual(computation.current_cost, 1)
        self.assertFalse(computation._can_move)
        self.assertEqual(computation._state, 'go?')
        self.test_clear_agent()

        # If not committed and has best gain not alone: no test as it could (in
        # the future) be randomly chosen

        #If not committed and not best gain
        computation._state = 'go?'
        computation.__value__ = 1
        computation.__cost__ = 1
        computation._committed = False
        computation._partner = None
        computation._potential_gain = 2
        computation._neighbors_gains['x3'] = 2
        computation._potential_value = 0
        computation._handle_gain_message('x2', Mgm2GainMessage(5))
        self.assertEqual(computation.current_value, 1)
        self.assertEqual(computation.current_cost, 1)
        self.assertEqual(computation._state, 'value')
        self.test_clear_agent()
    def test_gain_all_received(self):
        x1 = Variable("x1", list(range(3)))
        x2 = Variable("x2", list(range(2)))
        x3 = Variable("x3", list(range(2)))

        @AsNAryFunctionRelation(x1, x2)
        def phi(x1_, x2_):
            if x1_ == x2_:
                return 1
            return 0

        @AsNAryFunctionRelation(x1, x3)
        def psi(x1_, x3_):
            if x1_ == x3_:
                return 8
            return 0

        computation = Mgm2Computation(
            ComputationDef(
                VariableComputationNode(x1, [phi, psi]),
                AlgorithmDef.build_with_default_param("mgm2"),
            ))
        computation.message_sender = DummySender()

        computation._neighbors_values = {"x2": 1, "x3": 0}

        # If potential gain is 0
        computation.__value__ = 1
        computation.__cost__ = 1
        computation._potential_value = 0
        computation._potential_gain = 0
        computation._state = "gain"
        computation._neighbors_gains["x3"] = 2
        computation.on_gain_msg("x2", Mgm2GainMessage(5), 1)
        self.assertEqual(computation.current_value, 1)
        self.assertEqual(computation._state, "value")
        self.assertEqual(computation.current_cost, 1)
        # If commited and has best gain
        computation._state = "gain"
        computation.__value__ = 1
        computation.__cost__ = 1
        computation._committed = True
        computation._partner = x3
        computation._potential_gain = 10
        computation._neighbors_gains["x3"] = 10
        computation._potential_value = 0
        computation.on_gain_msg("x2", Mgm2GainMessage(5), 1)
        self.assertEqual(computation.current_value, 1)
        self.assertEqual(computation.current_cost, 1)
        self.assertTrue(computation._can_move)
        self.assertEqual(computation._state, "go?")
        # If commited and has not best gain
        computation._state = "gain"
        computation.__value__ = 1
        computation.__cost__ = 1
        computation._committed = True
        computation._partner = x3
        computation._potential_gain = 1
        computation._neighbors_gains["x3"] = 1
        computation._potential_value = 0
        computation.on_gain_msg("x2", Mgm2GainMessage(5), 1)
        self.assertEqual(computation.current_value, 1)
        self.assertEqual(computation.current_cost, 1)
        self.assertFalse(computation._can_move)
        self.assertEqual(computation._state, "go?")
        self.test_clear_agent()

        # If not committed and has best gain not alone: no test as it could (in
        # the future) be randomly chosen

        # If not committed and not best gain
        computation._state = "gain"
        computation.__value__ = 1
        computation.__cost__ = 1
        computation._committed = False
        computation._partner = None
        computation._potential_gain = 2
        computation._neighbors_gains["x3"] = 2
        computation._potential_value = 0
        computation.on_gain_msg("x2", Mgm2GainMessage(5), 1)
        self.assertEqual(computation.current_value, 1)
        self.assertEqual(computation.current_cost, 1)
        self.assertEqual(computation._state, "value")
        self.test_clear_agent()