negmas.outcomes

Defines basic concepts related to outcomes

Outcomes in this package are always assumed to be multi-issue outcomes where single-issue outcomes can be implemented as the special case with a single issue.

  • Both Continuous and discrete issues are supported. All issue will have names. If none is given, a random name will be used. It is HIGHLY recommended to always name your issues.

  • Outcomes are dictionaries with issue names as keys and issue values as values.

Examples

Different ways to create issues:

>>> issues = [
...     make_issue((0.5, 2.0), "price"),
...     make_issue(["2018.10." + str(_) for _ in range(1, 4)], "date"),
...     make_issue(20, "count"),
... ]
>>> for _ in issues:
...     print(_)
price: (0.5, 2.0)
date: ['2018.10.1', '2018.10.2', '2018.10.3']
count: (0, 19)

Outcome example compatible with the given set of issues:

>>> a = {"price": 1.2, "date": "2018.10.04", "count": 4}
class negmas.outcomes.CallableIssue(values, name=None)[source]

Bases: Issue

An Issue with a callable for generating values. This is a very limited issue type and most operations are not supported on it.

is_continuous() bool[source]

Check if this issue has continuous values (always False for callables).

is_uncountable() bool[source]

Check if the issue has uncountably many values (always True for callables).

is_valid()[source]

Validity checking is not supported for callable issues.

Raises:

ValueError – Always raised since validity cannot be determined.

ordered_value_generator(n: int | float | None = 10, grid=True, compact=False, endpoints=True) Generator[Any, None, None][source]

Not supported for callable issues.

Parameters:
  • n – Number of values to generate.

  • grid – Ignored - ordering not supported.

  • compact – Ignored - ordering not supported.

  • endpoints – Ignored - ordering not supported.

Raises:

NotImplementedError – Always raised since ordering is undefined for callables.

rand()[source]

Picks a random valid value.

rand_invalid()[source]

Pick a random invalid value

rand_outcomes(n: int, with_replacement=False, fail_if_not_enough=False) list[source]

Generate n random values by calling the underlying callable.

Parameters:
  • n – Number of random values to generate.

  • with_replacement – Must be True; sampling without replacement is not supported.

  • fail_if_not_enough – Ignored for callable issues.

Returns:

A list of n values produced by calling the stored callable.

Raises:

ValueError – If with_replacement is False.

property type: str[source]

Return the issue type identifier (always ‘uncountable’ for callables).

value_at(index: int)[source]

Indexing is not supported for callable issues.

Parameters:

index – Ignored - indexing not supported.

Raises:

ValueError – Always raised since callables cannot be indexed.

value_generator(n: int | float | None = 10, grid=True, compact=False, endpoints=True) Generator[Any, None, None][source]

Generate n values by calling the underlying callable.

Parameters:
  • n – Number of values to generate (must be a finite integer).

  • grid – Ignored - values come from callable.

  • compact – Ignored - values come from callable.

  • endpoints – Ignored - values come from callable.

Yields:

Values produced by calling the stored callable n times.

Raises:

ValueError – If n is None or a float.

class negmas.outcomes.CardinalIssue(values, name=None)[source]

Bases: OrdinalIssue

An Issue for which differences between values are meaningful.

class negmas.outcomes.CartesianOutcomeSpace(issues, name: str | None = None, path: Path | None = None, constraints: list[Callable[[tuple], bool]] = NOTHING)[source]

Bases: XmlSerializable

An outcome-space that is generated by the cartesian product of a tuple of Issue s.

add_constraint(constraint: Callable[[tuple], bool]) None[source]

Add a constraint function to this outcome space.

Parameters:

constraint – A callable that takes an Outcome and returns True if valid, False otherwise.

Remarks:
  • Outcomes that fail this constraint will be filtered out from enumerate, sample, etc.

are_types_ok(outcome: tuple) bool[source]

Checks if the type of each value in the outcome is correct for the given issue

property cardinality: int | float[source]

The space cardinality = the number of outcomes

cardinality_if_discretized(levels: int, max_cardinality: int | float = inf) int[source]

Computes the cardinality that would result from discretizing continuous issues.

cartesian_product(other: CartesianOutcomeSpace) CartesianOutcomeSpace[source]

Returns a new outcome space that is the Cartesian product of this space and another.

clear_constraints() None[source]

Remove all constraints from this outcome space.

property constraints: list[Callable[[tuple], bool]][source]

Returns the list of constraint functions.

contains_issue(x: Issue) bool[source]

Cheks that the given issue is in the tuple of issues constituting the outcome space (i.e. it is one of its dimensions)

contains_os(x: OutcomeSpace) bool[source]

Checks whether an outcome-space is contained in this outcome-space

ensure_correct_types(outcome: tuple) tuple[source]

Returns an outcome that is guaratneed to have correct types or raises an exception

enumerate_or_sample(levels: int | float = inf, max_cardinality: int | float = inf) Iterable[tuple][source]

Enumerates all outcomes if possible (i.e. discrete space) or returns max_cardinality different outcomes otherwise

enumerate_or_sample_rational(preferences: Iterable[HasReservedValue | HasReservedOutcome], levels: int | float = inf, max_cardinality: int | float = inf, aggregator: Callable[[Iterable[bool]], bool] = <built-in function any>) Iterable[Outcome][source]

Enumerates all outcomes if possible (i.e. discrete space) or returns max_cardinality different outcomes otherwise.

Parameters:
  • preferences – A list of Preferences that is used to judge outcomes

  • levels – The number of levels to use for discretization if needed

  • max_cardinality – The maximum cardinality allowed in case of discretization

  • aggregator – A predicate that takes an Iterable of booleans representing whether or not an outcome is rational for a given Preferences (i.e. better than reservation) and returns a single boolean representing the result for all preferences. Default is any but can be all.

classmethod from_dict(d, python_class_identifier='__python_class__')[source]

Deserializes an outcome space from a dictionary representation.

static from_outcomes(outcomes: list[tuple], numeric_as_ranges: bool = False, issue_names: list[str] | None = None, name: str | None = None) DiscreteCartesianOutcomeSpace[source]

Creates a discrete outcome space by inferring issues from a list of outcomes.

classmethod from_xml_str(xml_str: str, safe_parsing=True, name=None, **kwargs) CartesianOutcomeSpace[source]

Parses an outcome space from an XML string representation.

is_all_continuous() bool[source]

Checks whether all issues are discrete

is_compact() bool[source]

Checks whether all issues are complete ranges

is_discrete() bool[source]

Checks whether all issues are discrete

is_finite() bool[source]

Checks whether the space is finite

is_float() bool[source]

Checks whether all issues are real

is_integer() bool[source]

Checks whether all issues are integer

is_not_discrete() bool[source]

Checks whether all issues are discrete

is_numeric() bool[source]

Checks whether all issues are numeric

is_valid(outcome: tuple) bool[source]

Checks if the given outcome is valid within this outcome space.

property issue_names: list[str][source]

Returns an ordered list of issue names

issues: tuple[Issue, ...][source]
name: str | None[source]
path: Path | None[source]
random_outcome()[source]

Generates a single random outcome by sampling one value from each issue.

remove_constraint(constraint: Callable[[tuple], bool]) None[source]

Remove a constraint function from this outcome space.

Parameters:

constraint – The constraint function to remove.

sample(n_outcomes: int, with_replacement: bool = True, fail_if_not_enough=True) Iterable[tuple][source]

Samples outcomes from this space, with or without replacement.

satisfies_constraints(outcome: tuple) bool[source]

Check if an outcome satisfies all constraints.

Parameters:

outcome – The outcome to check.

Returns:

True if the outcome satisfies all constraints, False otherwise.

to_dict(python_class_identifier='__python_class__')[source]

Serializes the outcome space to a dictionary representation.

