negotiation_platform.metrics package

class negotiation_platform.metrics.UtilitySurplusMetric(config: Dict[str, Any] | None = None)[source]

Bases: BaseMetric

Metric for calculating utility surplus achieved by each player in negotiations.

The UtilitySurplusMetric quantifies how much better (or worse) each player performed compared to their Best Alternative to Negotiated Agreement (BATNA). This provides a normalized measure of negotiation success that accounts for each player’s outside options.

Calculation Method:

For each player: Final Utility - BATNA Utility = Surplus

The metric handles different game types automatically: - company_car: Subtracts BATNA from absolute monetary utilities - integrative_negotiations: Subtracts BATNA from point-based utilities - resource_allocation: Subtracts BATNA from resource-based utilities

Special Cases:
  • No Agreement: All players receive 0.0 surplus (stayed at BATNA)

  • Missing BATNA: Uses raw utility as fallback with warning

  • Missing Player: Assigns 0.0 surplus for missing players

Value Interpretation:
  • > 0: Player improved upon their BATNA through negotiation

  • = 0: Player achieved exactly their BATNA value

  • < 0: Player accepted worse outcome than their BATNA

Example

>>> metric = UtilitySurplusMetric()
>>> game_result = GameResult(
...     final_scores={"player1": 45000, "player2": 38000},
...     game_data={
...         "agreement_reached": True,
...         "batnas_at_agreement": {"player1": 41000, "player2": 35000}
...     }
... )
>>> surplus = metric.calculate(game_result, [])
>>> print(surplus)
{"player1": 4000.0, "player2": 3000.0}
Inherits from BaseMetric
- metric_name

“Utility Surplus”

- config

Optional configuration parameters

__init__(config: Dict[str, Any] | None = None)[source]

Initialize the Utility Surplus metric with optional configuration.

Creates a new UtilitySurplusMetric instance with the standard name “Utility Surplus” and any provided configuration parameters.

Parameters:

config (Dict[str, Any], optional) –

Configuration parameters for metric behavior. Currently unused but reserved for future enhancements such as:

  • normalization_method: How to scale surplus values

  • missing_batna_strategy: Handling of missing BATNA data

  • precision: Decimal places for calculations

Defaults to None (empty configuration).

Example

>>> # Basic initialization
>>> metric = UtilitySurplusMetric()
>>> # With configuration (future use)
>>> config = {"precision": 2, "normalize": True}
>>> metric = UtilitySurplusMetric(config)
calculate(game_result: GameResult, actions_history: List[PlayerAction]) Dict[str, float][source]

Calculate utility surplus for each player based on final outcomes and BATNA values.

Computes how much each player improved (or worsened) their position compared to their Best Alternative to Negotiated Agreement. The calculation method adapts automatically to different game types and utility scales.

Parameters:
  • game_result (GameResult) – Complete game outcome containing: - final_scores: Dict mapping player IDs to final utility values - game_data: Game state including agreement status and BATNA values - players: List of all participating players

  • actions_history (List[PlayerAction]) – Complete action log (unused for this metric but required by BaseMetric interface).

Returns:

Dictionary mapping each player ID to their utility

surplus value. Positive values indicate improvement over BATNA, negative values indicate worse outcomes than BATNA.

Return type:

Dict[str, float]

Calculation Logic:
  1. Check if agreement was reached (no agreement = 0 surplus for all)

  2. For each player, extract final utility and BATNA value

  3. Calculate surplus as: Final Utility - BATNA Utility

  4. Handle missing data with appropriate fallbacks

Game Type Handling:
  • company_car: Uses absolute monetary values with time-decayed BATNAs

  • integrative_negotiations: Uses point-based utilities with fixed BATNAs

  • resource_allocation: Uses resource-based utilities with team BATNAs

  • unknown: Generic handling with BATNA detection

Special Cases:
  • No Agreement: Returns 0.0 for all players (stayed at BATNA)

  • Missing BATNA: Uses raw utility with warning message

  • Missing Player: Returns 0.0 for players not in final_scores

Example

>>> # Company car negotiation
>>> game_result = GameResult(
...     players=["buyer", "seller"],
...     final_scores={"buyer": 43000, "seller": 43000},
...     game_data={
...         "agreement_reached": True,
...         "batnas_at_agreement": {"buyer": 41000, "seller": 39000}
...     }
... )
>>> metric = UtilitySurplusMetric()
>>> surplus = metric.calculate(game_result, [])
>>> print(surplus)
{'buyer': 2000.0, 'seller': 4000.0}
Error Handling:
  • Missing final_scores: Returns 0.0 for affected players

  • Missing BATNA data: Falls back to raw utility with logging

  • Invalid game_data: Graceful degradation with warnings

