{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import spot\n", "spot.setup()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Support for parity games\n", "\n", "The support for parity games is currently quite rudimentary, as Spot currently only uses those games in `ltlsynt`.\n", "\n", "In essence, a parity game is just a parity automaton with a property named `state-player` that stores the player owning each state. The players are named 0 and 1.\n", "\n", "Player 1 is winning if it has a strategy to satisfy the acceptance condition regardless of player 0's moves.\n", "Player 0 is winning if it has a strategy to not satisfy the acceptance codition regardless of player 1's moves." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Input/Output\n", "\n", "An extension of the HOA format makes it possible to store the `state-player` property. This allows us to read the parity game constructed by `ltlsynt` using `spot.automaton()` like any other automaton." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Fin(\n", "\n", ") & (Inf(\n", "\n", ") | Fin(\n", "\n", "))\n", "[parity max odd 3]\n", "\n", "\n", "\n", "0\n", "\n", "0\n", "\n", "\n", "\n", "I->0\n", "\n", "\n", "\n", "\n", "\n", "1\n", "\n", "1\n", "\n", "\n", "\n", "0->1\n", "\n", "\n", "!a\n", "\n", "\n", "\n", "\n", "2\n", "\n", "2\n", "\n", "\n", "\n", "0->2\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "3\n", "\n", "3\n", "\n", "\n", "\n", "1->3\n", "\n", "\n", "!b\n", "\n", "\n", "\n", "\n", "4\n", "\n", "4\n", "\n", "\n", "\n", "1->4\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "2->4\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "5\n", "\n", "5\n", "\n", "\n", "\n", "2->5\n", "\n", "\n", "!b\n", "\n", "\n", "\n", "\n", "6\n", "\n", "6\n", "\n", "\n", "\n", "3->6\n", "\n", "\n", "!a\n", "\n", "\n", "\n", "\n", "7\n", "\n", "7\n", "\n", "\n", "\n", "3->7\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "8\n", "\n", "8\n", "\n", "\n", "\n", "4->8\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "5->6\n", "\n", "\n", "!a\n", "\n", "\n", "\n", "\n", "5->7\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "6->3\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "7->5\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "8->4\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "9\n", "\n", "9\n", "\n", "\n", "\n", "8->9\n", "\n", "\n", "!b\n", "\n", "\n", "\n", "\n", "10\n", "\n", "10\n", "\n", "\n", "\n", "9->10\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "10->9\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n" ], "text/plain": [ " *' at 0x7f9bf8477330> >" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "game = spot.automaton(\"ltlsynt --ins=a --outs=b -f '!b & GFa <-> Gb' --print-game-hoa |\");\n", "game" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the graphical output, player 0 is represented by circles (or ellipses or rounded rectangles depending on the situations), while player 1's states are diamond shaped. In the case of `ltlsynt`, player 0 plays the role of the environment, and player 1 plays the role of the controler.\n", "\n", "In the HOA output, a header `spot-state-player` (or `spot.state-player` in HOA 1.1) lists the owner of each state." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "HOA: v1\n", "States: 11\n", "Start: 0\n", "AP: 2 \"b\" \"a\"\n", "acc-name: parity max odd 3\n", "Acceptance: 3 Fin(2) & (Inf(1) | Fin(0))\n", "properties: trans-labels explicit-labels trans-acc colored complete\n", "properties: deterministic\n", "spot-state-player: 0 1 1 0 0 0 1 1 1 0 1\n", "--BODY--\n", "State: 0\n", "[!1] 1 {1}\n", "[1] 2 {1}\n", "State: 1\n", "[!0] 3 {1}\n", "[0] 4 {1}\n", "State: 2\n", "[0] 4 {1}\n", "[!0] 5 {1}\n", "State: 3\n", "[!1] 6 {1}\n", "[1] 7 {2}\n", "State: 4\n", "[t] 8 {2}\n", "State: 5\n", "[1] 7 {2}\n", "[!1] 6 {1}\n", "State: 6\n", "[t] 3 {1}\n", "State: 7\n", "[t] 5 {2}\n", "State: 8\n", "[0] 4 {2}\n", "[!0] 9 {1}\n", "State: 9\n", "[t] 10 {1}\n", "State: 10\n", "[t] 9 {1}\n", "--END--\n" ] } ], "source": [ "print(game.to_str('hoa'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Solving games" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `solve_parity_game()` function returns the player winning from the initial state (`False` for player 0, and `True` for player 1)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "spot.solve_parity_game(game)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Additional information about the player winning in each state, and the strategy have been stored in the automaton but are not displayed by default.\n", "\n", "Calling the `highlight_strategy` function will decorate the game's automaton with colors showing the winning regions (states from which a player has a strategy to win), and strategy (which transition should be used for each winning state owned by that player) of a given player. Here green corresponds to player 1 (who tries to satisfy the acceptance condition), and red to player 0 (who tries not to)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Fin(\n", "\n", ") & (Inf(\n", "\n", ") | Fin(\n", "\n", "))\n", "[parity max odd 3]\n", "\n", "\n", "\n", "0\n", "\n", "0\n", "\n", "\n", "\n", "I->0\n", "\n", "\n", "\n", "\n", "\n", "1\n", "\n", "1\n", "\n", "\n", "\n", "0->1\n", "\n", "\n", "!a\n", "\n", "\n", "\n", "\n", "2\n", "\n", "2\n", "\n", "\n", "\n", "0->2\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "3\n", "\n", "3\n", "\n", "\n", "\n", "1->3\n", "\n", "\n", "!b\n", "\n", "\n", "\n", "\n", "4\n", "\n", "4\n", "\n", "\n", "\n", "1->4\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "2->4\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "5\n", "\n", "5\n", "\n", "\n", "\n", "2->5\n", "\n", "\n", "!b\n", "\n", "\n", "\n", "\n", "6\n", "\n", "6\n", "\n", "\n", "\n", "3->6\n", "\n", "\n", "!a\n", "\n", "\n", "\n", "\n", "7\n", "\n", "7\n", "\n", "\n", "\n", "3->7\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "8\n", "\n", "8\n", "\n", "\n", "\n", "4->8\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "5->6\n", "\n", "\n", "!a\n", "\n", "\n", "\n", "\n", "5->7\n", "\n", "\n", "a\n", "\n", "\n", "\n", "\n", "6->3\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "7->5\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "8->4\n", "\n", "\n", "b\n", "\n", "\n", "\n", "\n", "9\n", "\n", "9\n", "\n", "\n", "\n", "8->9\n", "\n", "\n", "!b\n", "\n", "\n", "\n", "\n", "10\n", "\n", "10\n", "\n", "\n", "\n", "9->10\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n", "10->9\n", "\n", "\n", "1\n", "\n", "\n", "\n", "\n" ], "text/plain": [ " *' at 0x7f9bf83e1060> >" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "spot.highlight_strategy(game)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.6rc1" } }, "nbformat": 4, "nbformat_minor": 4 }