to_discrete(levels: int | float = 10, max_cardinality: int | float = inf) DiscreteCartesianOutcomeSpace[source]

Discretizes the outcome space by sampling Logging Levels values for each continuous issue.

The result of the discretization is stable in the sense that repeated calls will return the same output.

to_largest_discrete(levels: int, max_cardinality: int | float = inf, **kwargs) DiscreteCartesianOutcomeSpace[source]

Discretizes to the largest possible space within the given cardinality constraint.

to_single_issue(numeric=False, stringify=True, levels: int = 5, max_cardinality: int | float = inf) DiscreteCartesianOutcomeSpace[source]

Creates a new outcome space that is a single-issue version of this one discretizing it as needed

Parameters:
  • numeric – If given, the output issue will be a ContiguousIssue otberwise it will be a CategoricalIssue

  • stringify – If given, the output issue will have string values. Checked only if Numeric and Mathematical Modules is False

  • levels – Number of levels to discretize any continuous issue

  • max_cardinality – Maximum allowed number of outcomes in the resulting issue.

Remarks:
  • Will discretize inifinte outcome spaces

to_xml_str(**kwargs) str[source]

Serializes the outcome space to an XML string representation.

class negmas.outcomes.CategoricalIssue(values, name=None)[source]

Bases: DiscreteIssue

An Issue type representing discrete values that have no ordering or difference defined.

property all: Generator[Any, None, None][source]

Generate all possible values for this categorical issue.

Returns:

Generator yielding each valid categorical value

Return type:

Generator[Any, None, None]

is_continuous() bool[source]

Check if this issue has continuous values.

Returns:

Always False for categorical issues (discrete values only)

Return type:

bool

is_uncountable() bool[source]

Check if the issue has uncountably infinite values.

Returns:

Always False for categorical issues (finite countable values)

Return type:

bool

rand_invalid()[source]

Pick a random invalid value

property type: str[source]

Type of issue (continuous, discrete, categorical, etc.).

Returns:

Always returns ‘categorical’ for this issue type

Return type:

str

class negmas.outcomes.ContiguousIssue(values: int | tuple[int, int], name: str | None = None)[source]

Bases: RangeIssue, DiscreteIssue

A RangeIssue (also a DiscreteIssue) representing a contiguous range of integers.

property all: Generator[int, None, None][source]

Generator yielding all integer values in the range [min, max].

property cardinality: int[source]

Number of distinct integer values in this issue’s range.

contains(issue: Issue) bool[source]

Checks weather this issue contains the input issue (i.e. every value in the input issue is in this issue)

is_continuous() bool[source]

Check if this issue has continuous values (always False for integers).

ordered_value_generator(n: int | float | None = None, grid=True, compact=False, endpoints=True) Generator[int, None, None][source]

Generate integer values in ascending order from this range.

Parameters:
  • n – Maximum number of values to generate, or None for all.

  • grid – If True, use evenly spaced values; otherwise sample randomly.

  • compact – If True, concentrate values around the center of the range.

  • endpoints – If True, include min and max values in the output.

Returns:

Generator yielding integers from the range in order.

rand() int[source]

Picks a random valid value.

rand_invalid()[source]

Pick a random invalid value

rand_outcomes(n: int, with_replacement=False, fail_if_not_enough=False) list[int][source]

Picks a random valid value.

to_discrete(n: int | None, grid=True, compact=False, endpoints=True) DiscreteIssue[source]

Convert to a discrete issue with at most n values.

Parameters:
  • n – Maximum number of discrete values, or None to keep all.

  • grid – If True, use evenly spaced values; otherwise sample randomly.

  • compact – If True, select a contiguous subrange from the center.

  • endpoints – If True, include min and max values in the discretization.

Returns:

A ContiguousIssue (if compact) or general DiscreteIssue with sampled values.

value_at(index: int)[source]

Return the integer value at the given index position.

Parameters:

index – Zero-based position in the range.

Raises:

IndexError – If index is out of bounds.

value_generator(n: int | float | None = None, grid=True, compact=False, endpoints=True) Generator[int, None, None][source]

Generate a sample of integer values from this range.

Parameters:
  • n – Maximum number of values to generate, or None for all.

  • grid – If True, use evenly spaced values; otherwise sample randomly.

  • compact – If True, concentrate values around the center of the range.

  • endpoints – If True, include min and max values in the output.

Returns:

Generator yielding sampled integer values from the range.

class negmas.outcomes.ContinuousInfiniteIssue(values, name=None, n_levels=10)[source]

Bases: ContinuousIssue, InfiniteIssue

An issue that can represent all real numbers

contains(issue: Issue) bool[source]

Checks weather this issue contains the input issue (i.e. every value in the input issue is in this issue)

class negmas.outcomes.ContinuousIssue(values, name=None, n_levels=10)[source]

Bases: RangeIssue

A RangeIssue representing a continous range of real numbers with finite limits.

property all[source]

Cannot enumerate all values of a continuous issue.

Raises:

ValueError – Always raised since continuous issues are uncountable.

property cardinality: int | float[source]

Number of possible values (infinite for continuous issues).

Returns:

Always returns infinity for continuous issues

Return type:

int | float

contains(issue: Issue) bool[source]

Checks weather this issue contains the input issue (i.e. every value in the input issue is in this issue)

is_continuous() bool[source]

Check if this issue has continuous values.

Returns:

Always True for continuous issues

Return type:

bool

is_uncountable() bool[source]

Check if the issue has uncountably infinite values.

Returns:

Always True for continuous issues (uncountably infinite)

Return type:

bool

ordered_value_generator(n: int | float | None = 10, grid=True, compact=False, endpoints=True) Generator[float, None, None][source]

Generate float values in ascending order from this range.

Parameters:
  • n – Number of values to generate (required, must be finite).

  • grid – If True, use evenly spaced values; otherwise sample randomly.

  • compact – If True, concentrate values around the center of the range.

  • endpoints – If True, include min and max values in the output.

Returns:

Generator yielding float values in ascending order.

Raises:

ValueError – If n is None or infinite.

rand() float[source]

Picks a random valid value.

rand_invalid()[source]

Pick a random invalid value

rand_outcomes(n: int, with_replacement=False, fail_if_not_enough=False) list[float][source]

Generate n random float values from this continuous range.

Parameters:
  • n – Number of random values to generate.

  • with_replacement – If True, sample randomly; otherwise use linspace.

  • fail_if_not_enough – Ignored for continuous issues (always enough values).

Returns:

A list of n float values from the range.

to_dict(python_class_identifier='__python_class__')[source]

Serialize this issue to a dictionary for reconstruction.

Parameters:

python_class_identifier – Key used to store the class type info.

property type: str[source]

Type of issue (continuous, discrete, categorical, etc.).

Returns:

Always returns ‘continuous’ for this issue type

Return type:

str

value_at(index: int)[source]

Return the value at the given discretization level.

Parameters:

index – Zero-based index into discretized levels.

Raises:

IndexError – If the computed value exceeds max_value.

value_generator(n: int | float | None = 100, grid=True, compact=False, endpoints=True) Generator[float, None, None][source]

Generate a sample of float values from this continuous range.

Parameters:
  • n – Number of values to generate (required, must be finite).

  • grid – If True, use evenly spaced values; otherwise sample randomly.

  • compact – If True, concentrate values around the center of the range.

  • endpoints – If True, include min and max values in the output.

Returns:

Generator yielding sampled float values.

class negmas.outcomes.CountableInfiniteIssue(values: tuple[int | float, int | float], *args, **kwargs)[source]

Bases: ContiguousIssue, InfiniteIssue

An issue that can have all integer values.

Remarks:
  • Actually, inifinties are replace with +- INFINITE_INT which is a very large number

property cardinality: float[source]

Cardinality.

Returns:

The result.

Return type:

float

contains(issue: Issue) bool[source]