get_description() str[source]

Provide a comprehensive description of the Utility Surplus metric.

Returns:

Detailed explanation of metric purpose, calculation, and interpretation.

Return type:

str

class negotiation_platform.metrics.RiskMinimizationMetric(config: Dict[str, Any] | None = None)[source]

Bases: BaseMetric

Calculates risk minimization: percentage of deals that are worse than BATNA Lower percentages indicate better risk management

__init__(config: Dict[str, Any] | None = None)[source]

Initialize the Risk Minimization metric with optional configuration.

Creates a new RiskMinimizationMetric instance that evaluates players’ risk management behavior during negotiations by analyzing proposal patterns relative to BATNA thresholds.

Parameters:

config (Dict[str, Any], optional) –

Configuration parameters for metric behavior. Currently unused but reserved for future enhancements such as:

  • risk_threshold: Custom risk tolerance levels

  • weighting_scheme: How to weight different risk factors

  • time_horizon: Number of rounds to analyze

Defaults to None (empty configuration).

Example

>>> # Basic initialization
>>> metric = RiskMinimizationMetric()
>>> # With configuration (future use)
>>> config = {"risk_threshold": 0.05, "weighting": "exponential"}
>>> metric = RiskMinimizationMetric(config)

Note

Risk minimization analysis adapts automatically to different game types (price bargaining, resource allocation, integrative).

calculate(game_result: GameResult, actions_history: List[PlayerAction]) Dict[str, float][source]

Calculate risk minimization percentage for each player based on proposal behavior.

Analyzes how well each player managed risk by examining the percentage of proposals that were worse than their BATNA threshold. Lower percentages indicate better risk management and more conservative negotiation strategies.

Parameters:
  • game_result (GameResult) – Complete game outcome containing: - game_data: Game state with BATNA values and agreement status - final_scores: Final utility outcomes for all players - players: List of all participating players

  • actions_history (List[PlayerAction]) – Complete chronological log of all actions taken during the negotiation, used to analyze proposal patterns and risk-taking behavior.

Returns:

Dictionary mapping each player ID to their risk

minimization percentage (0.0-100.0). Lower values indicate better risk management: - 0.0: Perfect risk management (no risky proposals) - 50.0: Moderate risk management (half proposals risky) - 100.0: Poor risk management (all proposals risky)

Return type:

Dict[str, float]

Calculation Logic:
  1. Adapts automatically to game type (price bargaining, resource allocation, integrative)

  2. For each player, counts proposals worse than time-adjusted BATNA

  3. Calculates percentage: (risky_proposals / total_proposals) * 100

  4. Accounts for BATNA decay over negotiation rounds

Example

>>> result = metric.calculate(game_result, actions_history)
>>> print(result)
{'player1': 25.0, 'player2': 10.0}  # player2 managed risk better

Note

Time-adjusted BATNA calculations account for deadline pressure and opportunity cost changes throughout the negotiation.

get_description() str[source]

Provides a comprehensive description of the Risk Minimization metric.

This method returns a detailed explanation of how the Risk Minimization metric evaluates negotiation performance by measuring the percentage of proposed deals or offers that remain within BATNA (Best Alternative to a Negotiated Agreement) limits.

Returns:

A multi-line string containing:
  • Metric definition and purpose

  • Mathematical formula for calculation

  • Interpretation guide with example percentages

  • Game-specific application rules

  • Risk management quality indicators

Return type:

str

Note

The description includes specific guidance for different negotiation contexts, such as price bargaining versus multi-issue negotiations, helping users understand when and how the metric applies.

class negotiation_platform.metrics.DeadlineSensitivityMetric(config: Dict[str, Any] | None = None)[source]

Bases: BaseMetric

Simple deadline sensitivity: 100 if agreement reached, 0 otherwise Measures whether deadline pressure resulted in any deal

__init__(config: Dict[str, Any] | None = None)[source]

Initialize the Deadline Sensitivity metric with optional configuration.

Creates a new DeadlineSensitivityMetric instance that measures how effectively players respond to deadline pressure during negotiations. This metric evaluates whether time constraints motivate agreement-seeking behavior and successful negotiation completion.

Parameters:

config (Dict[str, Any], optional) –

Configuration parameters for metric behavior. Currently unused but reserved for future enhancements such as:

  • deadline_threshold: Minimum rounds for sensitivity analysis

  • pressure_weighting: How to weight early vs. late round behavior

  • completion_bonus: Additional scoring for successful agreements

