Getting Started

Running a negotiation

NegMAS has several built-in negotiation Mechanisms, negotiation agents (Negotiators), and UtilityFunctions. You can use these to run negotiations as follows.

Imagine a buyer and a seller negotiating over the price of a single object. First, we make an issue “price” with 50 discrete values. Note here, it is possible to create multiple issues, but we will not include that here. If you are interested, see the NegMAS documentation for a tutorial.

from negmas import make_issue, SAOMechanism, TimeBasedConcedingNegotiator
from negmas.sao.negotiators import BoulwareTBNegotiator as Boulware
from negmas.sao.negotiators import LinearTBNegotiator as Linear
from negmas.preferences import LinearAdditiveUtilityFunction as UFun
from negmas.preferences.value_fun import IdentityFun, AffineFun
import matplotlib.pyplot as plt


# create negotiation agenda (issues)
issues = [make_issue(name="price", values=50)]

# create the mechanism
mechanism = SAOMechanism(issues=issues, n_steps=20)

The negotiation protocol in NegMAS is handled by a Mechanism object. Here we instantiate aSAOMechanism which implements the Stacked Alternating Offers Protocol. In this protocol, negotiators exchange offers until an offer is accepted by all negotiators (in this case 2), a negotiators leaves the table ending the negotiation or a time-out condition is met. In the example above, we use a limit on the number of rounds of 20 (a step of a mechanism is an executed round).

Next, we define the utilities of the seller and the buyer. The utility function of the seller is defined by the IdentityFun which means that the higher the price, the higher the utility function. The buyer’s utility function is reversed. The last two lines make sure that utility is scaled between 0 and 1.

seller_utility = UFun(values=[IdentityFun()], outcome_space=mechanism.outcome_space)

buyer_utility = UFun(
    values=[AffineFun(slope=-1)], outcome_space=mechanism.outcome_space
)

seller_utility = seller_utility.normalize()
buyer_utility = buyer_utility.normalize()

Then we add two agents with a boulware strategy. The negotiation ends with status overview. For example, you can see if the negotiation timed-out, what agreement was found, and how long the negotiation took. Moreover, we output the full negotiation history. For a more visual representation, we can plot the session. This shows the bidding curve, but also the proximity to e.g. the Nash point.

# create and add agent A and B
mechanism.add(Boulware(name="seller"), ufun=seller_utility)
mechanism.add(Linear(name="buyer"), ufun=buyer_utility)

# run the negotiation and show the results
print(mechanism.run())
SAOState(
    running=False,
    waiting=False,
    started=True,
    step=16,
    time=0.003750874995603226,
    relative_time=0.8095238095238095,
    broken=False,
    timedout=False,
    agreement=(35,),
    results=None,
    n_negotiators=2,
    has_error=False,
    error_details='',
    erred_negotiator='',
    erred_agent='',
    threads={},
    last_thread='',
    current_offer=(35,),
    current_proposer='buyer-953acaf8-4227-4d51-a652-8626f799fa76',
    current_proposer_agent=None,
    n_acceptances=2,
    new_offers=[],
    new_offerer_agents=[None, None],
    last_negotiator='buyer',
    current_data=None,
    new_data=[]
)

In this case, the negotiation ended with an agreement which is indicated by the agreement field of the SAOState.

We can see a trace of the negotiation giving the step number, agent-id and its offer using the extended_trace property of the mechanism (session):

# negotiation history
print(mechanism.extended_trace)
[
    (0, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (49,)),
    (0, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (2,)),
    (1, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (49,)),
    (1, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (4,)),
    (2, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (49,)),
    (2, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (7,)),
    (3, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (49,)),
    (3, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (9,)),
    (4, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (49,)),
    (4, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (11,)),
    (5, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (49,)),
    (5, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (14,)),
    (6, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (49,)),
    (6, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (16,)),
    (7, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (48,)),
    (7, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (18,)),
    (8, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (48,)),
    (8, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (21,)),
    (9, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (47,)),
    (9, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (23,)),
    (10, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (46,)),
    (10, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (25,)),
    (11, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (44,)),
    (11, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (28,)),
    (12, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (42,)),
    (12, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (30,)),
    (13, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (40,)),
    (13, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (32,)),
    (14, 'seller-e3614ef9-6d24-442a-9332-b15342ffa1e4', (37,)),
    (14, 'buyer-953acaf8-4227-4d51-a652-8626f799fa76', (35,))
]

We can also plot the negotiation.

mechanism.plot(mark_max_welfare_points=False)
plt.show()
_images/getting_started_9_0.png

The most commonly used method for visualizing a negotiation is to plot the utility of one negotiator on the x-axis and the utility of the other in the y-axis, offers of different negotiators are then displayed in different colors. The agreement is marked by a black star and important points like the Nash Bargaining Solution, Kalai/Egaliterian Bargaining Solution, Kalai-Smorodonisky Bargaining Solution and points with maximum welfare. This kind of figure is shown in the left-hand side of the previous graph and can be produced by calling plot() on the mechanism. Because our single-issue negotiation is a zero-sum game, all points have the same welfare of 1.0 and lie on a straight line.

Another type of graph represents time (i.e. relative-time ranging from 0 to 1, real time, or step number) on the x-axis and represents the utility of one negotiator’s offer for itself with a bold color on the y-axis. The utility of the offers from this negotiators for all other negotiators are also shown using a lighter line with no marks. This kind of representation is useful in understanding clearly the change of each negotiator’s behavior over time (in terms of its own and its partners’ utilities). In the previous graph, we can clearly see the difference between the seller’s (upper right) and buyer’s (lower right) offering strategies.

The plot function is very customizable and you can learn about all its parameters here