Checks weather this issue contains the input issue (i.e. every value in the input issue is in this issue)

is_continuous() bool[source]

Check if continuous.

Returns:

The result.

Return type:

bool

is_integer() bool[source]

Check if integer.

Returns:

The result.

Return type:

bool

rand_invalid()[source]

Returns a random value outside the valid range, or None if the range is unbounded.

value_at(index: int)[source]

Access value by index (not supported for infinite issues).

Parameters:

index – The index to access.

Raises:

ValueError – Infinite issues cannot be indexed.

class negmas.outcomes.DiscreteCardinalIssue(values, name=None)[source]

Bases: DiscreteOrdinalIssue, CardinalIssue

An issue that has an ordering and for which differences between values is defined (i.e. subtraction)

class negmas.outcomes.DiscreteCartesianOutcomeSpace(issues, name: str | None = None, path: Path | None = None, constraints: list[Callable[[tuple], bool]] = NOTHING)[source]

Bases: CartesianOutcomeSpace

A discrete outcome-space that is generated by the cartesian product of a tuple of Issue s (i.e. with finite number of outcomes).

property cardinality: int[source]

Returns the total number of possible outcomes in this space.

cardinality_if_discretized(levels: int, max_cardinality: int | float = inf) int[source]

Returns the cardinality unchanged since this space is already discrete.

enumerate() Iterable[tuple][source]

Iterates over all possible outcomes in this discrete space.

is_discrete() bool[source]

Checks whether there are no continua components of the space

limit_cardinality(max_cardinality: int | float = inf, levels: int | float = inf) DiscreteCartesianOutcomeSpace[source]

Limits the cardinality of the outcome space to the given maximum (or the number of levels for each issue to Logging Levels)

Parameters:
  • max_cardinality – The maximum number of outcomes in the resulting space

  • levels – The maximum number of levels for each issue/subissue

to_discrete(levels: int | float = 10, max_cardinality: int | float = inf) DiscreteCartesianOutcomeSpace[source]

Returns self since this space is already discrete.

to_largest_discrete(levels: int, max_cardinality: int | float = inf, **kwargs) DiscreteCartesianOutcomeSpace[source]

Returns self since this space is already discrete.

to_single_issue(numeric=False, stringify=True, levels: int = 5, max_cardinality: int | float = inf) DiscreteCartesianOutcomeSpace[source]

Creates a new outcome space that is a single-issue version of this one

Parameters:
Remarks:
  • maps the agenda and ufuns to work correctly together

  • Only works if the outcome space is finite

class negmas.outcomes.DiscreteIssue(values, name: str | None = None)[source]

Bases: Issue

An Issue with a discrete set of values.

abstract property all: Generator[Any, None, None][source]

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 make_issue
>>> list(make_issue(5).all)
[0, 1, 2, 3, 4]
property cardinality: int[source]

The number of possible outcomes for the issue. Guaranteed to be fininte

is_continuous() bool[source]

Always returns False since discrete issues are not continuous.

is_valid(v)[source]

Checks whether the given value is one of the valid issue values.

ordered_value_generator(n: int | float | None = 10, grid=True, compact=True, endpoints=True) Generator[Any, None, None][source]

Generates values in their natural order, cycling if n exceeds cardinality.

rand()[source]

Picks a random valid value.

rand_outcomes(n: int, with_replacement=False, fail_if_not_enough=False) Iterable[Outcome][source]

Picks a set of random outcomes

value_at(index: int)[source]

Returns the value at the given index, raising IndexError if out of bounds.

value_generator(n: int | float | None = None, grid=True, compact=True, endpoints=True) Generator[Any, None, None][source]

Generates sampled values based on the specified sampling strategy.

class negmas.outcomes.DiscreteOrdinalIssue(values, name=None)[source]

Bases: DiscreteIssue, OrdinalIssue

A DiscreteIssue that have some defined ordering of outcomes but not necessarily a meaningful difference function between its values.

property all: Generator[Any, None, None][source]

All.

Returns:

The result.

Return type:

Generator[Any, None, None]

ordered_value_generator(n: int = 10, grid=True, compact=False, endpoints=True) Generator[Any, None, None][source]

A generator that generates at most n values (in order)

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 make_issue
>>> list(make_issue(5).ordered_value_generator())
[0, 1, 2, 3, 4]
>>> list(
...     int(10 * _)
...     for _ in make_issue((0.0, 1.0)).ordered_value_generator(11)
... )
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
rand_invalid()[source]

Pick a random invalid value

class negmas.outcomes.DiscreteOutcomeSpace(*args, **kwargs)[source]

Bases: OutcomeSpace, Collection, Protocol

The base protocol for all outcome spaces with a finite number of items.

This type of outcome-space acts as a standard python Collection which means that its length can be found using len() and it can be iterated over to return outcomes.

property cardinality: int[source]

The space cardinality = the number of outcomes

enumerate() Iterable[Outcome][source]

Enumerates the outcome space returning all its outcomes (or up to max_cardinality for infinite ones)

is_discrete() bool[source]

Checks whether there are no continua components of the space

limit_cardinality(max_cardinality: int | float = inf, levels: int | float = inf) DiscreteOutcomeSpace[source]

Limits the cardinality of the outcome space to the given maximum (or the number of levels for each issue to Logging Levels)

Parameters:
  • max_cardinality – The maximum number of outcomes in the resulting space

  • levels – The maximum levels allowed per issue (if issues are defined for this outcome space)

sample(n_outcomes: int, with_replacement: bool = False, fail_if_not_enough=True) Iterable[Outcome][source]

Sample.

Parameters:
  • n_outcomes – N outcomes.

  • with_replacement – With replacement.

  • fail_if_not_enough – Fail if not enough.

Returns:

The result.

Return type:

Iterable[Outcome]

to_discrete(*args, **kwargs) DiscreteOutcomeSpace[source]

To discrete.

Parameters:
  • *args – Additional positional arguments.

  • **kwargs – Additional keyword arguments.

Returns:

The result.

Return type:

DiscreteOutcomeSpace

to_single_issue(numeric: bool = False, stringify: bool = True) CartesianOutcomeSpace[source]

Convert multi-issue outcome space to a single-issue representation.

Parameters:
  • numeric – If True, encode outcomes as numeric values; otherwise use original types.

  • stringify – If True, convert outcome values to strings for the single issue.

Returns:

A CartesianOutcomeSpace with a single issue representing all original outcomes.

class negmas.outcomes.EnumeratingOutcomeSpace(invalid: set[tuple] = NOTHING, baseset: set[tuple] = NOTHING, name: str | None = None, path: Path | None = None, constraints: list[Callable[[tuple], bool]] = NOTHING)[source]

Bases: DiscreteOutcomeSpace, OSWithValidity

An outcome space representing the enumeration of some outcomes. No issues defined

add_constraint(constraint: Callable[[tuple], bool]) None[source]

Add a constraint function to this outcome space.

Parameters:

constraint – A callable that takes an Outcome and returns True if valid, False otherwise.

Remarks:
  • Outcomes that fail this constraint will be filtered out from enumerate, sample, etc.

are_types_ok(outcome: tuple) bool[source]

Checks if the type of each value in the outcome is correct for the given issue

property cardinality: int[source]

The space cardinality = the number of outcomes

cardinality_if_discretized(levels: int, max_cardinality: int | float = inf) int[source]

Returns the cardinality if discretized the given way.

clear_constraints() None[source]

Remove all constraints from this outcome space.

property constraints: list[Callable[[tuple], bool]][source]

Returns the list of constraint functions.

contains_os(x: OutcomeSpace) bool[source]

Checks whether an outcome-space is contained in this outcome-space.

ensure_correct_types(outcome: tuple) tuple[source]

Returns an outcome that is guaratneed to have correct types or raises an exception

enumerate() Iterable[tuple][source]