Defaults to None (empty configuration).

Example

>>> # Basic initialization
>>> metric = DeadlineSensitivityMetric()
>>> # With configuration (future use)
>>> config = {"threshold": 3, "weighting": "exponential"}
>>> metric = DeadlineSensitivityMetric(config)

Note

This metric uses a simplified binary approach: 100 points for successful agreements, 0 points for failed negotiations.

calculate(game_result: GameResult, actions_history: List[PlayerAction]) Dict[str, float][source]

Calculate deadline sensitivity score for each player based on negotiation completion.

Measures how effectively players respond to deadline pressure by evaluating whether they successfully reach agreements within the time constraints. Uses a simplified binary scoring system that rewards negotiation completion.

Parameters:
  • game_result (GameResult) – Complete game outcome containing: - game_data: Game state with agreement status and round information - players: List of all participating players - final_scores: Not used for this metric

  • actions_history (List[PlayerAction]) – Complete action log (unused for this metric but required by BaseMetric interface).

Returns:

Dictionary mapping each player ID to their deadline

sensitivity score: - 100.0: Successful agreement reached (deadline pressure effective) - 0.0: No agreement reached (deadline pressure ineffective)

Return type:

Dict[str, float]

Scoring Logic:
  • Binary evaluation: success (100) vs. failure (0)

  • All players receive same score based on overall negotiation outcome

  • Future versions may incorporate more nuanced time-based analysis

Example

>>> result = metric.calculate(game_result, actions_history)
>>> print(result)
{'player1': 100.0, 'player2': 100.0}  # Both succeeded under deadline

Note

This simplified approach focuses on outcome rather than process. Future enhancements may analyze proposal timing and urgency patterns.

get_description() str[source]

Provides a comprehensive description of the Deadline Sensitivity metric.

This method returns a detailed explanation of how the Deadline Sensitivity metric evaluates the effectiveness of time pressure in driving negotiation outcomes by measuring whether agreements are successfully reached before deadlines expire.

Returns:

A multi-line string containing:
  • Metric definition and deadline pressure assessment

  • Binary scoring formula (100 for agreement, 0 for failure)

  • Interpretation of deadline effectiveness

  • Time pressure impact on negotiation dynamics

  • Success/failure outcome indicators

Return type:

str

Note

This metric is particularly useful for analyzing how time constraints influence negotiator behavior and whether deadline pressure creates the intended motivation to reach agreements.

class negotiation_platform.metrics.FeasibilityMetric(config: Dict[str, Any] | None = None)[source]

Bases: BaseMetric

Calculates feasibility: whether the agreement is actually possible given constraints Binary metric: 1.0 if feasible, 0.0 if not feasible

__init__(config: Dict[str, Any] | None = None)[source]

Initialize the Feasibility metric with optional configuration.

Creates a new FeasibilityMetric instance that evaluates whether negotiated agreements are actually achievable given game constraints and player limitations. This binary metric helps identify unrealistic or impossible negotiation outcomes.

Parameters:

config (Dict[str, Any], optional) –

Configuration parameters for metric behavior. Currently unused but reserved for future enhancements such as:

  • constraint_tolerance: Flexibility in feasibility checking

  • validation_mode: Strict vs. lenient constraint enforcement

  • custom_constraints: Additional feasibility rules

Defaults to None (empty configuration).

Example

>>> # Basic initialization
>>> metric = FeasibilityMetric()
>>> # With configuration (future use)
>>> config = {"tolerance": 0.05, "mode": "strict"}
>>> metric = FeasibilityMetric(config)

Note

Feasibility checking adapts automatically to different game types and their specific constraint systems.

calculate(game_result: GameResult, actions_history: List[PlayerAction]) Dict[str, float][source]

Calculate feasibility score for each player’s perspective on the negotiated agreement.

Evaluates whether the final negotiated agreement is actually achievable given game constraints, player resources, and external limitations. Returns binary scores indicating feasibility from each player’s viewpoint.

Parameters:
  • game_result (GameResult) – Complete game outcome containing: - game_data: Game state with agreement details and constraints - final_scores: Final utility outcomes for validation - players: List of all participating players

  • actions_history (List[PlayerAction]) – Complete action log (unused for this metric but required by BaseMetric interface).

Returns:

Dictionary mapping each player ID to their feasibility

score as a binary value: - 1.0: Agreement is feasible from this player’s perspective - 0.0: Agreement is not feasible or no agreement reached

Return type:

Dict[str, float]

Feasibility Criteria (Game-Specific):
  • Price Bargaining: Agreed price within BATNA constraints

  • Resource Allocation: Total resources don’t exceed available supply

  • Integrative: All issue selections are valid and achievable

