game-resolver-cpp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. game_resolver_cpp-0.1.0/.clang-format +8 -0
  2. game_resolver_cpp-0.1.0/.clang-tidy +12 -0
  3. game_resolver_cpp-0.1.0/.gitignore +19 -0
  4. game_resolver_cpp-0.1.0/CMakeLists.txt +125 -0
  5. game_resolver_cpp-0.1.0/LICENSE +21 -0
  6. game_resolver_cpp-0.1.0/Makefile +54 -0
  7. game_resolver_cpp-0.1.0/PKG-INFO +147 -0
  8. game_resolver_cpp-0.1.0/README.md +525 -0
  9. game_resolver_cpp-0.1.0/benchmarks/CMakeLists.txt +5 -0
  10. game_resolver_cpp-0.1.0/benchmarks/benchmark.cpp +116 -0
  11. game_resolver_cpp-0.1.0/cmake/game_resolverConfig.cmake.in +8 -0
  12. game_resolver_cpp-0.1.0/docs/README_for_pypi.md +117 -0
  13. game_resolver_cpp-0.1.0/examples/CMakeLists.txt +13 -0
  14. game_resolver_cpp-0.1.0/examples/battle_of_sex.cpp +41 -0
  15. game_resolver_cpp-0.1.0/examples/bayesian_battle_of_sex.cpp +72 -0
  16. game_resolver_cpp-0.1.0/examples/cournot.cpp +40 -0
  17. game_resolver_cpp-0.1.0/examples/hawk_dove.cpp +36 -0
  18. game_resolver_cpp-0.1.0/examples/prisoners_dilemma.cpp +24 -0
  19. game_resolver_cpp-0.1.0/include/game_resolver/action.hpp +44 -0
  20. game_resolver_cpp-0.1.0/include/game_resolver/bayesian/bayesian_game.hpp +40 -0
  21. game_resolver_cpp-0.1.0/include/game_resolver/bayesian/bayesian_nash_equilibrium.hpp +68 -0
  22. game_resolver_cpp-0.1.0/include/game_resolver/bayesian/bayesian_player.hpp +106 -0
  23. game_resolver_cpp-0.1.0/include/game_resolver/error.hpp +26 -0
  24. game_resolver_cpp-0.1.0/include/game_resolver/game.hpp +33 -0
  25. game_resolver_cpp-0.1.0/include/game_resolver/game_resolver.hpp +12 -0
  26. game_resolver_cpp-0.1.0/include/game_resolver/nash_equilibrium.hpp +58 -0
  27. game_resolver_cpp-0.1.0/include/game_resolver/ndarray.hpp +144 -0
  28. game_resolver_cpp-0.1.0/include/game_resolver/payoff.hpp +162 -0
  29. game_resolver_cpp-0.1.0/include/game_resolver/player.hpp +36 -0
  30. game_resolver_cpp-0.1.0/include/game_resolver/solver/nash_solver.hpp +54 -0
  31. game_resolver_cpp-0.1.0/include/game_resolver/version.hpp +10 -0
  32. game_resolver_cpp-0.1.0/pyproject.toml +79 -0
  33. game_resolver_cpp-0.1.0/python/CMakeLists.txt +12 -0
  34. game_resolver_cpp-0.1.0/python/benchmarks/compare_with_python.py +227 -0
  35. game_resolver_cpp-0.1.0/python/game_resolver_cpp/__init__.py +29 -0
  36. game_resolver_cpp-0.1.0/python/game_resolver_cpp/bayesian_game.py +32 -0
  37. game_resolver_cpp-0.1.0/python/game_resolver_cpp/bayesian_nash_equilibrium.py +90 -0
  38. game_resolver_cpp-0.1.0/python/game_resolver_cpp/bayesian_player.py +17 -0
  39. game_resolver_cpp-0.1.0/python/game_resolver_cpp/game.py +13 -0
  40. game_resolver_cpp-0.1.0/python/game_resolver_cpp/nash_equilibrium.py +211 -0
  41. game_resolver_cpp-0.1.0/python/game_resolver_cpp/payoff.py +49 -0
  42. game_resolver_cpp-0.1.0/python/game_resolver_cpp/player.py +28 -0
  43. game_resolver_cpp-0.1.0/python/src/binding.cpp +247 -0
  44. game_resolver_cpp-0.1.0/python/tests/test_compat.py +351 -0
  45. game_resolver_cpp-0.1.0/src/action.cpp +117 -0
  46. game_resolver_cpp-0.1.0/src/bayesian/bayesian_nash_equilibrium.cpp +290 -0
  47. game_resolver_cpp-0.1.0/src/bayesian/bayesian_player.cpp +71 -0
  48. game_resolver_cpp-0.1.0/src/nash_equilibrium.cpp +316 -0
  49. game_resolver_cpp-0.1.0/src/payoff.cpp +64 -0
  50. game_resolver_cpp-0.1.0/src/solver/nash_solver.cpp +154 -0
  51. game_resolver_cpp-0.1.0/src/version.cpp +9 -0
  52. game_resolver_cpp-0.1.0/tests/CMakeLists.txt +39 -0
  53. game_resolver_cpp-0.1.0/tests/action_test.cpp +77 -0
  54. game_resolver_cpp-0.1.0/tests/bayesian_test.cpp +185 -0
  55. game_resolver_cpp-0.1.0/tests/example_games.hpp +121 -0
  56. game_resolver_cpp-0.1.0/tests/golden/battle_of_sex.txt +6 -0
  57. game_resolver_cpp-0.1.0/tests/golden/bayesian_battle_of_sex.txt +8 -0
  58. game_resolver_cpp-0.1.0/tests/golden/cournot.txt +7 -0
  59. game_resolver_cpp-0.1.0/tests/golden/generate.py +144 -0
  60. game_resolver_cpp-0.1.0/tests/golden/hawk_dove.txt +6 -0
  61. game_resolver_cpp-0.1.0/tests/golden/prisoners_dilemma.txt +5 -0
  62. game_resolver_cpp-0.1.0/tests/golden/verify_exact.py +200 -0
  63. game_resolver_cpp-0.1.0/tests/golden_test.cpp +225 -0
  64. game_resolver_cpp-0.1.0/tests/nash_equilibrium_test.cpp +260 -0
  65. game_resolver_cpp-0.1.0/tests/nash_solver_test.cpp +179 -0
  66. game_resolver_cpp-0.1.0/tests/ndarray_test.cpp +93 -0
  67. game_resolver_cpp-0.1.0/tests/smoke_test.cpp +7 -0