Enumerates the outcome space returning all its outcomes (or up to max_cardinality for infinite ones)

enumerate_or_sample(levels: int | float = inf, max_cardinality: int | float = inf) Iterable[tuple][source]

Enumerates all outcomes if possible (i.e. discrete space) or returns max_cardinality different outcomes otherwise

invalidate(outcome: tuple) None[source]

Indicates that the outcome is invalid

is_discrete() bool[source]

Checks whether there are no continua components of the space

is_finite() bool[source]

Checks whether the space is finite

is_float() bool[source]

Checks whether all values in all outcomes are real

is_integer() bool[source]

Checks whether all values in all outcomes are integers

is_numeric() bool[source]

Checks whether all values in all outcomes are numeric

is_valid(outcome: tuple) bool[source]

Checks if the given outcome is valid for that outcome space

limit_cardinality(max_cardinality: int | float = inf, levels: int | float = inf) DiscreteOutcomeSpace[source]

Limits the cardinality of the outcome space to the given maximum (or the number of levels for each issue to Logging Levels)

Parameters:
  • max_cardinality – The maximum number of outcomes in the resulting space

  • levels – The maximum levels allowed per issue (if issues are defined for this outcome space)

name: str | None[source]
path: Path | None[source]
random_outcome() tuple[source]

Returns a single random outcome.

remove_constraint(constraint: Callable[[tuple], bool]) None[source]

Remove a constraint function from this outcome space.

Parameters:

constraint – The constraint function to remove.

sample(n_outcomes: int, with_replacement: bool = False, fail_if_not_enough=False) Iterable[tuple][source]

Samples up to n_outcomes with or without replacement

satisfies_constraints(outcome: tuple) bool[source]

Check if an outcome satisfies all constraints.

Parameters:

outcome – The outcome to check.

Returns:

True if the outcome satisfies all constraints, False otherwise.

to_discrete(levels: int | float = 5, max_cardinality: int | float = inf) DiscreteOutcomeSpace[source]

Returns a stable finite outcome space. If the outcome-space is already finite. It shoud return itself.

Parameters:
  • levels – The levels of discretization of any continuous dimension (or subdimension)

  • max_cardintlity – The maximum cardinality allowed for the resulting outcomespace (if the original OS was infinite). This limitation is NOT applied for outcome spaces that are alredy discretized. See limit_cardinality() for a method to limit the cardinality of an already discrete space

If called again, it should return the same discrete outcome space every time.

to_largest_discrete(levels: int, max_cardinality: int | float = inf, **kwargs) DiscreteOutcomeSpace[source]

Returns self since this space is already discrete.

to_single_issue(numeric: bool = False, stringify: bool = True) CartesianOutcomeSpace[source]

Converts this space to a single-issue outcome space (not implemented for this class).

validate(outcome: tuple) None[source]

Indicates that the outcome is invalid

class negmas.outcomes.ExtendedOutcome(outcome: Outcome | None, outcome_space: OutcomeSpace | None = None, data: dict[str, Any] | None = None)[source]

Bases: object

An outcome with optional data fields.

This class allows offering policies to return additional data alongside the proposed outcome, such as text explanations, reasoning, or metadata.

outcome[source]

The actual outcome tuple representing the proposed offer (if outcome_space is also specified, this is interpreted as preferred offer).

Type:

Outcome | None

outcome_space[source]

An outcome space representing all proposed offers (if more than one).

Type:

OutcomeSpace | None

data[source]

Optional dictionary of additional data. Can contain: - “text”: A text message explaining the offer or providing context. - Any other key-value pairs for custom metadata.

Type:

dict[str, Any] | None

Example

>>> from negmas.outcomes.common import ExtendedOutcome
>>> outcome = (5, 10)  # price=5, quantity=10
>>> extended = ExtendedOutcome(
...     outcome=outcome,
...     data={"text": "I propose this fair price", "confidence": 0.9},
... )
>>> extended.outcome
(5, 10)
>>> extended.data["text"]
'I propose this fair price'

See also

best_for(ufun: BaseUtilityFunction) Outcome | None[source]

Returns the best outcome for the given utility function from the offer.

Parameters:

ufun – The utility function to evaluate outcomes.

data: dict[str, Any] | None[source]
outcome: Outcome | None[source]
outcome_space: OutcomeSpace | None[source]
class negmas.outcomes.IndependentDiscreteIssuesOS(*args, **kwargs)[source]

Bases: Protocol

An Outcome-Space that is constructed from a tuple of DiscreteIssue objects.

issues: tuple[DiscreteIssue, ...][source]
class negmas.outcomes.IndependentIssuesOS(*args, **kwargs)[source]

Bases: Protocol

An Outcome-Space that is constructed from a tuple of Issue objects.

issues: tuple[Issue, ...][source]
class negmas.outcomes.InfiniteIssue[source]

Bases: object

Indicates that the issue is infinite (i.e. one or more of its limits is infinity)

class negmas.outcomes.Issue(values, name: str | None = None)[source]

Bases: HasMinMax, Iterable, ABC

Base class of all issues in NegMAS

property all: Generator[Any, None, None][source]

A generator that generates all possible values.

property cardinality: int | float[source]

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

contains(issue: Issue) bool[source]

Checks weather this issue contains the input issue (i.e. every value in the input issue is in this issue)

classmethod from_dict(d, python_class_identifier='__python_class__')[source]

Constructs an issue from a dict generated using to_dict()

has_finite_limits() bool[source]

Checks whether the minimum and maximum values of the issue are known and are finite

has_limits() bool[source]

Checks whether the minimum and maximum values of the issue are known

intersect(other: Issue)[source]

Returns an issue which is the intersection of the two issues and otherwise is the same as this one

abstractmethod is_continuous() bool[source]

The issue has a continuous set of values. Note that this is different from having values that are real (which is tested using is_float )

is_discrete() bool[source]

Checks whether the issue has a discrete set of values. This is different from is_integer which checks that the values themselves are integers and is_discrete_valued which checks that they are discrete.

is_discrete_valued() bool[source]

Checks that each value of this issue is not a real number

is_finite() bool[source]

Checks whether the issue has a discrete set of values

is_float() bool[source]

Checks that each value of this issue is a real number

is_integer() bool[source]

Checks that each value of this issue is an integer

is_numeric() bool[source]

Checks that each value of this issue is a number

abstractmethod is_valid(v) bool[source]

Checks whether the given value is valid for this issue

abstractmethod ordered_value_generator(n: int | float | None = None, grid=True, compact=False, endpoints=True) Generator[int, None, None][source]

A generator that generates at most n values (in a stable order)

Parameters:
  • n – The number of samples. If inf or None, all values will be generated but when the issue is infinite, it will just fail

  • grid – Sample on a grid (equally distanced as much as possible)

  • compact – If True, the samples will be chosen near each other (see endpoints though)

  • endpoints – If given, the first and last index are guaranteed to be in the samples

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

  • If the order is not defined for this issue, this generator will still generate values in the same order every time it is called.

  • If you need a list then use something like:

>>> from negmas.outcomes import make_issue
>>> list(make_issue(5).value_generator())
[0, 1, 2, 3, 4]
>>> list(int(10 * _) for _ in make_issue((0.0, 1.0)).value_generator(11))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
abstractmethod rand() int | float | str[source]

Picks a random valid value.

abstractmethod rand_invalid()[source]

Pick a random invalid value

abstractmethod rand_outcomes(n: int, with_replacement=False, fail_if_not_enough=False) list[source]

Picks n random valid value (at most).

Parameters:
  • n – The number of outcome values to sample

  • with_replacement – If true, sampling is done with replacement (i.e.repetition is allowed)

  • fail_if_not_enough – If true, raises an exception if it is not possible to sample exactly n values. If false, will sample as many values as possible up to n

Returns:

A list of sampled values

rand_valid()[source]

Generates a random valid value for this issue