Example

>>> result = metric.calculate(game_result, actions_history)
>>> print(result)
{'buyer': 1.0, 'seller': 1.0}  # Feasible for both parties

Note

Different players may have different feasibility scores if the agreement violates constraints for some but not all participants.

get_description() str[source]

Provides a comprehensive description of the Feasibility metric.

This method returns a detailed explanation of how the Feasibility metric evaluates whether negotiated agreements can be realistically implemented given the constraints, resources, and time pressures present in the negotiation scenario.

Returns:

A multi-line string containing:
  • Metric definition and implementability assessment

  • Binary scoring system (1.0 for feasible, 0.0 for infeasible)

  • Game-specific feasibility validation criteria

  • Constraint categories and resource limitations

  • Time pressure and BATNA decay considerations

Return type:

str

Note

The description covers various negotiation contexts including resource allocation, budget constraints, compatibility requirements, and acceptable range validations across different game types.

class negotiation_platform.metrics.GameResult(game_id: str, players: List[str], winner: str | None, final_scores: Dict[str, float], total_rounds: int, game_data: Dict[str, Any], success: bool)[source]

Bases: object

Data structure containing the complete outcome and results of a negotiation game.

GameResult serves as the authoritative record of a completed negotiation, containing all final state information needed for analysis, metrics calculation, and reporting. It provides a standardized format for game outcomes across different negotiation types.

game_id

Unique identifier for this specific game session. Used to correlate results with logs and analysis data.

Type:

str

players

Complete list of all players who participated. Maintains original player order for consistent analysis.

Type:

List[str]

winner

Identifier of the winning player, if applicable. None for games without clear winners (mutual agreements, ties, etc.). Some games may have multiple winners or no winner concept.

Type:

Optional[str]

final_scores

Final scores for each player. Maps player_id to their game-specific score. Score interpretation varies by game type (utility values, points, satisfaction ratings, etc.).

Type:

Dict[str, float]

total_rounds

Total number of negotiation rounds completed. Includes all rounds from game start to termination.

Type:

int

game_data

Complete final game state and additional data. Contains game-specific information such as: - final_agreement: Terms of any reached agreement - batna_values: Best alternatives for each player - resource_allocations: Final resource distributions - negotiation_history: Detailed interaction log

Type:

Dict[str, Any]

success

Whether the game completed successfully. True for normal completion (agreement or deadline reached). False for abnormal termination (errors, rule violations, crashes).

Type:

bool

Example

>>> result = GameResult(
...     game_id="session_2023_001",
...     players=["model_a", "model_b"],
...     winner="model_a",
...     final_scores={"model_a": 8.5, "model_b": 6.2},
...     total_rounds=4,
...     game_data={"agreement_reached": True, "final_price": 43500},
...     success=True
... )
>>> print(result.final_scores["model_a"])
8.5
Usage:

GameResult objects are created by game implementations upon completion and consumed by the metrics system, reporting tools, and analysis scripts. They provide the primary interface between game execution and result analysis.

game_id: str
players: List[str]
winner: str | None
final_scores: Dict[str, float]
total_rounds: int
game_data: Dict[str, Any]
success: bool
__init__(game_id: str, players: List[str], winner: str | None, final_scores: Dict[str, float], total_rounds: int, game_data: Dict[str, Any], success: bool) None
class negotiation_platform.metrics.PlayerAction(player_id: str, action_type: str, action_data: Dict[str, Any], timestamp: float, round_number: int)[source]

Bases: object

Data structure representing a single player action within a negotiation game.

PlayerAction serves as a standardized container for all player interactions during negotiations. It captures both the action content and contextual metadata necessary for game processing and analysis.

player_id

Unique identifier of the player who took this action. Must match one of the registered players in the game.

Type:

str

action_type

Category or type of action taken. Common types include: - “proposal”: Player making an offer or suggestion - “acceptance”: Player accepting a previous proposal - “rejection”: Player rejecting a previous proposal - “counter_proposal”: Player modifying a previous proposal - “message”: General communication or clarification

Type:

str

action_data

Action-specific data and parameters. Structure varies by action_type and game type. Examples: - Proposal: {“price”: 45000, “terms”: “cash_payment”} - Acceptance: {“accepted_proposal_id”: “prop_123”} - Message: {“text”: “I need to consider this offer”}

Type:

Dict[str, Any]

timestamp

Unix timestamp when the action was taken. Used for timing analysis and action ordering.

Type:

float

round_number

