TriMCTS
TriMCTS is an installable Python package providing C++ bindings for Monte Carlo Tree Search, supporting both AlphaZero and MuZero paradigms, optimized for triangular grid games like the one in trianglengin.
🔑 Key Features
- High-performance C++ core implementation.
- Seamless Python integration via Pybind11.
- Supports AlphaZero-style evaluation (policy/value from state).
- Batched Network Evaluations: Efficiently calls the Python network's
evaluate_batchmethod during search for improved performance, especially with GPUs. - MCTS Tree Reuse: Significantly speeds up sequential MCTS calls (e.g., during self-play) by reusing the relevant subtree from the previous search step. The C++ core manages the tree lifetime via opaque handles (
py::capsule) passed between Python calls. - (Planned) Supports MuZero-style evaluation (initial inference + recurrent inference).
- Configurable search parameters (simulation count, PUCT, discount factor, Dirichlet noise, batch size).
- Designed for use with external Python game state objects and network evaluators.
- Type-hinted Python API (
py.typedcompliant).
🚀 Installation
# From PyPI (once published)
pip install trimcts
# For development (from cloned repo root)
# Ensure you clean previous builds if you encounter issues:
# rm -rf build/ src/trimcts.egg-info/ dist/ src/trimcts/trimcts_cpp.*.so
pip install -e .[dev]
💡 Usage Example (AlphaZero Style with Tree Reuse)
import time
import numpy as np
import torch # Added import
# Use the actual GameState if trianglengin is installed
try:
from trianglengin import GameState, EnvConfig
HAS_TRIANGLENGIN = True
except ImportError:
# Define minimal mocks if trianglengin is not available
class GameState: # type: ignore
def __init__(self, *args, **kwargs): self.current_step = 0
def is_over(self): return False
def copy(self): return self
def step(self, action): return 0.0, False
def get_outcome(self): return 0.0
def valid_actions(self): return [0, 1]
class EnvConfig: pass # type: ignore
HAS_TRIANGLENGIN = False
# Assuming alphatriangle is installed and provides these:
# from alphatriangle.nn import NeuralNetwork # Example network wrapper
# from alphatriangle.config import ModelConfig, TrainConfig
from trimcts import run_mcts, SearchConfiguration, AlphaZeroNetworkInterface
# --- Mock Neural Network (same as before) ---
class MockNeuralNetwork:
def __init__(self, *args, **kwargs):
self.model = torch.nn.Module() # Dummy model
print("MockNeuralNetwork initialized.")
def evaluate_state(self, state: GameState) -> tuple[dict[int, float], float]:
valid_actions = state.valid_actions()
if not valid_actions: return {}, 0.0
policy = {action: 1.0 / len(valid_actions) for action in valid_actions}
value = 0.5
return policy, value
def evaluate_batch(self, states: list[GameState]) -> list[tuple[dict[int, float], float]]:
print(f" Mock evaluate_batch called with {len(states)} states.")
return [self.evaluate_state(s) for s in states]
def load_weights(self, path): print(f"Mock: Pretending to load weights from {path}")
def to(self, device): print(f"Mock: Pretending to move model to {device}"); return self
# --- End Mock Neural Network ---
# --- AlphaZero Wrapper (same as before) ---
class MyAlphaZeroWrapper(AlphaZeroNetworkInterface):
def __init__(self, model_path: str | None = None):
self.network = MockNeuralNetwork()
if model_path: self.network.load_weights(model_path)
self.network.model.eval()
print("MyAlphaZeroWrapper initialized.")
def evaluate_state(self, state: GameState) -> tuple[dict[int, float], float]:
print(f"Python: Evaluating SINGLE state step {state.current_step}")
policy_map, value = self.network.evaluate_state(state)
print(f"Python: Single evaluation result - Policy keys: {len(policy_map)}, Value: {value:.4f}")
return policy_map, value
def evaluate_batch(self, states: list[GameState]) -> list[tuple[dict[int, float], float]]:
print(f"Python: Evaluating BATCH of {len(states)} states.")
results = self.network.evaluate_batch(states)
print(f"Python: Batch evaluation returned {len(results)} results.")
return results
# --- Simulation Loop Example ---
env_config = EnvConfig()
if HAS_TRIANGLENGIN:
env_config.ROWS = 3
env_config.COLS = 3
env_config.NUM_SHAPE_SLOTS = 1
env_config.PLAYABLE_RANGE_PER_ROW = [(0,3), (0,3), (0,3)]
game_state = GameState(config=env_config, initial_seed=42)
network_wrapper = MyAlphaZeroWrapper()
mcts_config = SearchConfiguration()
mcts_config.max_simulations = 50
mcts_config.mcts_batch_size = 8
# --- Tree Reuse Variables ---
mcts_tree_handle = None # Start with no tree
last_action = -1 # No previous action initially
print("--- Running Self-Play Loop with Tree Reuse ---")
max_episode_steps = 10
for step in range(max_episode_steps):
if game_state.is_over():
print(f"\nGame over at step {step}. Final Score: {game_state.game_score()}")
break
print(f"\n--- Step {step} ---")
print(f"Current State Step: {game_state.current_step}")
print(f"Passing tree handle: {'Yes' if mcts_tree_handle else 'No'}")
print(f"Passing last action: {last_action}")
# Run MCTS, passing the handle and last action
# It returns visit counts AND the new handle
start_time = time.time()
visit_counts, mcts_tree_handle = run_mcts(
root_state=game_state,
network_interface=network_wrapper,
config=mcts_config,
previous_tree_handle=mcts_tree_handle, # Pass handle from previous step
last_action=last_action # Pass action that led to current state
)
end_time = time.time()
print(f"MCTS Result (Visit Counts) after {end_time - start_time:.3f} seconds:")
print(visit_counts)
print(f"Received new tree handle: {'Present' if mcts_tree_handle else 'None'}")
# Select best action based on visits
if not visit_counts:
print("MCTS returned no visits. Ending episode.")
break
best_action = max(visit_counts, key=visit_counts.get)
print(f"Selected Action: {best_action}")
# Store the selected action for the *next* MCTS call
last_action = best_action
# Apply the action to the game state
reward, done = game_state.step(best_action)
print(f"Step Reward: {reward:.3f}, Done: {done}")
else:
print(f"\nEpisode finished after {max_episode_steps} steps.")
# The mcts_tree_handle (a py::capsule) will be automatically garbage collected
# by Python when it goes out of scope, triggering the C++ destructor.
print("\n--- End of Simulation ---")
(MuZero example will be added later)
📂 Project Structure
trimcts/
├── .github/workflows/ # CI configuration (e.g., ci_cd.yml)
├── src/trimcts/ # Python package source ([src/trimcts/README.md](src/trimcts/README.md))
│ ├── cpp/ # C++ source code ([src/trimcts/cpp/README.md](src/trimcts/cpp/README.md))
│ │ ├── CMakeLists.txt # CMake build script for C++ part
│ │ ├── bindings.cpp # Pybind11 bindings
│ │ ├── config.h # C++ configuration struct
│ │ ├── mcts.cpp # C++ MCTS implementation (Node, simulation loop)
│ │ ├── mcts.h # C++ MCTS header
│ │ ├── mcts_manager.cpp # C++ MCTS Tree Manager implementation
│ │ ├── mcts_manager.h # C++ MCTS Tree Manager header (handles lifetime)
│ │ ├── python_interface.h # C++ helpers for Python interaction
│ │ └── structs.h # Common C++ structs (NetworkOutput, etc.)
│ ├── __init__.py # Exposes public API (run_mcts, configs, etc.)
│ ├── config.py # Python SearchConfiguration (Pydantic)
│ ├── mcts_wrapper.py # Python network interface definition & run_mcts wrapper
│ └── py.typed # Marker file for type checkers (PEP 561)
├── tests/ # Python tests ([tests/README.md](tests/README.md))
│ ├── conftest.py
│ └── test_alpha_wrapper.py # Tests for AlphaZero functionality
├── .gitignore
├── LICENSE
├── MANIFEST.in # Specifies files for source distribution
├── pyproject.toml # Build system & package configuration
├── README.md # This file
└── setup.py # Setup script for C++ extension building
🛠️ Building from Source
- Clone the repository:
git clone https://github.com/lguibr/trimcts.git - Navigate to the directory:
cd trimcts - Recommended: Create and activate a virtual environment:
python -m venv .venv source .venv/bin/activate # On Windows use `.venv\Scripts\activate`
- Install build dependencies:
pip install pybind11>=2.10 cmake wheel - Clean previous builds (important if switching Python versions or encountering issues):
rm -rf build/ src/trimcts.egg-info/ dist/ src/trimcts/trimcts_cpp.*.so
- Install the package in editable mode:
pip install -e .
🧪 Running Tests
# Make sure you have installed dev dependencies
pip install -e .[dev]
pytest
🤝 Contributing
Contributions are welcome! Please follow standard fork-and-pull-request workflow. Ensure tests pass and code adheres to formatting/linting standards (Ruff, MyPy).
📜 License
This project is licensed under the MIT License - see the LICENSE file for details.
Metadata
Release files for trimcts 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 5.0 MB
Release files / trimcts-1.3.0-cp312-cp312-win_amd64.whl
| Download URL | trimcts-1.3.0-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 183.0 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
69a3b4f3ce6b47865016125c8644fac010bb81f07fd4dc8a5a5158adc57436eb
|
|
BLAKE2b-256 checksum How to use checksums |
bd87d0ed0c5b9b602460be2163ff603be7e5b23449c10f03cb2ad15e4739542d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl
| Download URL | trimcts-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.12 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
c298929dc949c76425e104ac8b62126f52ebd4ed407dd6fc20dfb1bd20726efd
|
|
BLAKE2b-256 checksum How to use checksums |
7843b3bde20efe19bdb5ebfc0bfa65fdc1814d23420f30167d18b5cc1016b919
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | trimcts-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 218.6 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
b6215bfb848bf4ba351dc0934c6e1ab46af1f4ac3aaae8c9d085e4339afa98e2
|
|
BLAKE2b-256 checksum How to use checksums |
c13872aecbe0086de3476ee7492eb215dd7edc2b7d0b46e8f36f9b59f2fa3209
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp312-cp312-macosx_14_0_universal2.whl
| Download URL | trimcts-1.3.0-cp312-cp312-macosx_14_0_universal2.whl |
|---|---|
| Size | 90.3 kB |
| Tags | CPython 3.12 macOS 14.0+ universal2 (ARM64, x86-64) |
|
SHA-256 checksum How to use checksums |
c616d503495436b71cd1c9eea03ae83c33f145d97e09fe586e531c59b5436086
|
|
BLAKE2b-256 checksum How to use checksums |
27edf24c4f79aa0109bfcec85c1c9e48a4c96aae3289eae99880a80be4d3e9ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp311-cp311-win_amd64.whl
| Download URL | trimcts-1.3.0-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 181.8 kB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
60c914a149dea858be3bf971c1694b9a2be582b7a888147a2b0680e34aeed6e4
|
|
BLAKE2b-256 checksum How to use checksums |
054f6585b2aea9767ffbb097888e32e178f2b0032fec969a5fe7f5a037957656
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl
| Download URL | trimcts-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.11 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
4733c95704754d4664a340682dfd66a13df1e0249b9ca53f7ed9c6fb4d88cc78
|
|
BLAKE2b-256 checksum How to use checksums |
3788868e6e9142d9cec141dce305c8250fd508666e21013bd32487c121647503
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | trimcts-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 218.6 kB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
cb1e60e325ef94481125931c19f0c9bebf8d2bd6559d51f928f1a54cc6c6ce71
|
|
BLAKE2b-256 checksum How to use checksums |
cbd4470f79e60333cb850fab50c860661163ef0c864a4a153eaa25dab7f823e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp311-cp311-macosx_14_0_universal2.whl
| Download URL | trimcts-1.3.0-cp311-cp311-macosx_14_0_universal2.whl |
|---|---|
| Size | 90.5 kB |
| Tags | CPython 3.11 macOS 14.0+ universal2 (ARM64, x86-64) |
|
SHA-256 checksum How to use checksums |
e3fb82d622ada04b920ea04199181f681f9e298334d72192af2caab9a851970d
|
|
BLAKE2b-256 checksum How to use checksums |
29a392acfefe019426c163117ca7ce02c03817cd08b21a015ca9708bcb614763
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp310-cp310-win_amd64.whl
| Download URL | trimcts-1.3.0-cp310-cp310-win_amd64.whl |
|---|---|
| Size | 179.1 kB |
| Tags | CPython 3.10 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
018c760011b489068a2d33b0c6f85df4c6866329bd7972b1b1d9c13366d171c7
|
|
BLAKE2b-256 checksum How to use checksums |
11307a6e8d89bd9bebd5a1aaadadc98e95914fe4ec53183f6cde32360e1115b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl
| Download URL | trimcts-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
8bd91db5b7bf04fb2ad1f992ff8961cad13be98d323ecc70a6b7496e9d875047
|
|
BLAKE2b-256 checksum How to use checksums |
f5e6cec27d12fa5599e1d66615a46bd0ff677eeb5a026fe594d07f259f63705c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | trimcts-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 218.6 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
4ed806c4ff39d6534bb4f4a6d0d8eade7f46cb96c950f3b2c0de2e211e826091
|
|
BLAKE2b-256 checksum How to use checksums |
3003ec83eb658ffa935bd177ee124b63eb5c28bd85b963ae13b84b0920eeb3b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency logRelease files / trimcts-1.3.0-cp310-cp310-macosx_14_0_universal2.whl
| Download URL | trimcts-1.3.0-cp310-cp310-macosx_14_0_universal2.whl |
|---|---|
| Size | 89.2 kB |
| Tags | CPython 3.10 macOS 14.0+ universal2 (ARM64, x86-64) |
|
SHA-256 checksum How to use checksums |
63c24f34f1ca2ea5997ed9e5c6d57baaa02d96a33272e023f331f62d559364a5
|
|
BLAKE2b-256 checksum How to use checksums |
7703126270fcd62be5c3066dbb841280b0224519233c11876032f676c24df94e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 23, 2025.
Transparency log