@@ -0,0 +1,8 @@
1
+ ---
2
+ Language: Cpp
3
+ BasedOnStyle: Google
4
+ ColumnLimit: 100
5
+ DerivePointerAlignment: false
6
+ PointerAlignment: Left
7
+ IncludeBlocks: Preserve
8
+ AllowShortFunctionsOnASingleLine: Inline
@@ -0,0 +1,12 @@
1
+ Checks: >
2
+ bugprone-*,
3
+ performance-*,
4
+ modernize-*,
5
+ readability-*,
6
+ -bugprone-easily-swappable-parameters,
7
+ -modernize-use-trailing-return-type,
8
+ -readability-identifier-length,
9
+ -readability-magic-numbers
10
+
11
+ WarningsAsErrors: ''
12
+ HeaderFilterRegex: 'include/game_resolver/.*'
@@ -0,0 +1,19 @@
1
+ build/
2
+ build-*/
3
+ cmake-build-*/
4
+ _deps/
5
+ CMakeCache.txt
6
+ CMakeFiles/
7
+ compile_commands.json
8
+ .cache/
9
+ *.o
10
+ *.a
11
+ *.so
12
+ *.dylib
13
+ .DS_Store
14
+ .vscode/
15
+ .idea/
16
+ .claude/
17
+ dist/
18
+ wheelhouse/
19
+ *.egg-info/
@@ -0,0 +1,125 @@
1
+ cmake_minimum_required(VERSION 3.21)
2
+ project(game_resolver_cpp VERSION 0.1.0 LANGUAGES CXX)
3
+
4
+ option(GAME_RESOLVER_BUILD_TESTS "Build the test suite" ${PROJECT_IS_TOP_LEVEL})
5
+ option(GAME_RESOLVER_BUILD_EXAMPLES "Build the example programs" ${PROJECT_IS_TOP_LEVEL})
6
+ option(GAME_RESOLVER_BUILD_BENCHMARKS "Build the benchmark program" ${PROJECT_IS_TOP_LEVEL})
7
+ option(GAME_RESOLVER_BUILD_PYTHON "Build the Python extension module" OFF)
8
+ option(GAME_RESOLVER_WERROR "Treat compiler warnings as errors" OFF)
9
+ option(GAME_RESOLVER_SANITIZE "Build with sanitizers (see GAME_RESOLVER_SANITIZERS)" OFF)
10
+
11
+ # macOS の Apple clang 15 に同梱の ASan ランタイムは、最近の macOS 上で
12
+ # 「CHECK failed: sanitizer_malloc_mac.inc」で起動時に落ちる(自明なプログラムでも再現する
13
+ # ツールチェーン側の問題)。そのため Apple では既定を UBSan のみにする。
14
+ # ASan は Linux の CI ジョブでかける。明示指定すれば macOS でも有効にできる。
15
+ if(APPLE)
16
+ set(GAME_RESOLVER_SANITIZERS "undefined" CACHE STRING "Comma separated sanitizer list")
17
+ else()
18
+ set(GAME_RESOLVER_SANITIZERS "address,undefined" CACHE STRING "Comma separated sanitizer list")
19
+ endif()
20
+
21
+ set(CMAKE_CXX_STANDARD 20)
22
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
23
+ set(CMAKE_CXX_EXTENSIONS OFF)
24
+ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
25
+
26
+ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
27
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
28
+ endif()
29
+
30
+ # ---------------------------------------------------------------- library
31
+ add_library(game_resolver
32
+ src/version.cpp
33
+ src/action.cpp
34
+ src/payoff.cpp
35
+ src/nash_equilibrium.cpp
36
+ src/solver/nash_solver.cpp
37
+ src/bayesian/bayesian_player.cpp
38
+ src/bayesian/bayesian_nash_equilibrium.cpp
39
+ )
40
+ add_library(game_resolver::game_resolver ALIAS game_resolver)
41
+
42
+ target_include_directories(game_resolver PUBLIC
43
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
44
+ $<INSTALL_INTERFACE:include>
45
+ )
46
+ target_compile_features(game_resolver PUBLIC cxx_std_20)
47
+
48
+ # 静的ライブラリを共有オブジェクトにリンクできるようにする。
49
+ # これが無いと Linux で Python 拡張モジュール (_core.so) のリンクが
50
+ # 「relocation R_X86_64_32 ... can not be used when making a shared object」で失敗する。
51
+ # macOS は常に PIC なので気づきにくい。利用者が自分の共有ライブラリに組み込む場合にも要る。
52
+ set_target_properties(game_resolver PROPERTIES POSITION_INDEPENDENT_CODE ON)
53
+
54
+ find_package(Threads REQUIRED)
55
+ target_link_libraries(game_resolver PUBLIC Threads::Threads)
56
+
57
+ if(MSVC)
58
+ target_compile_options(game_resolver PRIVATE /W4)
59
+ if(GAME_RESOLVER_WERROR)
60
+ target_compile_options(game_resolver PRIVATE /WX)
61
+ endif()
62
+ else()
63
+ target_compile_options(game_resolver PRIVATE -Wall -Wextra -Wpedantic)
64
+ if(GAME_RESOLVER_WERROR)
65
+ target_compile_options(game_resolver PRIVATE -Werror)
66
+ endif()
67
+ endif()
68
+
69
+ if(GAME_RESOLVER_SANITIZE)
70
+ message(STATUS "Sanitizers: ${GAME_RESOLVER_SANITIZERS}")
71
+ target_compile_options(game_resolver PUBLIC
72
+ -fsanitize=${GAME_RESOLVER_SANITIZERS} -fno-omit-frame-pointer)
73
+ target_link_options(game_resolver PUBLIC -fsanitize=${GAME_RESOLVER_SANITIZERS})
74
+ endif()
75
+
76
+ # ---------------------------------------------------------------- subdirs
77
+ if(GAME_RESOLVER_BUILD_EXAMPLES)
78
+ add_subdirectory(examples)
79
+ endif()
80
+
81
+ if(GAME_RESOLVER_BUILD_BENCHMARKS)
82
+ add_subdirectory(benchmarks)
83
+ endif()
84
+
85
+ if(GAME_RESOLVER_BUILD_PYTHON)
86
+ add_subdirectory(python)
87
+ endif()
88
+
89
+ if(GAME_RESOLVER_BUILD_TESTS)
90
+ enable_testing()
91
+ add_subdirectory(tests)
92
+ endif()
93
+
94
+ # ---------------------------------------------------------------- install
95
+ include(GNUInstallDirs)
96
+ include(CMakePackageConfigHelpers)
97
+
98
+ install(TARGETS game_resolver
99
+ EXPORT game_resolverTargets
100
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
101
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
102
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
103
+ )
104
+ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
105
+
106
+ install(EXPORT game_resolverTargets
107
+ FILE game_resolverTargets.cmake
108
+ NAMESPACE game_resolver::
109
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/game_resolver
110
+ )
111
+
112
+ configure_package_config_file(
113
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/game_resolverConfig.cmake.in
114
+ ${CMAKE_CURRENT_BINARY_DIR}/game_resolverConfig.cmake
115
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/game_resolver
116
+ )
117
+ write_basic_package_version_file(
118
+ ${CMAKE_CURRENT_BINARY_DIR}/game_resolverConfigVersion.cmake
119
+ COMPATIBILITY SameMajorVersion
120
+ )
121
+ install(FILES
122
+ ${CMAKE_CURRENT_BINARY_DIR}/game_resolverConfig.cmake
123
+ ${CMAKE_CURRENT_BINARY_DIR}/game_resolverConfigVersion.cmake
124
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/game_resolver
125
+ )
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 nishino-lab, The University of Tokyo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,54 @@
1
+ CMAKE ?= cmake
2
+ CTEST ?= ctest
3
+ BUILD_DIR ?= build
4
+ BUILD_TYPE ?= Release
5
+ GENERATOR ?= Ninja
6
+
7
+ .PHONY: all configure build test bench format format-check tidy clean python-install python-test python-bench
8
+
9
+ all: build
10
+
11
+ configure:
12
+ $(CMAKE) -S . -B $(BUILD_DIR) -G $(GENERATOR) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE)
13
+
14
+ build: configure
15
+ $(CMAKE) --build $(BUILD_DIR) -j
16
+
17
+ test: build
18
+ $(CTEST) --test-dir $(BUILD_DIR) --output-on-failure
19
+
20
+ bench: build
21
+ @$(BUILD_DIR)/benchmarks/gr_benchmark
22
+
23
+ # Python バインディング
24
+ python-install:
25
+ pip install ".[test]"
26
+
27
+ python-test:
28
+ pytest python/tests -q
29
+
30
+ python-bench:
31
+ python3 python/benchmarks/compare_with_python.py
32
+
33
+ # サニタイザ付きのデバッグビルドでテストする
34
+ test-asan:
35
+ $(CMAKE) -S . -B $(BUILD_DIR)-asan -G $(GENERATOR) -DCMAKE_BUILD_TYPE=Debug -DGAME_RESOLVER_SANITIZE=ON
36
+ $(CMAKE) --build $(BUILD_DIR)-asan -j
37
+ $(CTEST) --test-dir $(BUILD_DIR)-asan --output-on-failure
38
+
39
+ CLANG_FORMAT ?= clang-format
40
+ SOURCES = $(shell find include src tests examples benchmarks \( -name '*.hpp' -o -name '*.cpp' \))
41
+
42
+ format:
43
+ @command -v $(CLANG_FORMAT) >/dev/null || { echo "clang-format がありません: brew install clang-format"; exit 1; }
44
+ @$(CLANG_FORMAT) -i $(SOURCES)
45
+
46
+ format-check:
47
+ @command -v $(CLANG_FORMAT) >/dev/null || { echo "clang-format がありません: brew install clang-format"; exit 1; }
48
+ @$(CLANG_FORMAT) --dry-run --Werror $(SOURCES)
49
+
50
+ tidy: configure
51
+ @find include src -name '*.hpp' -o -name '*.cpp' | xargs clang-tidy -p $(BUILD_DIR)
52
+
53
+ clean:
54
+ rm -rf $(BUILD_DIR) $(BUILD_DIR)-asan
@@ -0,0 +1,147 @@
1
+ Metadata-Version: 2.2
2
+ Name: game_resolver_cpp
3
+ Version: 0.1.0
4
+ Summary: C++ backed game equilibrium solver with the game_resolver interface
5
+ Keywords: game-theory,nash-equilibrium,bayesian-game
6
+ Author: nishino-lab
7
+ License: MIT
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: C++
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
20
+ Classifier: Operating System :: POSIX :: Linux
21
+ Classifier: Operating System :: MacOS :: MacOS X
22
+ Project-URL: Homepage, https://github.com/nishinolab/game_resolver_cpp
23
+ Project-URL: Source, https://github.com/nishinolab/game_resolver_cpp
24
+ Project-URL: Python version, https://github.com/nishinolab/game_resolver
25
+ Requires-Python: >=3.9
26
+ Requires-Dist: numpy>=1.22
27
+ Provides-Extra: test
28
+ Requires-Dist: pytest>=7; extra == "test"
29
+ Description-Content-Type: text/markdown
30
+
31
+ # game_resolver_cpp
32
+
33
+ This library is internal library for nishino-lab(The University of Tokyo)
34
+
35
+ http://www.css.t.u-tokyo.ac.jp
36
+
37
+ A C++20 solver for pure strategy Nash equilibria and Bayesian Nash equilibria, with the
38
+ same Python interface as [game_resolver](https://pypi.org/project/game-resolver/).
39
+ Existing code runs by changing the import prefix only.
40
+
41
+ ## How to install
42
+
43
+ ```
44
+ pip install game_resolver_cpp
45
+ ```
46
+
47
+ ## Run your own game
48
+
49
+ ```python
50
+ import numpy as np
51
+ from game_resolver_cpp.game import Game
52
+ from game_resolver_cpp.nash_equilibrium import NashEquilibrium
53
+ from game_resolver_cpp.player import Player
54
+
55
+
56
+ class PrisonersDilemma(Game):
57
+ def __init__(self):
58
+ super().__init__()
59
+ actions = np.array(["C", "D"])
60
+ self.add(Player(0, actions=actions, payoff_matrix=np.array([[3, 0], [5, 1]])))
61
+ self.add(Player(1, actions=actions, payoff_matrix=np.array([[3, 5], [0, 1]])))
62
+
63
+
64
+ nash = NashEquilibrium(PrisonersDilemma()).get_nash_equilibrium()
65
+ print(nash["index"]) # [(1, 1)]
66
+ print(nash["profile"]) # [['D', 'D']]
67
+ print(nash["payoff"]) # [[1.0, 1.0]]
68
+ ```
69
+
70
+ All four ways of defining payoffs work, exactly as in `game_resolver`:
71
+
72
+ - `payoff_function=` with a function NumPy can broadcast (Type1)
73
+ - `payoff_function=` with a function called per cell (Type2)
74
+ - `payoff_matrix=` with a NumPy array (Type3)
75
+ - `payoff=` with a `Payoff` table, or a plain dict (Type4)
76
+
77
+ ## Run a Bayesian game
78
+
79
+ Subclass `BayesianGame` and implement `posterior()`.
80
+
81
+ ```python
82
+ from game_resolver_cpp.bayesian_game import BayesianGame
83
+ from game_resolver_cpp.bayesian_nash_equilibrium import BayesianNashEquilibrium
84
+ from game_resolver_cpp.bayesian_player import BayesianPlayer
85
+
86
+
87
+ class SampleGame(BayesianGame):
88
+ def __init__(self):
89
+ super().__init__()
90
+ actions = np.array(["Boxing", "Ballet"])
91
+ types = np.array(["A", "B"])
92
+ self.add(BayesianPlayer(0, actions=actions, types=types, payoff_function=self.male))
93
+ self.add(BayesianPlayer(1, actions=actions, types=types, payoff_function=self.female))
94
+
95
+ def posterior(self, player_id, type_tuple):
96
+ own = type_tuple[player_id]
97
+ other = type_tuple[(player_id + 1) % 2]
98
+ return 1 / 4 if own == other else 3 / 4
99
+
100
+ # payoff functions take (own type, each player's action)
101
+ def male(self, type, male_action, female_action): ...
102
+ def female(self, type, male_action, female_action): ...
103
+
104
+
105
+ nash = BayesianNashEquilibrium(SampleGame()).get_nash_equilibrium()
106
+ ```
107
+
108
+ ## What gets faster
109
+
110
+ Against the pure Python `game_resolver`, on an 11-core Apple M series machine.
111
+
112
+ | | Python | this package |
113
+ | --- | --- | --- |
114
+ | Complete information, 990 x 990 = 980,100 cells | 5.8 - 750 ms | 4.2 - 225 ms |
115
+ | Bayesian, 2 players x 3 actions x 3 types | 21.0 ms | 0.2 ms |
116
+ | Bayesian, 2 players x 3 actions x 4 types | 298 ms | 0.6 ms |
117
+ | Bayesian, 2 players x 3 actions x 5 types | 3958 ms | 4.2 ms |
118
+
119
+ **Bayesian games are where this pays off, and the gap widens with size.** The Python version
120
+ calls `posterior()` once per strategy profile, per player, per type; this one caches it and
121
+ calls it `players x type profiles` times — 32 calls instead of 209,952 for 3 actions and 4
122
+ types.
123
+
124
+ Complete information games gain little (1.1x to 3.3x). NumPy is already doing that work in
125
+ C, so only the equilibrium search moves over. Note that within the Python version itself the
126
+ same game takes 5.8 ms or 750 ms depending only on how the payoffs are written — choosing
127
+ Type1 or Type3 matters far more than choosing this package.
128
+
129
+ ## Results match the Python version
130
+
131
+ The equilibria of all five sample games are pinned and checked on every test run, and
132
+ verified against exact rational arithmetic.
133
+
134
+ One deliberate difference: payoffs are compared with a small relative tolerance instead of
135
+ an exact `==`, because an exact comparison makes genuine ties depend on rounding. The
136
+ Cournot example has three equilibria on its grid; the Python version reports one of them.
137
+ Pass `tolerance=0` to `NashEquilibrium` for the Python version's strict behaviour.
138
+
139
+ ## Not supported
140
+
141
+ - Mixed strategy Nash equilibria (the Python version does not have them either)
142
+ - Extensive form games, subgame perfect equilibria
143
+
144
+ ## Links
145
+
146
+ - Source, C++ API, and design notes: https://github.com/nishinolab/game_resolver_cpp
147
+ - The original Python version: https://github.com/nishinolab/game_resolver