The negotiation round when this action occurred. Enables round-based analysis and game flow tracking.

Type:

int

Example

>>> action = PlayerAction(
...     player_id="player_1",
...     action_type="proposal",
...     action_data={"price": 42000, "warranty": True},
...     timestamp=1609459200.0,
...     round_number=3
... )
>>> print(action.action_data["price"])
42000

Note

PlayerAction objects are immutable once created (dataclass with frozen=False by default, but should be treated as read-only after creation).

player_id: str
action_type: str
action_data: Dict[str, Any]
timestamp: float
round_number: int
__init__(player_id: str, action_type: str, action_data: Dict[str, Any], timestamp: float, round_number: int) None

Submodules

Deadline Sensitivity Module

Deadline Sensitivity Metric: Measures true deadline awareness vs panic behavior

negotiation_platform.metrics.deadline_sensitivity.calculate_deadline_sensitivity(surplus_list: List[float]) Tuple[float, float, float, float][source]

Calculate comprehensive deadline sensitivity metrics from surplus progression.

This function analyzes how surplus values change throughout negotiation rounds to measure sensitivity to deadline pressure, providing statistical insights into negotiator behavior under time constraints.

Parameters:

surplus_list (List[float]) – Sequential surplus values per round, representing the progression of negotiation outcomes over time (e.g., [10, 11, 12, 14, 16, 18, 21, 24, 27, 31]).

Returns:

A 4-tuple containing statistical measures:
  • slope: Average surplus improvement per round (positive indicates deadline awareness and progressive concession-making)

  • r_squared: Consistency measure (0-1 scale, high values indicate steady, predictable progression patterns)

  • variance: Steadiness of improvements (low values indicate consistent, smooth progression without erratic changes)

  • p_value: Statistical significance of the trend (low values indicate statistically significant deadline sensitivity)

Return type:

Tuple[float, float, float, float]

Example

>>> surplus_data = [10.0, 12.0, 15.0, 20.0, 30.0]
>>> slope, r2, var, p = calculate_deadline_sensitivity(surplus_data)
>>> print(f"Slope: {slope:.2f}, R²: {r2:.3f}")
Slope: 5.00, R²: 0.950

Note

Higher slope values with low p-values indicate strong deadline sensitivity, suggesting negotiators respond effectively to time pressure by making increasingly beneficial agreements.

class negotiation_platform.metrics.deadline_sensitivity.DeadlineSensitivityMetric(config: Dict[str, Any] | None = None)[source]

Bases: BaseMetric

Simple deadline sensitivity: 100 if agreement reached, 0 otherwise Measures whether deadline pressure resulted in any deal

__init__(config: Dict[str, Any] | None = None)[source]

Initialize the Deadline Sensitivity metric with optional configuration.

Creates a new DeadlineSensitivityMetric instance that measures how effectively players respond to deadline pressure during negotiations. This metric evaluates whether time constraints motivate agreement-seeking behavior and successful negotiation completion.

Parameters:

config (Dict[str, Any], optional) –

Configuration parameters for metric behavior. Currently unused but reserved for future enhancements such as:

  • deadline_threshold: Minimum rounds for sensitivity analysis

  • pressure_weighting: How to weight early vs. late round behavior

  • completion_bonus: Additional scoring for successful agreements

Defaults to None (empty configuration).

Example

>>> # Basic initialization
>>> metric = DeadlineSensitivityMetric()
>>> # With configuration (future use)
>>> config = {"threshold": 3, "weighting": "exponential"}
>>> metric = DeadlineSensitivityMetric(config)

Note

This metric uses a simplified binary approach: 100 points for successful agreements, 0 points for failed negotiations.

calculate(game_result: GameResult, actions_history: List[PlayerAction]) Dict[str, float][source]

Calculate deadline sensitivity score for each player based on negotiation completion.

Measures how effectively players respond to deadline pressure by evaluating whether they successfully reach agreements within the time constraints. Uses a simplified binary scoring system that rewards negotiation completion.

Parameters:
  • game_result (GameResult) – Complete game outcome containing: - game_data: Game state with agreement status and round information - players: List of all participating players - final_scores: Not used for this metric

  • actions_history (List[PlayerAction]) – Complete action log (unused for this metric but required by BaseMetric interface).

Returns:

Dictionary mapping each player ID to their deadline

sensitivity score: - 100.0: Successful agreement reached (deadline pressure effective) - 0.0: No agreement reached (deadline pressure ineffective)

Return type:

Dict[str, float]

Scoring Logic:
  • Binary evaluation: success (100) vs. failure (0)

  • All players receive same score based on overall negotiation outcome

  • Future versions may incorporate more nuanced time-based analysis

