Issue

class negmas.outcomes.Issue(values: Union[List[Any], int, Tuple[float, float], Tuple[int, int], List[int], Callable[], Any]], name: Optional[str] = None, min_value: Optional[Any] = None, max_value: Optional[Any] = None, value_type: Optional[Type] = None, id=None)[source]

Bases: negmas.common.NamedObject

Encodes an Issue.

Parameters
  • values – Possible values for the issue

  • name – Name of the issue. If not given, a random name will be generated

  • min_value – Minimum value ( used only if the issue values parameter was a callable )

  • max_value – Maximum value ( used only if the issue values parameter was a callable )

  • value_type – If a type is given, all values will be forced to this type

Examples

>>> print(Issue(['to be', 'not to be'], name='THE problem'))
THE problem: ['to be', 'not to be']
>>> print(Issue(3, name='Cars'))
Cars: (0, 2)
>>> print(Issue((0.0, 1.0), name='required accuracy'))
required accuracy: (0.0, 1.0)
>>> a = Issue((0.0, 1.0), name='required accuracy')
>>> a.is_uncountable()
True
>>> a.is_countable()
False
>>> a.is_continuous()
True
>>> a = Issue(lambda: random.randint(10), min_value=0, max_value=9)
>>> a.is_uncountable()
True
>>> a.is_countable()
False
>>> a.is_continuous()
False

Remarks:

  • Issues can be initialized by either an iterable of strings, an integer or a tuple of two values with the following meanings:

    • list of anything : This is an issue that can any value within the given set of values (strings, ints, floats, etc)

    • int : This is an issue that takes any value from 0 to the given value -1 (int)

    • Tuple[ float , float ] : This is an issue that can take any real value between the given limits (min, max)

    • Tuple[ int , int ] : This is an issue that can take any integer value between the given limits (min, max)

    • CallableThe callable should take no parameters and should act as a generator of issue values. This

      type of issue is always assumed to be neither countable nor continuous and are called uncountable. For example, you can use this type to make an issue that generates all integers from 0 to infinity.

  • If a list is given, min, max must be callable on it.

Attributes Summary

all

A generator that generates all possible values.

cardinality

The number of possible outcomes for the issue.

outcome_range

An outcome range that represents the full space of the issues

type

The type of the issue.

value_type

values

Methods Summary

alli([n])

A generator that generates all possible values or samples n values for real Issues.

combine(issues[, issue_name, …])

Combines multiple issues into a single issue

discretize_and_enumerate(issues[, …])

Enumerates the outcomes of a list of issues.

enumerate(issues[, max_n_outcomes, astype])

Enumerates the outcomes of a list of issues.

from_dict(d)

from_genius(file_name[, force_single_issue, …])

Imports a the domain issues from a GENIUS XML file.

from_java(d, class_name)

from_outcomes(outcomes[, numeric_as_ranges])

Create a set of issues given some outcomes

from_xml_str(xml_str[, force_single_issue, …])

Exports a list/dict of issues from a GENIUS XML file.

generate(issues[, counts, names])

Generates a set of issues with given parameters.

is_continuous()

Test whether the issue is a continuous issue

is_countable()

Test whether the issue is a discrete issue

is_discrete()

Test whether the issue is a discrete issue

is_float()

is_integer()

is_numeric()

is_uncountable()

Test whether the issue has uncountable possible outcomes

num_outcomes(issues)

Returns the total number of outcomes in a set of issues.

rand()

Picks a random valid value.

rand_invalid()

Pick a random invalid value

rand_outcomes(n[, with_replacement, …])

Picks a random valid value.

rand_valid()

Picks a random valid value.

sample(issues, n_outcomes[, astype, …])

Samples some outcomes from the issue space defined by the list of issues

to_dict()

to_genius(issues, file_name[, enumerate_integer])

Exports a the domain issues to a GENIUS XML file.

to_java()

to_xml_str(issues[, enumerate_integer])

Converts the list of issues into a well-formed xml string

Attributes Documentation

all

A generator that generates all possible values.

Remarks:
  • This function returns a generator for the case when the number of values is very large.

  • If you need a list then use something like:

>>> from negmas.outcomes import Issue
>>> list(Issue(5).all)
[0, 1, 2, 3, 4]
cardinality

The number of possible outcomes for the issue. Returns infinity for continuous and uncountable spaces

outcome_range

An outcome range that represents the full space of the issues

type

