Skip to content

Commit

Permalink
add workflows, improve document
Browse files Browse the repository at this point in the history
  • Loading branch information
wind23 committed Apr 3, 2024
1 parent 1fbe148 commit d010962
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 29 deletions.
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
actions:
patterns:
- "*"
48 changes: 48 additions & 0 deletions .github/workflows/conda.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Conda

on:
workflow_dispatch:
push:
branches:
- master
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.8", "3.10"]

runs-on: ${{ matrix.platform }}

# The setup-miniconda action needs this to activate miniconda
defaults:
run:
shell: "bash -l {0}"

steps:
- uses: actions/checkout@v4

- name: Get conda
uses: conda-incubator/setup-miniconda@v3.0.3
with:
python-version: ${{ matrix.python-version }}
channels: conda-forge

- name: Prepare
run: conda install conda-build conda-verify

- name: Build
run: conda build conda.recipe

- name: Install
run: conda install -c ${CONDA_PREFIX}/conda-bld/ whr

- name: Test
run: python tests/test_whr.py
70 changes: 70 additions & 0 deletions .github/workflows/pip.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Pip

on:
workflow_dispatch:
pull_request:
push:
branches:
- master

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [windows-latest, macos-latest, ubuntu-latest]
python-version: ["3.7", "3.11"]

runs-on: ${{ matrix.platform }}

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Add requirements
run: python -m pip install --upgrade wheel setuptools

- name: Build and install
run: pip install --verbose .

- name: Test
run: python tests/test_whr.py

build-mingw64:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: msys2/setup-msys2@v2
with:
update: true
install: >-
mingw-w64-x86_64-gcc
mingw-w64-x86_64-python-pip
mingw-w64-x86_64-python-wheel
- uses: actions/checkout@v4

- name: Install pybind11
# This is required because --no-build-isolation disable dependences
# installation
run: pip install pybind11

- name: Build and install
# --no-build-isolation is required because the vanilla setuptool does not
# support Mingw64.See patches here:
# https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-python-setuptools
# Without those patches build_ext fails with:
# error: --plat-name must be one of ('win32', 'win-amd64', 'win-arm32', 'win-arm64')
run: pip install --no-build-isolation .

- name: Test
run: python tests/test_whr.py
4 changes: 4 additions & 0 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: Wheels

on:
workflow_dispatch:
pull_request:
push:
branches:
- master
release:
types:
- published
Expand Down
72 changes: 49 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
Whole History Rating
====================

| CI | status |
|----------------------|--------|
| conda.recipe | [![Conda Actions Status][actions-conda-badge]][actions-conda-link] |
| pip builds | [![Pip Actions Status][actions-pip-badge]][actions-pip-link] |
| cibuildwheel | [![Wheels Actions Status][actions-wheels-badge]][actions-wheels-link] |

[actions-conda-link]: https://github.com/wind23/whole_history_rating/actions?query=workflow%3AConda
[actions-conda-badge]: https://github.com/wind23/whole_history_rating/workflows/Conda/badge.svg
[actions-pip-link]: https://github.com/wind23/whole_history_rating/actions?query=workflow%3APip
[actions-pip-badge]: https://github.com/wind23/whole_history_rating/workflows/Pip/badge.svg
[actions-wheels-link]: https://github.com/wind23/whole_history_rating/actions?query=workflow%3AWheels
[actions-wheels-badge]: https://github.com/wind23/whole_history_rating/workflows/Wheels/badge.svg

## Description