Example

>>> result = metric.calculate(game_result, actions_history)
>>> print(result)
{'player1': 100.0, 'player2': 100.0}  # Both succeeded under deadline

Note

This simplified approach focuses on outcome rather than process. Future enhancements may analyze proposal timing and urgency patterns.

get_description() str[source]

Provides a comprehensive description of the Deadline Sensitivity metric.

This method returns a detailed explanation of how the Deadline Sensitivity metric evaluates the effectiveness of time pressure in driving negotiation outcomes by measuring whether agreements are successfully reached before deadlines expire.

Returns:

A multi-line string containing:
  • Metric definition and deadline pressure assessment

  • Binary scoring formula (100 for agreement, 0 for failure)

  • Interpretation of deadline effectiveness

  • Time pressure impact on negotiation dynamics

  • Success/failure outcome indicators

Return type:

str

Note

This metric is particularly useful for analyzing how time constraints influence negotiator behavior and whether deadline pressure creates the intended motivation to reach agreements.

Feasibility Module

Feasibility Metric: Is the agreement even possible

class negotiation_platform.metrics.feasibility.FeasibilityMetric(config: Dict[str, Any] | None = None)[source]

Calculates feasibility: whether the agreement is actually possible given constraints Binary metric: 1.0 if feasible, 0.0 if not feasible

__init__(config: Dict[str, Any] | None = None)[source]

Initialize the Feasibility metric with optional configuration.

Creates a new FeasibilityMetric instance that evaluates whether negotiated agreements are actually achievable given game constraints and player limitations. This binary metric helps identify unrealistic or impossible negotiation outcomes.

Parameters:

config (Dict[str, Any], optional) –

Configuration parameters for metric behavior. Currently unused but reserved for future enhancements such as:

  • constraint_tolerance: Flexibility in feasibility checking

  • validation_mode: Strict vs. lenient constraint enforcement

  • custom_constraints: Additional feasibility rules

Defaults to None (empty configuration).

Example

>>> # Basic initialization
>>> metric = FeasibilityMetric()
>>> # With configuration (future use)
>>> config = {"tolerance": 0.05, "mode": "strict"}
>>> metric = FeasibilityMetric(config)

Note

Feasibility checking adapts automatically to different game types and their specific constraint systems.

calculate(game_result: GameResult, actions_history: List[PlayerAction]) Dict[str, float][source]

Calculate feasibility score for each player’s perspective on the negotiated agreement.

Evaluates whether the final negotiated agreement is actually achievable given game constraints, player resources, and external limitations. Returns binary scores indicating feasibility from each player’s viewpoint.

Parameters:
  • game_result (GameResult) – Complete game outcome containing: - game_data: Game state with agreement details and constraints - final_scores: Final utility outcomes for validation - players: List of all participating players

  • actions_history (List[PlayerAction]) – Complete action log (unused for this metric but required by BaseMetric interface).

Returns:

Dictionary mapping each player ID to their feasibility

score as a binary value: - 1.0: Agreement is feasible from this player’s perspective - 0.0: Agreement is not feasible or no agreement reached

Return type:

Dict[str, float]

Feasibility Criteria (Game-Specific):
  • Price Bargaining: Agreed price within BATNA constraints

  • Resource Allocation: Total resources don’t exceed available supply

  • Integrative: All issue selections are valid and achievable

Example

>>> result = metric.calculate(game_result, actions_history)
>>> print(result)
{'buyer': 1.0, 'seller': 1.0}  # Feasible for both parties

Note

Different players may have different feasibility scores if the agreement violates constraints for some but not all participants.

get_description() str[source]

Provides a comprehensive description of the Feasibility metric.

This method returns a detailed explanation of how the Feasibility metric evaluates whether negotiated agreements can be realistically implemented given the constraints, resources, and time pressures present in the negotiation scenario.

Returns:

A multi-line string containing:
  • Metric definition and implementability assessment

  • Binary scoring system (1.0 for feasible, 0.0 for infeasible)

  • Game-specific feasibility validation criteria

  • Constraint categories and resource limitations

  • Time pressure and BATNA decay considerations

Return type:

str

Note

The description covers various negotiation contexts including resource allocation, budget constraints, compatibility requirements, and acceptable range validations across different game types.

members:

undoc-members:

show-inheritance:

Risk Minimization Module

Risk Minimization Metric: (worse than BATNA / all deals) * 100

class negotiation_platform.metrics.risk_minimization.RiskMinimizationMetric(config: Dict[str, Any] | None = None)[source]