The type of the issue.

Returns

either ‘continuous’, ‘uncountable’ or ‘discrete’

Return type

str

Remarks:

  • IF values is set to None or to a callable, the issue is treated as continuous

value_type
values

Methods Documentation

alli(n: Optional[int] = 10)Generator[source]

A generator that generates all possible values or samples n values for real Issues.

Remarks:
  • This function returns a generator for the case when the number of values is very large.

  • If you need a list then use something like:

>>> from negmas.outcomes import Issue
>>> list(Issue(5).all)
[0, 1, 2, 3, 4]
classmethod combine(issues: Iterable[negmas.outcomes.Issue], issue_name='combined', keep_issue_names=True, keep_value_names=True, issue_sep='_', value_sep='-')Optional[negmas.outcomes.Issue][source]

Combines multiple issues into a single issue

Parameters
  • issues – The issues to be combined

  • issue_name – used only if keep_issue_names is False

  • keep_issue_names – If true, the final issue name will be a concatenation of issue names separated by issue_sep otherwise issue_name will be used.

  • keep_value_names – If true, the values for the generated issue will be a concatenation of values from earlier issues separated by value_sep.

  • issue_sep – Separator for the issue name (used only if keep_issue_names)

  • value_sep – Separator for the issue name (used only if keep_value_names)

Remarks:

  • Only works if the issues have finite cardinality

classmethod discretize_and_enumerate(issues: Collection[negmas.outcomes.Issue], n_discretization: int = 10, astype: Type = <class 'dict'>, max_n_outcomes: Optional[int] = None)List[Union[negmas.outcomes.OutcomeType, Tuple[Union[int, float, str, list]], Dict[Union[int, str], Union[int, float, str, list]]]][source]

Enumerates the outcomes of a list of issues.

Parameters
  • issues – The list of issues.

  • max_n_outcomes – The maximum number of outcomes to return

  • astype – The type to use for the returned outcomes. Can be typle dict, or any OutcomeType.

Returns

List of outcomes of the given type.

classmethod enumerate(issues: Collection[negmas.outcomes.Issue], max_n_outcomes: Optional[int] = None, astype: Type = <class 'dict'>)List[Union[negmas.outcomes.OutcomeType, Tuple[Union[int, float, str, list]], Dict[Union[int, str], Union[int, float, str, list]]]][source]

Enumerates the outcomes of a list of issues.

Parameters
  • issues – The list of issues.

  • max_n_outcomes – The maximum number of outcomes to return

  • astype – The type to use for the returned outcomes. Can be typle dict, or any OutcomeType.

Returns

List of outcomes of the given type.

classmethod from_dict(d)[source]
classmethod from_genius(file_name: Union[pathlib.Path, str], force_single_issue=False, force_numeric=False, keep_value_names=True, keep_issue_names=True, safe_parsing=True, n_discretization: Optional[int] = None, max_n_outcomes: int = 1000000)Tuple[Optional[List[negmas.outcomes.Issue]], Optional[List[str]]][source]

Imports a the domain issues from a GENIUS XML file.

Parameters
  • max_n_outcomes – Maximum number of outcomes to use

  • n_discretization – Number of discretization levels per issue

  • safe_parsing – Add more checks to parsing

  • keep_issue_names – Use dictionaries instead of tuples to represent outcomes

  • keep_value_names – keep value names in case of strings

  • force_numeric – Force the issue values to be numeric

  • force_single_issue – Combine all issues into a single issue

  • file_name (str) – File name to import from

Returns

  • List[Issue] containing the issues

  • List[str] containing agent names (that are sometimes stored in the genius domain)

Return type

A two optional lists

Examples

>>> import pkg_resources
>>> issues, _ = Issue.from_genius(file_name = pkg_resources.resource_filename('negmas'
...                                      , resource_name='tests/data/Laptop/Laptop-C-domain.xml'))
>>> print([_.name for _ in issues])
['Laptop', 'Harddisk', 'External Monitor']
Remarks:

See from_xml_str for all the parameters

classmethod from_java(d: Dict[str, Any], class_name: str)negmas.outcomes.Issue[source]
classmethod from_outcomes(outcomes: List[Union[negmas.outcomes.OutcomeType, Tuple[Union[int, float, str, list]], Dict[Union[int, str], Union[int, float, str, list]]]], numeric_as_ranges: bool = False)List[negmas.outcomes.Issue][source]