to_dict(python_class_identifier='__python_class__')[source]

Converts the issue to a dictionary from which it can be constructed again using Issue.from_dict()

to_discrete(n: int | float | None = 10, grid=True, compact=True, endpoints=True) DiscreteIssue[source]

Converts the issue to a discrete issue by samling from it.

If the issue is already discret it will just return itself. This method cannot be used to reduce the cardinality of a discrete issue.

Parameters:
  • n (int | float | None) – Number of values in the resulting discrete issue. This will be ignored if the issue is already discrete. The only allowed float value is float("inf"). If any other float is passed, it will be silently cast to an int

  • grid (bool) – Sample on a grid

  • compact (bool) – Sample around the center

  • endpoints (bool) – Always incllude minimum and maximum values

property type: str[source]

Returns a nice name for the issue type

abstractmethod value_at(index: int)[source]

Returns the value at the given index of the issue. The same index will have the same values always indepdendent of whether the values of the issue have defined ordering.

abstractmethod value_generator(n: int | float | None = None, grid=True, compact=True, endpoints=True) Generator[Any, None, None][source]

A generator that generates at most n values (in any order)

Parameters:
  • grid – Sample on a grid (equally distanced as much as possible)

  • compact – If True, the samples will be choosen near each other (see endpoints though)

  • endpoints – If given, the first and last index are guaranteed to be in the samples

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 make_issue
>>> list(make_issue(5).value_generator())
[0, 1, 2, 3, 4]
>>> list(int(10 * _) for _ in make_issue((0.0, 1.0)).value_generator(11))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
property value_type[source]

Returns the type of values in this issue

property values[source]

Returns the raw values representation of the issue. Only use if you know what you are doing. To get all the values that can be assigned to this issue use all or generate_values

class negmas.outcomes.OrdinalIssue(values, name: str | None = None)[source]

Bases: Issue, ABC

An Issue that have some defined ordering of outcomes but not necessarily a meaningful difference function between its values.

abstractmethod ordered_value_generator(n: int = 10, grid=True, compact=False, endpoints=True) Generator[Any, None, None][source]

Generate values in a defined order.

Parameters:
  • n – Maximum number of values to generate.

  • grid – If True, generate values on a regular grid.

  • compact – If True, pack values more densely.

  • endpoints – If True, include the boundary values.

Yields:

Values from the issue in order.

negmas.outcomes.Outcome[source]

alias of tuple

class negmas.outcomes.OutcomeSpace(*args, **kwargs)[source]

Bases: Container, Protocol

The base protocol for all outcome spaces.

are_types_ok(outcome: Outcome) bool[source]

Checks if the type of each value in the outcome is correct for the given issue

property cardinality: int | float[source]

The space cardinality = the number of outcomes

cardinality_if_discretized(levels: int, max_cardinality: int | float = inf) int[source]

Returns the cardinality if discretized the given way.

ensure_correct_types(outcome: Outcome) Outcome[source]

Returns an outcome that is guaratneed to have correct types or raises an exception

enumerate_or_sample(levels: int | float = inf, max_cardinality: int | float = inf) Iterable[Outcome][source]

Enumerates all outcomes if possible (i.e. discrete space) or returns max_cardinality different outcomes otherwise

is_discrete() bool[source]

Checks whether there are no continua components of the space

is_finite() bool[source]

Checks whether the space is finite

is_float() bool[source]

Checks whether all values in all outcomes are real

is_integer() bool[source]

Checks whether all values in all outcomes are integers

is_numeric() bool[source]

Checks whether all values in all outcomes are numeric

is_valid(outcome: Outcome) bool[source]

Checks if the given outcome is valid for that outcome space

random_outcome() Outcome[source]

Returns a single random outcome.

sample(n_outcomes: int, with_replacement: bool = False, fail_if_not_enough=False) Iterable[Outcome][source]

Samples up to n_outcomes with or without replacement

to_discrete(levels: int | float = 5, max_cardinality: int | float = inf) DiscreteOutcomeSpace[source]

Returns a stable finite outcome space. If the outcome-space is already finite. It shoud return itself.

Parameters:
  • levels – The levels of discretization of any continuous dimension (or subdimension)

  • max_cardintlity – The maximum cardinality allowed for the resulting outcomespace (if the original OS was infinite). This limitation is NOT applied for outcome spaces that are alredy discretized. See limit_cardinality() for a method to limit the cardinality of an already discrete space

If called again, it should return the same discrete outcome space every time.

to_largest_discrete(levels: int, max_cardinality: int | float = inf, **kwargs) DiscreteOutcomeSpace[source]

Convert to the largest discrete approximation within cardinality limits.

Parameters:
  • levels – Number of discrete levels to sample for each continuous dimension.

  • max_cardinality – Maximum total number of outcomes in the discrete space.

  • **kwargs – Additional keyword arguments passed to the discretization method.

Returns:

A discrete approximation of this outcome space.

negmas.outcomes.PartialOutcomeTuple[source]

alias of tuple

class negmas.outcomes.RangeIssue(values, name=None)[source]

Bases: CardinalIssue

An issue representing a range of values (can be continuous or discrete)

is_valid(v)[source]

Check if valid.

Parameters:

v

class negmas.outcomes.SingletonIssue(value: Any, name: str | None = None)[source]

Bases: DiscreteIssue

An Issue type representing a single fixed value.

This is useful for representing an outcome as an outcome space with a single outcome.

property all: Generator[Any, None, None][source]

Generate all possible values for this singleton issue.

Returns:

Generator yielding the single value

Return type:

Generator[Any, None, None]

contains(issue: Issue) bool[source]

Checks whether this issue contains the input issue.

A singleton issue only contains another issue if that issue has exactly the same single value.

is_continuous() bool[source]

Check if this issue has continuous values.

Returns:

Always False for singleton issues

Return type:

bool

is_uncountable() bool[source]

Check if the issue has uncountably infinite values.

Returns:

Always False for singleton issues

Return type:

bool

is_valid(v) bool[source]

Checks whether the given value equals the singleton value.

rand() Any[source]

Picks a random valid value (always the single value).

rand_invalid() Any[source]

Pick a random invalid value

property type: str[source]

Type of issue.

Returns:

Always returns ‘singleton’ for this issue type

Return type:

str

property value: Any[source]

Returns the single value of this issue.

class negmas.outcomes.SingletonOutcomeSpace(name: str | None = None, path: Path | None = None, constraints: list[Callable[[tuple], bool]] = NOTHING, *, outcome, issue_names: Sequence[str] | None = None)[source]

Bases: DiscreteCartesianOutcomeSpace

A discrete outcome-space representing a single outcome.

This is useful for representing a specific outcome as an outcome space, e.g., for checking containment or performing set operations.

Parameters:
  • outcome – The outcome tuple to represent (keyword-only)

  • issue_names – Optional names for the issues. If None, generates names as issue00, issue01, …

  • name – Optional name for the outcome space

property cardinality: int[source]

Always returns 1 since this space contains exactly one outcome.

contains_os(x: OutcomeSpace) bool[source]

Checks if this singleton space contains another outcome space.

enumerate() Iterable[tuple][source]

Returns an iterable containing the single outcome.

is_valid(outcome: tuple) bool[source]

Checks if the given outcome equals the single outcome in this space.

issue_names: Sequence[str] | None[source]
issues: tuple[SingletonIssue, ...][source]
outcome: tuple[source]
sample(n_outcomes: int, with_replacement: bool = True, fail_if_not_enough=True) Iterable[tuple][source]

Returns the single outcome up to n_outcomes times.

negmas.outcomes.check_one_and_only(outcome_space, issues, outcomes) None[source]

Ensures that one and only one of the three inputs is given (i.e. not None)

negmas.outcomes.check_one_at_most(outcome_space, issues, outcomes) None[source]