A Python interface incorporating a C++ implementation of the [Whole History Rating](http://remi.coulom.free.fr/WHR/WHR.pdf) algorithm proposed by [Rémi Coulom](http://remi.coulom.free.fr/).
Expand Down Expand Up @@ -28,29 +41,42 @@ If you encounter compatibility issues while using the latest version, you can al

Here is an easy example about how to use the package:

In [1]: import whr
...:
...: base = whr.Base(config={'w2': 30})
...: base.create_game('Alice', 'Carol', 'D', 0) # Alice and Carol had a draw on Day 0
...: base.create_game('Bob', 'Dave', 'B', 10) # Bob won Dave on Day 10
...: base.create_game('Dave', 'Alice', 'W', 30) # Dave lost to Alice on Day 30
...: base.create_game('Bob', 'Carol', 'W', 60) # Bob lost to Carol on Day 60
...:
...: base.iterate(50) # iterate for 50 rounds

In [2]: print(base.ratings_for_player('Alice'))
...: print(base.ratings_for_player('Bob'))
...: print(base.ratings_for_player('Carol'))
...: print(base.ratings_for_player('Dave'))
[[0, 78.50976252870765, 114.0890917675107], [30, 79.47183295485291, 116.02912272478814]]
[[10, -15.262552175731381, 108.50075126605397], [60, -18.08603087778281, 111.07152016073245]]
[[0, 103.9187774903099, 108.03027219107216], [60, 107.30695193277161, 111.12369929419124]]
[[10, -176.6773935927304, 134.07989121465133], [30, -177.31877387682724, 135.25422816732765]]

In [3]: print(base.get_ordered_ratings())
[('Carol', [[0, 103.9187774903099, 108.03027219107216], [60, 107.30695193277161, 111.12369929419124]]), ('Alice', [[0, 78.50976252870765, 114.0890917675107], [30, 79.47183295485291, 116.02912272478814]]), ('Bob', [[10, -15.262552175731381, 108.50075126605397], [60, -18.08603087778281, 111.07152016073245]]), ('Dave', [[10, -176.6773935927304, 134.07989121465133], [30, -177.31877387682724, 135.25422816732765]])]

To learn more about the detailed usage, please refer to the docstrings of `whr.Base` and `whr.Evaluate`.
In [1]: import whr
...: import math
...:
...: base = whr.Base(config={"w2": 30})
...: base.create_game("Alice", "Carol", "D", 0) # Alice and Carol had a draw on Day 0
...: base.create_game("Bob", "Dave", "B", 10) # Bob won Dave on Day 10
...: base.create_game("Dave", "Alice", "W", 30) # Dave lost to Alice on Day 30
...: base.create_game("Bob", "Carol", "W", 60) # Bob lost to Carol on Day 60
...:
...: base.iterate(50) # iterate for 50 rounds

In [2]: print(base.ratings_for_player("Alice"))
...: print(base.ratings_for_player("Bob"))
...: print(base.ratings_for_player("Carol"))
...: print(base.ratings_for_player("Dave"))
[[0, 78.50976252870765, 185.55230942797314], [30, 79.47183295485291, 187.12327376311526]]
[[10, -15.262552175731392, 180.95086989932025], [60, -18.086030877782818, 183.0820052639819]]
[[0, 103.91877749030998, 180.55812567296852], [60, 107.30695193277168, 183.1250043094528]]
[[10, -176.67739359273045, 201.15282077913983], [30, -177.3187738768273, 202.03179750776144]]

In [3]: print(base.get_ordered_ratings())
[('Carol', [[0, 103.91877749030998, 180.55812567296852], [60, 107.30695193277168, 183.1250043094528]]), ('Alice', [[0, 78.50976252870765, 185.55230942797314], [30, 79.47183295485291, 187.12327376311526]]), ('Bob', [[10, -15.262552175731392, 180.95086989932025], [60, -18.086030877782818, 183.0820052639819]]), ('Dave', [[10, -176.67739359273045, 201.15282077913983], [30, -177.3187738768273, 202.03179750776144]])]

In [4]: evaluate = whr.Evaluate(base)
...: test_games = [
...: ["Alice", "Bob", "B", 0],
...: ["Bob", "Carol", "W", 20],
...: ["Dave", "Bob", "D", 50],
...: ["Alice", "Dave", "B", 70],
...: ]
...: log_likelihood = evaluate.evaluate_ave_log_likelihood_games(test_games)

In [5]: print("Likelihood: ", math.exp(log_likelihood))
Likelihood: 0.6274093351974668

To learn more about the detailed usage, please refer to the docstrings of [`whr.Base`](https://github.com/wind23/whole_history_rating/blob/master/whr/base.py) and [`whr.Evaluate`](https://github.com/wind23/whole_history_rating/blob/master/whr/evaluate.py).

## References

Expand Down
35 changes: 35 additions & 0 deletions conda.recipe/meta.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package:
name: whr
version: 2.0.3

source:
path: ..

build:
number: 0
script: {{ PYTHON }} -m pip install . -vvv

requirements:
build:
- {{ compiler('cxx') }}

host:
- python
- pip
- pybind11 >=2.10.0

run:
- python


test:
imports:
- whr
source_files:
- tests
commands:
- python tests/test_whr.py

about:
summary: A Python interface incorporating a C++ implementation of the Whole History Rating algorithm
license_file: LICENSE
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pybind11.setup_helpers import Pybind11Extension, build_ext


__version__ = "2.0.2"
__version__ = "2.0.3"

this_directory = Path(__file__).parent
long_description = (this_directory / "README.md").read_text(encoding="utf-8")
Expand Down
2 changes: 1 addition & 1 deletion src/player_day.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ PlayerDay::PlayerDay(const std::shared_ptr<Player> player, int time_step)
: player_(player), time_step_(time_step), is_first_day_(false),
won_game_terms_cache_initialized_(false),
draw_game_terms_cache_initialized_(false),
lost_game_terms_cache_initialized_(false), r_(0.) {}
lost_game_terms_cache_initialized_(false), r_(0.), uncertainty_(0.) {}

void PlayerDay::set_gamma(double gamma) { r_ = std::log(gamma); }

Expand Down
13 changes: 13 additions & 0 deletions tests/test_whr.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,23 @@ def test_output(self):
map(lambda x: list(map(round, x)), self.whr.ratings_for_player("shusai"))
)

def test_evaluate(self):
test_games = [
["shusaku", "shusai", "B", 1],
["shusaku", "shusai", "W", 2],
["shusaku", "shusai", "W", 3, 0],
["shusaku", "shusai", "W", 4, 0],
["shusaku", "shusai", "W", 4, 0],
]
evaluate = whr.Evaluate(self.whr)
test_log_likelihood = evaluate.evaluate_ave_log_likelihood_games(test_games)
assert round(test_log_likelihood * 100000) == -50215


def test_whr_class():
whrt = WholeHistoryRatingTest()
whrt.test_output()
whrt.test_evaluate()


if __name__ == "__main__":
Expand Down
8 changes: 4 additions & 4 deletions whr/evaluate.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ def evaluate_ave_log_likelihood_games(
A list of games as the test dataset.
Example:
```
[('Carol', [[0, 103.91877749030998, 180.55812567296852], [60, 107.30695193277168, 183.1250043094528]]),
('Alice', [[0, 78.50976252870765, 185.55230942797314], [30, 79.47183295485291, 187.12327376311526]]),
('Bob', [[10, -15.262552175731392, 180.95086989932025], [60, -18.086030877782818, 183.0820052639819]]),
('Dave', [[10, -176.67739359273045, 201.15282077913983], [30, -177.3187738768273, 202.03179750776144]])]
[['Alice', 'Carol', 'D', 0],
['Bob', 'Dave', 'B', 10],
['Dave', 'Alice', 'W', 30, 10.],
['Bob', 'Carol', 'W', 60, 20.]]
```
ignore_null_players : bool, optional
Expand Down

0 comments on commit d010962

Please sign in to comment.