Create a set of issues given some outcomes

Parameters
  • outcomes – A list of outcomes

  • numeric_as_ranges – If True, all numeric issues generated will have ranges that are defined by the minimum and maximum values of that issue in the given outcomes instead of a list of the values that appeared in them.

Returns

a list of issues that include the given outcomes.

Remarks:

  • The outcome space spanned by the generated issues can in principle contain many more possible outcomes than the ones given

classmethod from_xml_str(xml_str: str, force_single_issue=False, force_numeric=False, keep_value_names=True, keep_issue_names=True, safe_parsing=True, n_discretization: Optional[int] = None, max_n_outcomes: int = 1000000)Tuple[Optional[List[negmas.outcomes.Issue]], Optional[List[str]]][source]

Exports a list/dict of issues from a GENIUS XML file.

Parameters
  • xml_str (str) – The string containing GENIUS style XML domain issue definitions

  • force_single_issue (bool) – Tries to generate a MappingUtility function with a single issue which is the

  • of all issues in the input (product) –

  • keep_value_names (bool) – Keep names of values

  • keep_issue_names (bool) – Keep names of issues

  • safe_parsing (bool) – Turn on extra checks

  • n_discretization (Optional[int]) – If not None, real valued issues are discretized with the given

  • of values (number) –

  • max_n_outcomes (int) – Maximum number of outcomes allowed (effective only if force_single_issue is True)

Returns

  • List[Issue] The issues (note that issue names will be stored in the name attribute of each issue if keep_issue_names)

  • List[dict] A list of agent information dicts each contains ‘agent’, ‘class’, ‘utility_file_name’

Examples

>>> import pkg_resources
>>> domain_file_name = pkg_resources.resource_filename('negmas'
...                                      , resource_name='tests/data/Laptop/Laptop-C-domain.xml')
>>> issues, _ = Issue.from_xml_str(open(domain_file_name, 'r').read()
... , force_single_issue=True, keep_value_names=False, keep_issue_names=False)
>>> issue = issues[0]
>>> print(issue.cardinality)
27
>>> print(list(issue.all))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
>>> issues, _ = Issue.from_xml_str(open(domain_file_name, 'r').read()
... , force_single_issue=True, keep_value_names=False, keep_issue_names=True)
>>> print(issues[0].name)
Laptop-Harddisk-External Monitor
>>> print(len(issues))
1
>>> print(list(issues[0].all))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
>>> issues, _ = Issue.from_xml_str(open(domain_file_name, 'r').read()
... , force_single_issue=True, keep_value_names=True, keep_issue_names=False)
>>> issue = issues[0]
>>> print(issue.cardinality)
27
>>> print('\n'.join(list(issue.all)[:5]))
Dell+60 Gb+19'' LCD
Dell+60 Gb+20'' LCD
Dell+60 Gb+23'' LCD
Dell+80 Gb+19'' LCD
Dell+80 Gb+20'' LCD
>>> issues, _ = Issue.from_xml_str(open(domain_file_name, 'r').read()
... , force_single_issue=False, keep_issue_names=False, keep_value_names=True)
>>> type(issues)
<class 'list'>
>>> str(issues[0])
"0: ['Dell', 'Macintosh', 'HP']"
>>> print([_.cardinality for _ in issues])
[3, 3, 3]
>>> print('\n'.join([' '.join(list(issue.all)) for issue in issues]))
Dell Macintosh HP
60 Gb 80 Gb 120 Gb
19'' LCD 20'' LCD 23'' LCD
>>> issues, _ = Issue.from_xml_str(open(domain_file_name, 'r').read()
... , force_single_issue=False, keep_issue_names=True, keep_value_names=True)
>>> len(issues)
3
>>> str(issues[0])
"Laptop: ['Dell', 'Macintosh', 'HP']"
>>> print([_.cardinality for _ in issues])
[3, 3, 3]
>>> print('\n'.join([' '.join(list(issue.all)) for issue in issues]))
Dell Macintosh HP
60 Gb 80 Gb 120 Gb
19'' LCD 20'' LCD 23'' LCD
>>> issues, _ = Issue.from_xml_str(open(domain_file_name, 'r').read()
... , force_single_issue=False, keep_issue_names=False, keep_value_names=False)
>>> len(issues)
3
>>> type(issues)
<class 'list'>
>>> str(issues[0]).split(': ')[-1]
'(0, 2)'
>>> print([_.cardinality for _ in issues])
[3, 3, 3]
>>> domain_file_name = pkg_resources.resource_filename('negmas'
...                              , resource_name='tests/data/fuzzyagent/single_issue_domain.xml')
>>> issues, _ = Issue.from_xml_str(open(domain_file_name, 'r').read()
... , force_single_issue=False, keep_issue_names=False, keep_value_names=False)
>>> len(issues)
1
>>> type(issues)
<class 'list'>
>>> str(issues[0]).split(': ')[-1]
'(10.0, 40.0)'
>>> print([_.cardinality for _ in issues])
[inf]
static generate(issues: Sequence[Union[int, List[str], Tuple[int, int], Callable, Tuple[float, float]]], counts: Optional[Sequence[int]] = None, names: Optional[Sequence[str]] = None)List[negmas.outcomes.Issue][source]

