0.8->0.9 Upgrade Guide

NegMAS 0.9 is not backward compatible with NegMAS 0.8 and to use it you will need to make some modifications to your code. This guide aims at helping you achieve this with minimal hassle.

Summary

Must Do

from

to

Notes

Issue(…)

make_issue(…)

The same paramters are accepted

outcome_as_dict(x, …)

outcome2dict(x, …, issues=issue)

Must pass the issues

outcome_as_tuple(x, …)

x

Just remove the call (all outcomes are tuples)

negmas.java

negmas.serialization

to_java

to_dict

Java interfaces (through jnemgas) are not supported anymore.

from_genius/to_genius

Remove keep_issue_names, keep_issue_values (not supported anymore)

Negotiator.on_ufun_changed

Negotiator.on_preferences_changed

Negotiator._utility_function

Negotiator.ufun

SAOAMI

SAONMI

PassThroughNegotiator

ControlledNegotiator

PassThroughSAONegotiator

ControlledNegotiator

from negmas.*.passthrough

from negmas.*.controlled

where * here stands for any submodule

The following rules must be followed:

  • Never change the internal structure of a utility function after it is constructed (i.e. do not change the weights on a LinearUtilityFunction ) because the negotiator will have no way to know about this change. To help enforcing that, almost all members of all ufuns are now private (i.e. starting with an _ ) and only getter properties for them are provided. Some members like outcome_spaace , issues are still just data members but you should never set them after the ufun is constructed (in the pythonic should also spirit of “we are all consenting adults here”).

  • In general, you should never need to access a private member of any class (i.e. a member starting with _ ). If you do need that, it is a bug. Please raise an issue in github.

  • Do not pass outcome_type to any ufun constructor. It is now removed as all outcomes are guarenteed to have the type tuple now.

  • Some I/O methods (and few others) had force_single_issue, keep_issue_names and keep_issue_values paramters to do on-the-fly type conversions and change the type of the outcomes. All of this is removed now. Conversion of issue spaces can be done explicitly using methods in the OutcomeSpace protocol like to_single and to_numeric.

Should Do

from

to

Notes

import negmas.utilities

import negmas.preferences

If not done, a deprication warning will be issued.

load_genius_domain_from_folder

Scenario.from_genius_folder

Some of the parameters are no longer supported. Check your use-case

LinearUtilityAggregationFunction

LinearAdditiveUtilityFunction

The old class name is still provided.

Negotiator.ami

Negotiator.nmi

Member of all Negotiator objects

Controller.get_ami

Controller.get_nmi

AgentMechanismInterface

NegotiatorMechanismInterface

The class was renamed to better reflect its role. The old name still works but is depricated

LinearUtilityFunction(bias!=0)

AffineUtilityFunction

We are reserving the name LinearUtilityFunction to ufuns with zero offset and AffineUtilityFunction for those with potentially nonzero offset

The following rules should be followed:

  • It is better to always tell the ufun its outcome-space by passing outcome_space , issues , or outcomes to it. Strictly speaking you do not need to do that for many scenarios (specially for affine and linear utility functions) but some operations may fail if the ufun does not know its outcome-space. For example, if you construct a utility function without passing an outcome space to it, you will get an execption if you try to call extreme_outcomes() or minmax() on it later as the ufun has no way to know how to evaluate either. Because some builtin negotiators (e.g. TimeBasedNegotiator ) do use these methods internally, you will get these exceptions at the time of calling said methods which may be tricky to debug.

Outcome Type

In NegMAS 0.8, you were able to use dicts, lists, tuples, or OutcomeType objects as outcomes. For examle if we have two issues (price and quantity), you coud represent an outcome as any of the following:

w = (0, 1)
w = dict(price=0, quantity=1)
w = O(price=0, quantity=1)

whare O is a dataclass inherited from OutcomeType.

All of this is gone in NegMAS 0.9 to simplify the code base (by removing hundreds of isinstance calls). Now all outcomes are tuples. In the above examples only the first one is supported.

This actually simplify your code as you do not need to check the type of the outcome you are receiving in any callbacks (e.g. the respond() method of the SAONegotiator class).

As a side effect, some functions have been removed or renamed.

Caution

Note that Contract in the situated module still stores the agreement as a dictionary as it is usually easier to understand from logs.

Multiple Issue Types

In NegMAS 0.8 we had a single Issue class representing all types of issues. This led to several complications as each method of this class had to check for the exact type of itself (i.e. is it an ordinal issue, a continuous issue, …). To make the codebase more maintainable, Issue is now an abstract base class that is inherited by specific issue types (e.g. OrdinalIssue, ContinuousIssue , etc). We also provide a factory function make_issue that takes the same parameters as the constructor of NegMAS 0.8’s Issue class and create the appropriate type.