Ensures that at most one of the three inputs is given (i.e. not None)

negmas.outcomes.combine_issues(issues: Sequence[Issue], name: str | None = None, keep_value_names=True, issue_sep='_', value_sep='-') Issue | None[source]

Combines multiple issues into a single issue.

Parameters:
  • issues – The issues to be combined

  • name – The name of the resulting issue (If not given, combines input issue names)

  • 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

negmas.outcomes.dict2outcome(d: dict[str, Any] | tuple | None, issues: tuple[str | Issue, ...]) Outcome | None[source]

Converts the outcome to a tuple no matter what was its type

Parameters:
  • d – the dictionary to be converted

  • issues – A list of issues or issue names (as strings) to order the tuple

Remarks:
  • If called with a tuple outcome, it will issue a warning

negmas.outcomes.discretize_and_enumerate_issues(issues: Iterable[Issue], n_discretization: int | None = 10, max_cardinality: int | float | None = None) list[Outcome][source]

Enumerates the outcomes of a list of issues.

Parameters:
  • issues – The list of issues.

  • max_cardinality – The maximum number of outcomes to return

Returns:

list of outcomes of the given type.

negmas.outcomes.ensure_os(outcome_space, issues, outcomes) OutcomeSpace[source]

Returns an outcome space from either an outcome-space, a list of issues, a list of outcomes, or the number of outcomes

Remakrs:
negmas.outcomes.enumerate_discrete_issues(issues: Sequence[DiscreteIssue]) list[Outcome][source]

Enumerates all outcomes of this set of discrete issues if possible.

Parameters:

issues – A list of issues

Returns:

list of outcomes

negmas.outcomes.enumerate_issues(issues: Sequence[Issue], max_cardinality: int | float | None = None) list[Outcome][source]

Enumerates the outcomes of a list of issues.

Parameters:
  • issues – The list of issues.

  • max_cardinality – The maximum number of outcomes to return

Returns:

list of outcomes of the given type.

negmas.outcomes.extract_data(outcome: tuple | ExtendedOutcome | None) dict[str, Any] | None[source]

Extracts the underlying Outcome tuple

negmas.outcomes.extract_outcome(outcome: tuple | ExtendedOutcome | None) tuple | None[source]

Extracts the underlying Outcome tuple

negmas.outcomes.extract_text(outcome: tuple | ExtendedOutcome | None) str | None[source]

Extracts the underlying Outcome tuple

negmas.outcomes.generalized_minkowski_distance(a: Outcome, b: Outcome, outcome_space: OutcomeSpace | None, *, weights: Sequence[float] | None = None, dist_power: float = 2) float[source]

Calculates the difference between two outcomes given an outcome-space (optionally with issue weights). This is defined as the distance.

Parameters:
  • outcome_space – The outcome space used for comparison (If None an apporximate implementation is provided)

  • a – first outcome

  • b – second outcome

  • weights – Issue weights

  • dist_power – The exponent used when calculating the distance

Remarks:

  • Implements the following distance measure:

    \[d(a, b) = \left( \sum_{i=1}^{N} w_i {\left| a_i - b_i \right|}^p \right)^{frac{1}{p}}\]

    where $a, b$ are the outocmes, $x_i$ is value for issue $i$ of outcoem $x$, $w_i$ is the weight of issue $i$ and $p$ is the dist_power passsed. Categorical issue differences is defined as $1$ if the values are not equal and $0$ otherwise.

  • Becomes the Euclidean distance if all issues are numeric and no weights are given

  • You can control the power:

    • Setting it to 1 is the city-block distance

    • Setting it to 0 is the maximum issue difference

negmas.outcomes.generate_issues(params: Sequence[int | list[str] | tuple[int, int] | Callable | tuple[float, float]], counts: list[int] | None = None, names: list[str] | None = None) tuple[Issue, ...][source]

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

Parameters:
  • params – 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’]

negmas.outcomes.issues_from_genius(file_name: PathLike | str, safe_parsing=True, n_discretization: int | None = None) tuple[Sequence[Issue] | None, Sequence[str] | None][source]

Imports a the domain issues from a GENIUS XML file.

Parameters:
  • file_name (str) – File name to import from

  • safe_parsing – Add more checks to parsing

  • n_discretization – Number of discretization levels per issue

Returns:

  • tuple[Issue, …] containing the issues

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

Return type:

A tuple of two optional lists

Examples