Generates a set of issues with given parameters. Each is optionally repeated

Parameters
  • issues – The parameters of the issues

  • counts – The number of times to repeat each of the issues

  • names – The names to assign to the issues. If None, then string representations of integers starting from zero will be used.

Returns

The list of issues with given conditions

Return type

List[‘Issue’]

is_continuous()bool[source]

Test whether the issue is a continuous issue

Returns

uncountable (including continuous) or not

Return type

bool

is_countable()bool[source]

Test whether the issue is a discrete issue

Returns

countable or not

Return type

bool

is_discrete()bool

Test whether the issue is a discrete issue

Returns

countable or not

Return type

bool

is_float()bool[source]
is_integer()bool[source]
is_numeric()bool[source]
is_uncountable()bool[source]

Test whether the issue has uncountable possible outcomes

Returns

uncountable (including continuous) or not

Return type

bool

static num_outcomes(issues: Iterable[negmas.outcomes.Issue])Union[int, float][source]

Returns the total number of outcomes in a set of issues. -1 indicates infinity

rand()Union[int, float, str][source]

Picks a random valid value.

rand_invalid()Union[int, float, str][source]

Pick a random invalid value

rand_outcomes(n: int, with_replacement=False, fail_if_not_enough=False)Iterable[Union[negmas.outcomes.OutcomeType, Tuple[Union[int, float, str, list]], Dict[Union[int, str], Union[int, float, str, list]]]][source]

Picks a random valid value.

rand_valid()Union[int, float, str]

Picks a random valid value.

classmethod sample(issues: Collection[negmas.outcomes.Issue], n_outcomes: int, astype: Type = <class 'dict'>, with_replacement: bool = True, fail_if_not_enough=True)List[Union[negmas.outcomes.OutcomeType, Tuple[Union[int, float, str, list]], Dict[Union[int, str], Union[int, float, str, list]]]][source]

Samples some outcomes from the issue space defined by the list of issues

Parameters
  • issues – List of issues to sample from

  • n_outcomes – The number of outcomes required

  • astype – The type of the outcomes. It can be tuple, dict or any OutcomeType

  • with_replacement – Whether sampling is with replacement (allowing repetition)

  • fail_if_not_enough – IF given then an exception is raised if not enough outcomes are available

Returns

a list of outcomes

Examples

>>> from negmas.outcomes import Issue, OutcomeType
>>> issues = [Issue(name='price', values=(0.0, 3.0)), Issue(name='quantity', values=10)]

Sampling outcomes as tuples

>>> samples = Issue.sample(issues=issues, n_outcomes=10, astype=tuple)
>>> len(samples) == 10
True
>>> type(samples[0]) == tuple
True

Sampling outcomes as dicts

>>> samples = Issue.sample(issues=issues, n_outcomes=10, astype=dict)
>>> len(samples) == 10
True
>>> type(samples[0]) == dict
True
>>> list(samples[0].keys())
['price', 'quantity']
>>> @dataclass
... class MyOutcome(OutcomeType):
...     price: float = 0.0
...     quantity: int = 0

Sampling outcomes as an arbitrary class

>>> samples = Issue.sample(issues=issues, n_outcomes=10, astype=MyOutcome)
>>> len(samples) == 10
True
>>> type(samples[0]) == MyOutcome
True
>>> list(samples[0].keys())
['price', 'quantity']
to_dict()[source]
classmethod to_genius(issues: Iterable[negmas.outcomes.Issue], file_name: Union[pathlib.Path, str], enumerate_integer: bool = True)None[source]

