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 |
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 likeoutcome_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 typetuple
now.Some I/O methods (and few others) had
force_single_issue
,keep_issue_names
andkeep_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 theOutcomeSpace
protocol liketo_single
andto_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 |
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 |
The following rules should be followed:
It is better to always tell the ufun its outcome-space by passing
outcome_space
,issues
, oroutcomes
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 callextreme_outcomes()
orminmax()
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.
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 theController
and theNegotiator
. 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 ofufun
whenever possible. For example,on_ufun_changed
was renamed toon_preferences_changed
to make it clear that general preferences can be used not only ufuns.Some methods now receive both
preferences
andufun
aruments (instead of onlyufun
) with theufun
argument overriding thepreferences
argument when given. This was done (instead of just renaming theufun
argument topreferences
) 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 passingpreferences
to the constructor) or byset_preferences()
before joining. This has two advantages: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 theawi
is set. By delaying the call toon_preferences_changed()
we make sure that theawi
is available in case it is needed.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 |
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 theGBMechanism
) which is useful when using RL on negmas.