Bases: BaseMetric

Calculates risk minimization: percentage of deals that are worse than BATNA Lower percentages indicate better risk management

__init__(config: Dict[str, Any] | None = None)[source]

Initialize the Risk Minimization metric with optional configuration.

Creates a new RiskMinimizationMetric instance that evaluates players’ risk management behavior during negotiations by analyzing proposal patterns relative to BATNA thresholds.

Parameters:

config (Dict[str, Any], optional) –

Configuration parameters for metric behavior. Currently unused but reserved for future enhancements such as:

  • risk_threshold: Custom risk tolerance levels

  • weighting_scheme: How to weight different risk factors

  • time_horizon: Number of rounds to analyze

Defaults to None (empty configuration).

Example

>>> # Basic initialization
>>> metric = RiskMinimizationMetric()
>>> # With configuration (future use)
>>> config = {"risk_threshold": 0.05, "weighting": "exponential"}
>>> metric = RiskMinimizationMetric(config)

Note

Risk minimization analysis adapts automatically to different game types (price bargaining, resource allocation, integrative).

calculate(game_result: GameResult, actions_history: List[PlayerAction]) Dict[str, float][source]

Calculate risk minimization percentage for each player based on proposal behavior.

Analyzes how well each player managed risk by examining the percentage of proposals that were worse than their BATNA threshold. Lower percentages indicate better risk management and more conservative negotiation strategies.

Parameters:
  • game_result (GameResult) – Complete game outcome containing: - game_data: Game state with BATNA values and agreement status - final_scores: Final utility outcomes for all players - players: List of all participating players

  • actions_history (List[PlayerAction]) – Complete chronological log of all actions taken during the negotiation, used to analyze proposal patterns and risk-taking behavior.

Returns:

Dictionary mapping each player ID to their risk

minimization percentage (0.0-100.0). Lower values indicate better risk management: - 0.0: Perfect risk management (no risky proposals) - 50.0: Moderate risk management (half proposals risky) - 100.0: Poor risk management (all proposals risky)

Return type:

Dict[str, float]

Calculation Logic:
  1. Adapts automatically to game type (price bargaining, resource allocation, integrative)

  2. For each player, counts proposals worse than time-adjusted BATNA

  3. Calculates percentage: (risky_proposals / total_proposals) * 100

  4. Accounts for BATNA decay over negotiation rounds

Example

>>> result = metric.calculate(game_result, actions_history)
>>> print(result)
{'player1': 25.0, 'player2': 10.0}  # player2 managed risk better

Note

Time-adjusted BATNA calculations account for deadline pressure and opportunity cost changes throughout the negotiation.

get_description() str[source]

Provides a comprehensive description of the Risk Minimization metric.

This method returns a detailed explanation of how the Risk Minimization metric evaluates negotiation performance by measuring the percentage of proposed deals or offers that remain within BATNA (Best Alternative to a Negotiated Agreement) limits.

Returns:

A multi-line string containing:
  • Metric definition and purpose

  • Mathematical formula for calculation

  • Interpretation guide with example percentages

  • Game-specific application rules

  • Risk management quality indicators

Return type:

str

Note

The description includes specific guidance for different negotiation contexts, such as price bargaining versus multi-issue negotiations, helping users understand when and how the metric applies.

Utility Surplus Module

Utility Surplus Metric

Implements the Utility Surplus metric, which measures how much value each player extracted from the negotiation compared to their Best Alternative to Negotiated Agreement (BATNA). This is a fundamental metric for evaluating negotiation effectiveness.

Formula:

Utility Surplus = Final Utility from Agreement - BATNA Utility

Interpretation:
  • Positive values: Player achieved better outcome than their best alternative

  • Zero values: Player achieved exactly their BATNA (or no agreement reached)

  • Negative values: Player achieved worse outcome than their best alternative

Key Features:
  • Game-agnostic calculation supporting all negotiation types

  • Handles both absolute and relative utility scales

  • Graceful handling of missing BATNA data with fallback strategies

  • Special handling for no-agreement scenarios

  • Detailed logging for debugging and analysis

Applications:
  • Measuring individual player negotiation performance

  • Comparing negotiation outcomes across different sessions

  • Evaluating the effectiveness of negotiation strategies

  • Analyzing win-win vs. win-lose negotiation outcomes

class negotiation_platform.metrics.utility_surplus.UtilitySurplusMetric(config: Dict[str, Any] | None = None)[source]

Bases: BaseMetric

Metric for calculating utility surplus achieved by each player in negotiations.