Exports a the domain issues to a GENIUS XML file.

Parameters
  • issues – The issues to be exported

  • file_name (str) – File name to export to

Returns

A List[Issue] or Dict[Issue]

Examples

>>> import pkg_resources
>>> issues, _ = Issue.from_genius(file_name = pkg_resources.resource_filename('negmas'
...                                      , resource_name='tests/data/Laptop/Laptop-C-domain.xml'))
>>> Issue.to_genius(issues=issues, file_name = pkg_resources.resource_filename('negmas'
...                                    , resource_name='tests/data/LaptopConv/Laptop-C-domain.xml'))
>>> issues2, _ = Issue.from_genius(file_name = pkg_resources.resource_filename('negmas'
...                                    , resource_name='tests/data/LaptopConv/Laptop-C-domain.xml'))
>>> print('\n'.join([' '.join(list(issue.all)) for issue in issues]))
Dell Macintosh HP
60 Gb 80 Gb 120 Gb
19'' LCD 20'' LCD 23'' LCD
>>> print('\n'.join([' '.join(list(issue.all)) for issue in issues2]))
Dell Macintosh HP
60 Gb 80 Gb 120 Gb
19'' LCD 20'' LCD 23'' LCD
  • Forcing Single outcome

>>> issues, _ = Issue.from_genius(file_name = pkg_resources.resource_filename('negmas'
...                                      , resource_name='tests/data/Laptop/Laptop-C-domain.xml')
...     , force_single_issue=True, keep_value_names=False, keep_issue_names=False)
>>> print(list(issues[0].all))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
>>> Issue.to_genius(issues=issues, enumerate_integer=True
...     , file_name = pkg_resources.resource_filename('negmas'
...                                   , resource_name='tests/data/LaptopConv/Laptop-C-domain.xml'))
>>> issues3, _ = Issue.from_genius(file_name=pkg_resources.resource_filename('negmas'
...                                    , resource_name='tests/data/LaptopConv/Laptop-C-domain.xml'))
>>> print([list(issue.all) for issue in issues3])
[['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26']]
Remarks:

See from_xml_str for all the parameters

to_java()[source]
classmethod to_xml_str(issues: List[negmas.outcomes.Issue], enumerate_integer: bool = True)str[source]

Converts the list of issues into a well-formed xml string

Examples

>>> issues = [Issue(values=10, name='i1'), Issue(values=['a', 'b', 'c'], name='i2'),
... Issue(values=(2.5, 3.5), name='i3')]
>>> s = Issue.to_xml_str(issues)
>>> print(s.strip())
<negotiation_template>
<utility_space number_of_issues="3">
<objective description="" etype="objective" index="0" name="root" type="objective">
    <issue etype="discrete" index="1" name="i1" type="discrete" vtype="discrete">
        <item index="1" value="0" cost="0" description="0">
        </item>
        <item index="2" value="1" cost="0" description="1">
        </item>
        <item index="3" value="2" cost="0" description="2">
        </item>
        <item index="4" value="3" cost="0" description="3">
        </item>
        <item index="5" value="4" cost="0" description="4">
        </item>
        <item index="6" value="5" cost="0" description="5">
        </item>
        <item index="7" value="6" cost="0" description="6">
        </item>
        <item index="8" value="7" cost="0" description="7">
        </item>
        <item index="9" value="8" cost="0" description="8">
        </item>
        <item index="10" value="9" cost="0" description="9">
        </item>
    </issue>
    <issue etype="discrete" index="2" name="i2" type="discrete" vtype="discrete">
        <item index="1" value="a" cost="0" description="a">
        </item>
        <item index="2" value="b" cost="0" description="b">
        </item>
        <item index="3" value="c" cost="0" description="c">
        </item>
    </issue>
    <issue etype="real" index="3" name="i3" type="real" vtype="real">
        <range lowerbound="2.5" upperbound="3.5"></range>
    </issue>
</objective>
</utility_space>
</negotiation_template>
>>> issues2, _ = Issue.from_xml_str(s)
>>> print([_.__class__.__name__ for _ in issues2])
['Issue', 'Issue', 'Issue']
>>> print(len(issues2))
3
>>> print([str(_) for _ in issues2])
["i1: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']", "i2: ['a', 'b', 'c']", 'i3: (2.5, 3.5)']
>>> print([_.values for _ in issues2])
[['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], ['a', 'b', 'c'], (2.5, 3.5)]