To upgrade to the new version with minimum effort, replace all calls to Issue with make_issue. For example:

issue = Issue(...)

becomes:

issue = make_issue(...)

Outcome Space Class

In NegMAS 0.8, outcome spaces were represented with lists of Issue s. You can still do that in NegMAS 0.9 but it is recommended to use the newly added OutcomeSpace hierarchy of classes for that. This allows you to use convenient functions defined on these classes to manipulate outcome-spaces which can be specially helpful for mechanism designers.

You do not need to change your code in any way to be compatible with this feature but it is recommended that you start using outcome-spaces instead of lists of issues. We provide a convenient make_os factory function for constructing outcome spaces from lists of issues, or lists of outcomes.

All mechnisms now receive their outcome-space either as an oucome_space, a list of Issue objects, or a list of Outcome objects.

Preferences Module Restructuring

In NegMAS 0.8, we had a single UtilityFunction class that represented all sorts of interfaces. For example if you implemented the eval() method it acted like a normal utility function that can be called to return the utility of an outcome. If you implemented instead the is_better() method the same class acted like a representation of ordinal preferences (with no utility value per outcome being defined). Needless to say, desipte its ease of use, several edge cases were difficult to handle and again we had to resort to runtime type checking too much. Moreover, it is difficult to follow the code of our implementation. All of this was implemented in a single-file Utilities module with thousands of lines.

In NegMAS 0.9, the Utilities module was renamed preferences and we replaced the monolithic UtiltiyFunction class with multiple classes implementing different types of preferences. You can check the new hierarchy in the preferences.protocols and preferences.ufun modules. Now UtilityFunction is reserved for crisp utility functions that define a real value for each outcome.

If you are using `UtilityFunction` in that sense (which is likely), you do not need to change anything in your code except importing from `preferences` instead of `utiltiies`.

Input and Output

We added a new class Scenario to represent a negotiation scenario (i.e. agneda and ufuns). It is the recommended way to load/save negotiation scenarios now. It can be used to load/save Genius XML scenarios as well as json versions.

Moreover, we removed some of the parameters in load_genius_domain_from_* functions (keep_issue_names, keep_value_names, …) that are not needed anymroe now that outcomes are always tuples.

Once you create a Scenario using something like from_genius_folder , you can now do several operations on it like converting it to a single-issue negotiation using to_single_issue() or to an all-numeric negotiation using to_numeric() . Whenever you do something like this the ufuns will be changed appropriately.

Java Support

Developing agents and negotiators in Java is no longer supported. This means that jnegmas is no longer needed or used.

Other Changes

NegMAS 0.9 has other changing that can be potentially breaking but are justified by the more consistency they bring and/or their performance edge. Most of these changes have no effect on well-behaving code using the library:

  • We renamed PassThroughNegotiator types to ControlledNegotiator types to better document their roles. These negotiators allow for user-controlled separation of responsibilities between the Controller and the Negotiator . The old name suggested that the negotiator cannot do anything (just a pass-through entity).

  • In most cases, we use the more general term preferences instead of ufun whenever possible. For example, on_ufun_changed was renamed to on_preferences_changed to make it clear that general preferences can be used not only ufuns.

  • Some methods now receive both preferences and ufun aruments (instead of only ufun ) with the ufun argument overriding the preferences argument when given. This was done (instead of just renaming the ufun argument to preferences ) to reduce the effect on downstream code.

  • The negotiator is not notified that its preferences have changed (through a call to its on_preferences_changed() method) only when it is about to start a negotiation even if the assignment of preferences was done in construction (by passing preferences to the constructor) or by set_preferences() before joining. This has two advantages:

    1. The later call makes it more likely that all data needed for the negotiator for using this callback is available. For example, if the negotiator is created by an agent to be used with multiple negotiations, it may be the case that the setting of preferences happens in the agent’s init() method before the awi is set. By delaying the call to on_preferences_changed() we make sure that the awi is available in case it is needed.

    2. In some cases, the negotitor may be constructed by never joins a negotiation. It is a waste of resources to compute whatever on_preferences_changed() is computing in such cases as the preferences will never be really used.

0.9->0.10 Upgrade Guide

NegMAS 0.10 is not backward compatible with NegMAS 0.9 and to use it you will need to make some modifications to your code. This guide aims at helping you achieve this with minimal hassle.

from

to

Notes

def respond(self,state, offer)

def respond(self, state)

SAO negotiator’s respond() does not receive the offer anymore. You can get the offer as state.current_offer

Other Changes

  • You can now step any world focusing on negotiations instead of simulation step boundaries. See documentation of World.step for details which helps with exposing NegMAS worlds as RL environments.

  • You can now pass negotiation actions to the SAOMechanism (and to some extend the GBMechanism ) which is useful when using RL on negmas.