The UtilitySurplusMetric quantifies how much better (or worse) each player performed compared to their Best Alternative to Negotiated Agreement (BATNA). This provides a normalized measure of negotiation success that accounts for each player’s outside options.

Calculation Method:

For each player: Final Utility - BATNA Utility = Surplus

The metric handles different game types automatically: - company_car: Subtracts BATNA from absolute monetary utilities - integrative_negotiations: Subtracts BATNA from point-based utilities - resource_allocation: Subtracts BATNA from resource-based utilities

Special Cases:
  • No Agreement: All players receive 0.0 surplus (stayed at BATNA)

  • Missing BATNA: Uses raw utility as fallback with warning

  • Missing Player: Assigns 0.0 surplus for missing players

Value Interpretation:
  • > 0: Player improved upon their BATNA through negotiation

  • = 0: Player achieved exactly their BATNA value

  • < 0: Player accepted worse outcome than their BATNA

Example

>>> metric = UtilitySurplusMetric()
>>> game_result = GameResult(
...     final_scores={"player1": 45000, "player2": 38000},
...     game_data={
...         "agreement_reached": True,
...         "batnas_at_agreement": {"player1": 41000, "player2": 35000}
...     }
... )
>>> surplus = metric.calculate(game_result, [])
>>> print(surplus)
{"player1": 4000.0, "player2": 3000.0}
Inherits from BaseMetric
- metric_name

“Utility Surplus”

- config

Optional configuration parameters

__init__(config: Dict[str, Any] | None = None)[source]

Initialize the Utility Surplus metric with optional configuration.

Creates a new UtilitySurplusMetric instance with the standard name “Utility Surplus” and any provided configuration parameters.

Parameters:

config (Dict[str, Any], optional) –

Configuration parameters for metric behavior. Currently unused but reserved for future enhancements such as:

  • normalization_method: How to scale surplus values

  • missing_batna_strategy: Handling of missing BATNA data

  • precision: Decimal places for calculations

Defaults to None (empty configuration).

Example

>>> # Basic initialization
>>> metric = UtilitySurplusMetric()
>>> # With configuration (future use)
>>> config = {"precision": 2, "normalize": True}
>>> metric = UtilitySurplusMetric(config)
calculate(game_result: GameResult, actions_history: List[PlayerAction]) Dict[str, float][source]

Calculate utility surplus for each player based on final outcomes and BATNA values.

Computes how much each player improved (or worsened) their position compared to their Best Alternative to Negotiated Agreement. The calculation method adapts automatically to different game types and utility scales.

Parameters:
  • game_result (GameResult) – Complete game outcome containing: - final_scores: Dict mapping player IDs to final utility values - game_data: Game state including agreement status and BATNA values - players: List of all participating players

  • actions_history (List[PlayerAction]) – Complete action log (unused for this metric but required by BaseMetric interface).

Returns:

Dictionary mapping each player ID to their utility

surplus value. Positive values indicate improvement over BATNA, negative values indicate worse outcomes than BATNA.

Return type:

Dict[str, float]

Calculation Logic:
  1. Check if agreement was reached (no agreement = 0 surplus for all)

  2. For each player, extract final utility and BATNA value

  3. Calculate surplus as: Final Utility - BATNA Utility

  4. Handle missing data with appropriate fallbacks

Game Type Handling:
  • company_car: Uses absolute monetary values with time-decayed BATNAs

  • integrative_negotiations: Uses point-based utilities with fixed BATNAs

  • resource_allocation: Uses resource-based utilities with team BATNAs

  • unknown: Generic handling with BATNA detection

Special Cases:
  • No Agreement: Returns 0.0 for all players (stayed at BATNA)

  • Missing BATNA: Uses raw utility with warning message

  • Missing Player: Returns 0.0 for players not in final_scores

Example

>>> # Company car negotiation
>>> game_result = GameResult(
...     players=["buyer", "seller"],
...     final_scores={"buyer": 43000, "seller": 43000},
...     game_data={
...         "agreement_reached": True,
...         "batnas_at_agreement": {"buyer": 41000, "seller": 39000}
...     }
... )
>>> metric = UtilitySurplusMetric()
>>> surplus = metric.calculate(game_result, [])
>>> print(surplus)
{'buyer': 2000.0, 'seller': 4000.0}
Error Handling:
  • Missing final_scores: Returns 0.0 for affected players

  • Missing BATNA data: Falls back to raw utility with logging

  • Invalid game_data: Graceful degradation with warnings

get_description() str[source]

Provide a comprehensive description of the Utility Surplus metric.

Returns:

Detailed explanation of metric purpose, calculation, and interpretation.

Return type:

str