>>> from pathlib import Path
>>> import negmas
>>> issues, _ = issues_from_genius(
...     file_name=Path(negmas.__file__).parent.parent.parent
...     / "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

negmas.outcomes.issues_from_geniusweb(file_name: PathLike | str, safe_parsing=True, n_discretization: int | None = None) tuple[Sequence[Issue] | None, Sequence[str] | None][source]

Imports a the domain issues from a GENIUS XML file.

Parameters:
  • file_name (str) – File name to import from

  • safe_parsing – Add more checks to parsing

  • n_discretization – Number of discretization levels per issue

Returns:

  • tuple[Issue, …] containing the issues

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

Return type:

A tuple of two optional lists

Examples

>>> from pathlib import Path
>>> import negmas
>>> issues, _ = issues_from_genius(
...     file_name=Path(negmas.__file__).parent.parent.parent
...     / "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

negmas.outcomes.issues_from_geniusweb_json_str(json_str: str, safe_parsing=True, n_discretization: int | None = None) tuple[Sequence[Issue] | None, Sequence[str] | None][source]

Exports a list/dict of issues from a GeniusWeb json file.

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

  • safe_parsing (bool) – Turn on extra checks

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

  • values (number of)

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

Returns:

  • tuple[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’

negmas.outcomes.issues_from_outcomes(outcomes: Sequence[Outcome] | int, numeric_as_ranges: bool = True, issue_names: list[str] | None = None) tuple[DiscreteIssue][source]

Create a set of issues given some outcomes.

Parameters:
  • outcomes – A list of outcomes or the number of outcomes

  • issue_names – If given, will be used as issue names, otherwise random issue names will be used

  • 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

negmas.outcomes.issues_from_xml_str(xml_str: str, safe_parsing=True, n_discretization: int | None = None) tuple[Sequence[Issue] | None, Sequence[str] | None][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

  • safe_parsing (bool) – Turn on extra checks

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

  • values (number of)

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

Returns:

  • tuple[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

>>> from pathlib import Path
>>> import negmas
>>> domain_file_name = (
...     Path(negmas.__file__).parent.parent.parent
...     / "tests/data/Laptop/Laptop-C-domain.xml"
... )
>>> with open(domain_file_name, "r") as ff:
...     issues, _ = issues_from_xml_str(ff.read())
>>> print([_.cardinality for _ in issues])
[3, 3, 3]
>>> domain_file_name = (
...     Path(negmas.__file__).parent.parent.parent
...     / "tests/data/fuzzyagent/single_issue_domain.xml"
... )
>>> with open(domain_file_name, "r") as ff:
...     issues, _ = issues_from_xml_str(ff.read())
>>> len(issues)
1
>>> type(issues)
<class 'tuple'>
>>> str(issues[0]).split(": ")[-1]
'(10.0, 40.0)'
>>> print([_.cardinality for _ in issues])
[inf]
negmas.outcomes.issues_to_genius(issues: Sequence[Issue], file_name: PathLike | str) 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 tuple[Issue, …] or dict[Issue]

Examples

>>> from pathlib import Path
>>> import negmas
>>> issues, _ = issues_from_genius(
...     file_name=Path(negmas.__file__).parent.parent.parent
...     / "tests/data/Laptop/Laptop-C-domain.xml"
... )
>>> issues_to_genius(
...     issues=issues,
...     file_name=Path(negmas.__file__).parent.parent.parent
...     / "tests/data/LaptopConv/Laptop-C-domain.xml",
... )
>>> issues2, _ = issues_from_genius(
...     file_name=Path(negmas.__file__).parent.parent.parent
...     / "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, _ = issues_from_genius(
...     file_name=Path(negmas.__file__).parent.parent.parent
...     / "tests/data/Laptop/Laptop-C-domain.xml"
... )
>>> print([list(issue.all) for issue in issues])
[['Dell', 'Macintosh', 'HP'], ['60 Gb', '80 Gb', '120 Gb'], ["19'' LCD", "20'' LCD", "23'' LCD"]]
Remarks:

See from_xml_str for all the parameters

negmas.outcomes.issues_to_xml_str(issues: Sequence[Issue]) str[source]

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

Examples

>>> issues = [
...     make_issue(values=10, name="i1"),
...     make_issue(values=["a", "b", "c"], name="i2"),
...     make_issue(values=(2.5, 3.5), name="i3"),
... ]
>>> s = issues_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="integer" index="1" name="i1" type="integer" vtype="integer" lowerbound="0" upperbound="9" />
    <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, _ = issues_from_xml_str(s)
>>> print([_.__class__.__name__ for _ in issues2])
['ContiguousIssue', 'CategoricalIssue', 'ContinuousIssue']
>>> print(len(issues2))
3
>>> print([str(_) for _ in issues2])
['i1: (0, 9)', "i2: ['a', 'b', 'c']", 'i3: (2.5, 3.5)']
>>> print([_.values for _ in issues2])
[(0, 9), ['a', 'b', 'c'], (2.5, 3.5)]
negmas.outcomes.make_issue(values, *args, optional: bool = False, **kwargs)[source]

A factory for creating issues based on values type as well as the base class of all issues

Parameters:
  • values – Possible values for the issue

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

  • optional – If given an OptionalIssue will be created

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). Depending on the types in the list, a different issue type will be created:

      • integers -> CardinalIssue

      • a type that supports subtraction -> OrdinalIssue (with defined order and defined difference between values)

      • otherwise -> CategoricalIssue (without defined order or difference between values)

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

    • Tuple[ int , int ] : This is a ContiguousIssue that can take any integer value in the given limits (min, max)

    • Tuple[ float , float ] : This is a ContinuousIssue that can take any real value in the given limits (min, max)

    • Tuple[ int , inf ] : This is a CountableInfiniteIssue that can take any integer value in the given limits

    • Tuple[ -inf , int ] : This is a CountableInfiniteIssue that can take any integer value in the given limits

    • Tuple[ float , inf ] : This is a ContinuousInfiniteIssue that can take any real value in the given limits

    • Tuple[ -inf , float ] : This is a ContinuousInfiniteIssue that can take any real value in the given limits

    • 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. Most operations are not supported on this issue type.

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

negmas.outcomes.make_os(issues: Sequence[Issue] | None = None, outcomes: Sequence[tuple] | None = None, name: str | None = None, path: Path | None = None) CartesianOutcomeSpace[source]

A factory to create outcome-spaces from lists of Issue s or Outcome s.

Remarks:

negmas.outcomes.min_dist(test_outcome: Outcome, outcomes: Sequence[Outcome], outcome_space: OutcomeSpace | None, distance_fun: DistanceFun = <function generalized_minkowski_distance>, **kwargs) float[source]

Minimum distance between an outcome and a set of outcomes in an outcome-spaceself.

Parameters:
  • test_outcome – The outcome tested

  • outcomes – A sequence of outcomes to compare to

  • outcome_space – The outcomespace used for comparison

  • distance_fun – The distance function

  • kwargs – Paramters to pass to the distance function

See also

generalized_euclidean_distance

negmas.outcomes.num_outcomes(issues: Sequence[Issue]) int | float[source]

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

negmas.outcomes.os_difference(os1: OutcomeSpace, os2: OutcomeSpace, name: str | None = None) EnumeratingOutcomeSpace[source]

Returns the difference of two outcome spaces (os1 - os2).

Parameters:
  • os1 – First outcome space

  • os2 – Second outcome space

  • name – Optional name for the result

Returns:

An EnumeratingOutcomeSpace containing outcomes in os1 but not in os2

negmas.outcomes.os_intersection(os1: OutcomeSpace, os2: OutcomeSpace, name: str | None = None) EnumeratingOutcomeSpace[source]

Returns the intersection of two outcome spaces.

Parameters:
  • os1 – First outcome space

  • os2 – Second outcome space

  • name – Optional name for the result

Returns:

An EnumeratingOutcomeSpace containing outcomes in both spaces

negmas.outcomes.os_or_none(outcome_space, issues, outcomes) OutcomeSpace | None[source]

Returns an outcome space from either an outcome-space, a list of issues, a list of outcomes, or the number of outcomes

Remakrs:
negmas.outcomes.os_union(os1: OutcomeSpace, os2: OutcomeSpace, name: str | None = None) EnumeratingOutcomeSpace[source]

Returns the union of two outcome spaces.

Parameters:
  • os1 – First outcome space

  • os2 – Second outcome space

  • name – Optional name for the result

Returns:

An EnumeratingOutcomeSpace containing all outcomes in either space

negmas.outcomes.outcome2dict(outcome: None, issues: Sequence[str | Issue]) None[source]
negmas.outcomes.outcome2dict(outcome: Outcome, issues: Sequence[str | Issue]) dict[str, Any]

Converts the outcome to a dict no matter what was its type.

Parameters:
  • outcome – The outcome to be converted (as a tuple)

  • issues – The issues/issue names used as dictionary keys in the output

Remarks:
  • If called with a dict that is already converted, it will just return it.

  • None is converted to None

Examples

>>> from negmas import make_issue
>>> issues = [make_issue(10, "price"), make_issue(5, "quantity")]
>>> outcome2dict((3, 4), issues=issues)
{'price': 3, 'quantity': 4}

You can also use issue names without creating Issue objects >>> issues = [“price”, “quantity”] >>> outcome2dict((3, 4), issues=issues) {‘price’: 3, ‘quantity’: 4}

Trying to convert an already converted outcome does nothing >>> issues = [“price”, “quantity”] >>> outcome2dict(outcome2dict((3, 4), issues=issues), issues=issues) {‘price’: 3, ‘quantity’: 4}

negmas.outcomes.outcome_in_range(outcome: Outcome, outcome_range: OutcomeRange, *, strict=False, fail_incomplete=False) bool[source]

Tests that the outcome is contained within the given range of outcomes.

An outcome range defines a value or a range of values for each issue.

Parameters:
  • outcome – “Outcome” being tested

  • outcome_range – “Outcome” range being tested against

  • strict – Whether to enforce that all issues in the outcome must be mentioned in the outcome_range

  • fail_incomplete – If True then outcomes that do not sepcify a value for all keys in the outcome_range

  • falling (will be considered not falling within it. If False then these outcomes will be considered)

  • range (within the range given that the values for the issues mentioned in the outcome satisfy the)

  • constraints.

Examples

>>> outcome_range = {
...     "price": (0.0, 2.0),
...     "distance": [0.3, 0.4],
...     "type": ["a", "b"],
...     "area": 3,
... }
>>> outcome_range_2 = {
...     "price": [(0.0, 1.0), (1.5, 2.0)],
...     "area": [(3, 4), (7, 9)],
... }
>>> outcome_in_range({"price": 3.0}, outcome_range)
False
>>> outcome_in_range({"date": "2018.10.4"}, outcome_range)
True
>>> outcome_in_range({"date": "2018.10.4"}, outcome_range, strict=True)
False
>>> outcome_in_range({"area": 3}, outcome_range, fail_incomplete=True)
False
>>> outcome_in_range({"area": 3}, outcome_range)
True
>>> outcome_in_range({"type": "c"}, outcome_range)
False
>>> outcome_in_range({"type": "a"}, outcome_range)
True
>>> outcome_in_range({"date": "2018.10.4"}, outcome_range_2)
True
>>> outcome_in_range({"area": 3.1}, outcome_range_2)
True
>>> outcome_in_range({"area": 3}, outcome_range_2)
False
>>> outcome_in_range({"area": 5}, outcome_range_2)
False
>>> outcome_in_range({"price": 0.4}, outcome_range_2)
True
>>> outcome_in_range({"price": 0.4}, outcome_range_2, fail_incomplete=True)
False
>>> outcome_in_range({"price": 1.2}, outcome_range_2)
False
>>> outcome_in_range({"price": 0.4, "area": 3.9}, outcome_range_2)
True
>>> outcome_in_range({"price": 0.4, "area": 10}, outcome_range_2)
False
>>> outcome_in_range({"price": 1.2, "area": 10}, outcome_range_2)
False
>>> outcome_in_range({"price": 1.2, "area": 4}, outcome_range_2)
False
>>> outcome_in_range({"type": "a"}, outcome_range_2)
True
>>> outcome_in_range({"type": "a"}, outcome_range_2, strict=True)
False
>>> outcome_range = {"price": 10}
>>> outcome_in_range({"price": 10}, outcome_range)
True
>>> outcome_in_range({"price": 11}, outcome_range)
False
Returns:

Success or failure

Return type:

bool

Remarks:

Outcome ranges specify regions in an outcome space. They can have any of the following conditions:

  • A key/issue not mentioned in the outcome range does not add any constraints meaning that All values are acceptable except if strict == True. If strict == True then NO value will be accepted for issues not in the outcome_range.

  • A key/issue with the value None in the outcome range means All values on this issue are acceptable. This is the same as having this key/issue removed from the outcome space

  • A key/issue withe the value [] (empty list) accepts NO outcomes

  • A key/issue with a single value means that it is the only one acceptable

  • A key/issue with a single 2-items tuple (min, max) means that any value within that range is acceptable.

  • A key/issue with a list of values means an output is acceptable if it falls within the condition specified by any of the values in the list (list == union). Each such value can be a single value, a 2-items tuple or another list. Notice that lists of lists can always be combined into a single list of values

negmas.outcomes.outcome_is_complete(outcome: Outcome, issues: tuple[Issue, ...]) bool[source]

Tests that the outcome is valid and complete.

Examples

>>> from negmas.outcomes import make_issue
>>> issues = [make_issue((0.5, 2.0), 'price'), make_issue(['2018.10.'+ str(_) for _ in range(1, 4)], 'date')                , make_issue(20, 'count')]
>>> for _ in issues: print(_)
price: (0.5, 2.0)
date: ['2018.10.1', '2018.10.2', '2018.10.3']
count: (0, 19)
>>> print([outcome_is_complete({'price':3.0}, issues), outcome_is_complete({'date': '2018.10.4'}, issues)            , outcome_is_complete({'count': 21}, issues)])
[False, False, False]
>>> valid_incomplete = {'price': 1.9}
>>> print(outcome_is_complete(valid_incomplete, issues))
False
>>> valid_incomplete.update({'date': '2018.10.2', 'count': 5})
>>> print(outcome_is_complete(valid_incomplete, issues))
True
>>> invalid = {'price': 2000, 'date': '2018.10.2', 'count': 5}
>>> print(outcome_is_complete(invalid, issues))
False
>>> invalid = {'unknown': 2000, 'date': '2018.10.2', 'count': 5}
>>> print(outcome_is_complete(invalid, issues))
False
Args:

outcome: outcome tested which much contain valid values all issues if it is to be considered complete. issues: issues

Returns:

If return_problem is True then a second return value contains a string with

reason of failure

Return type:

Union[bool, Tuple[bool, str]]

negmas.outcomes.outcome_is_valid(outcome: Outcome, issues: tuple[Issue, ...]) bool[source]

Test validity of an outcome given a set of issues.

Examples

>>> from negmas.outcomes import make_issue
>>> issues = [make_issue((0.5, 2.0), 'price'), make_issue(['2018.10.'+ str(_) for _ in range(1, 4)], 'date')                , make_issue(20, 'count')]
>>> for _ in issues: print(_)
price: (0.5, 2.0)
date: ['2018.10.1', '2018.10.2', '2018.10.3']
count: (0, 19)
>>> print([outcome_is_valid({'price':3.0}, issues), outcome_is_valid({'date': '2018.10.4'}, issues)            , outcome_is_valid({'count': 21}, issues)])
[False, False, False]
>>> valid_incomplete = {'price': 1.9}
>>> print(outcome_is_valid(valid_incomplete, issues))
False
>>> print(outcome_is_complete(valid_incomplete, issues))
False
>>> valid_incomplete.update({'date': '2018.10.2', 'count': 5})
>>> print(outcome_is_complete(valid_incomplete, issues))
True
Parameters:
  • outcome – outcome tested.

  • issues – issues

negmas.outcomes.outcome_types_are_ok(outcome: Outcome, issues: tuple[Issue, ...]) bool[source]

Checks that the types of all issue values in the outcome are correct

negmas.outcomes.sample_issues(issues: Sequence[Issue], n_outcomes: int, with_replacement: bool = True, fail_if_not_enough=True) Iterable[Outcome][source]

Samples some outcomes from the outcome space defined by the list of issues.

Parameters:
  • issues – list of issues to sample from

  • n_outcomes – The number of outcomes required

  • 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 make_issue
>>> issues = [
...     make_issue(name="price", values=(0.0, 3.0)),
...     make_issue(name="quantity", values=10),
... ]

Sampling outcomes as tuples

>>> samples = sample_issues(issues=issues, n_outcomes=10)
>>> len(samples) == 10
True
>>> type(samples[0]) == tuple
True
negmas.outcomes.sample_outcomes(issues: Sequence[Issue], n_outcomes: int | None = None, min_per_dim: int = 5, expansion_policy=None) list[Outcome][source]

Discretizes the issue space and returns either a predefined number of outcomes or uniform samples.

Parameters:
  • issues – The issues describing the issue space to be discretized

  • n_outcomes – If None then exactly min_per_dim bins will be used for every continuous dimension and all outcomes

  • returned (will be)

  • min_per_dim – Max levels of discretization per dimension

  • expansion_policy – None or ‘repeat’ or ‘null’ or ‘no’. If repeat, then some of the outcomes will be repeated

  • than (if None or 'no' then no expansion will happen if the total number of outcomes is less)

  • n_outcomes – If ‘null’ then expansion will be with None values

Returns:

list of outcomes

Examples

enumberate the whole space

>>> from negmas.outcomes import make_issue
>>> issues = [
...     make_issue(values=(0.0, 1.0), name="Price"),
...     make_issue(values=["a", "b"], name="Name"),
... ]
>>> sample_outcomes(issues=issues)
[(0.0, 'a'), (0.0, 'b'), (0.25, 'a'), (0.25, 'b'), (0.5, 'a'), (0.5, 'b'), (0.75, 'a'), (0.75, 'b'), (1.0, 'a'), (1.0, 'b')]

enumerate with sampling for very large space (we have 10 outcomes in the discretized space)

>>> from negmas.outcomes import make_issue
>>> issues = [
...     make_issue(values=(0.0, 1.0), name="Price"),
...     make_issue(values=["a", "b"], name="Name"),
... ]
>>> issues[0].is_continuous()
True
>>> sampled = sample_outcomes(issues=issues, n_outcomes=5)
>>> len(sampled)
5
>>> len(set(sampled))
5
>>> from negmas.outcomes import make_issue
>>> issues = [
...     make_issue(values=(0, 1), name="Price"),
...     make_issue(values=["a", "b"], name="Name"),
... ]
>>> issues[0].is_continuous()
False
>>> sampled = sample_outcomes(issues=issues, n_outcomes=5)
>>> len(sampled)
4
>>> len(set(sampled))
4