Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions docs/release_notes/draft_v3_1_0.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ points:
- `solve_all_boards_pbn`, `solve_all_boards_bin` — batch solving, parallelised
across hardware threads inside the library.
- `dealer_par` — par contracts from the dealer's perspective.
- `initialise_static_memory` (replaces the deprecated `set_max_threads`; the
C equivalent is spelled `InitializeStaticMemory` — the Python module currenly uses some British spelling, we plan to settle on American English throughout).
- `initialize_static_memory` (mirrors the C-side `SetMaxThreads` →
`InitializeStaticMemory` deprecation).

All of these release the GIL around the native call and validate their inputs.
Batch entry points accept an optional `max_threads`.
Expand All @@ -58,7 +58,6 @@ Batch entry points accept an optional `max_threads`.
empty table on next use.
- Thin LTO on macOS builds, inlined hot accessors, and native WASM exception
handling.

- **New performance tooling** — utilities for comparing solver performance
between two commits, and for recording warm benchmarks from a live consumer.
The comparison below (18-core Mac) shows solver performance is back at 2.9
Expand Down Expand Up @@ -91,8 +90,8 @@ TOTAL calc 9.35 123.59 8.42
`TransTableS::reset_memory` after memory release.
- **Par output now names the declaring seat** when successive par contracts
differ, in both the C++ and .NET paths.
- Worker exceptions in parallel board solving are reported as `RETURN_UNKNOWN_FAULT`
rather than terminating the process.
- Worker exceptions in parallel board solving are reported as `RETURN_UNKNOWN_FAULT`
rather than terminating the process.

### New public C API

Expand Down Expand Up @@ -133,12 +132,15 @@ name still works and no longer influences batch parallelism.

## Compatibility

No breaking changes for 3.0 consumers. The only deprecation is `SetMaxThreads`,
No API breaks for 3.0 consumers. The only deprecation is `SetMaxThreads`,
which remains available as an alias.

`SolveAllBoards*/CalcAllTables*` now spawn threads by default where 3.0 was sequential;
the `*Seq` variant opts out. There is also a bug fix which changes the
output from AnalysePlay*.
`SolveAllBoards*`/`CalcAllTables*` now spawn threads by default where 3.0 was
sequential; pass `maxThreads = 1` to the `*N`/`*X` variants, or call
`SolveAllBoardsSeq`/`SolveAllBoardsBinSeq`, to stay on one thread. The
[incorrect results with v3 #156](https://github.com/dds-bridge/dds/issues/156)
fix changes the trick counts returned by `AnalysePlay*`; they were previously
under-counted.

## Contributors

Expand Down
4 changes: 2 additions & 2 deletions library/src/api/dll.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,10 +429,10 @@ struct DDSInfo


/**
* @brief Initialise the solver's static memory.
* @brief Initialize the solver's static memory.
*
* Allocates the transposition-table memory pools, registers scheduler and
* thread-manager state, and performs one-time lookup-table initialisation.
* thread-manager state, and performs one-time lookup-table initialization.
* This does NOT control the number of worker threads — use the
* SolveAllBoardsN / CalcAllTablesN family for per-call thread caps.
*/
Expand Down
2 changes: 1 addition & 1 deletion library/src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ int _initialized = 0;


/*
* Initialise the solver's static memory: TT memory pools, scheduler /
* Initialize the solver's static memory: TT memory pools, scheduler /
* thread-manager state, and one-time lookup-table setup.
*
* Public API documentation is maintained in the API headers.
Expand Down
2 changes: 1 addition & 1 deletion library/tests/system/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ filegroup(
visibility = ["//python:__pkg__"],
)

# max_threads override equivalence + rename/alias initialisation test
# max_threads override equivalence + rename/alias initialization test
cc_test(
name = "max_threads_equivalence_test",
size = "small",
Expand Down
6 changes: 3 additions & 3 deletions library/tests/system/max_threads_equivalence_test.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// @file max_threads_equivalence_test.cpp
/// @brief Tests that the *N batch APIs honour maxThreads and stay equivalent to
/// the auto path, plus that the rename/alias both initialise the library.
/// the auto path, plus that the rename/alias both initialize the library.

#include <gtest/gtest.h>
#include <cstring>
Expand Down Expand Up @@ -102,7 +102,7 @@ TEST(MaxThreadsEquivalence, SolveAllBoardsBinNMatchesAuto)
const FutureTricks& fa = solved_auto.solved_board[b];
const FutureTricks& fo = solved_one.solved_board[b];
ASSERT_EQ(fa.cards, fo.cards) << "card count differs at board=" << b;
// Only the first `cards` entries are meaningful; the tail is uninitialised.
// Only the first `cards` entries are meaningful; the tail is uninitialized.
for (int c = 0; c < fa.cards; c++)
{
EXPECT_EQ(fa.suit[c], fo.suit[c]) << "suit at board=" << b << " c=" << c;
Expand All @@ -122,7 +122,7 @@ TEST(MaxThreadsEquivalence, InitializeStaticMemoryThenSolve)
EXPECT_EQ(CalcDDtable(deal, &table), RETURN_NO_FAULT);
}

// The deprecated SetMaxThreads alias still initialises the library.
// The deprecated SetMaxThreads alias still initializes the library.
TEST(MaxThreadsEquivalence, DeprecatedSetMaxThreadsAliasStillWorks)
{
SetMaxThreads(1);
Expand Down
6 changes: 3 additions & 3 deletions python/dds3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from ._dds3 import calc_par
from ._dds3 import calc_par_from_table
from ._dds3 import dealer_par
from ._dds3 import initialise_static_memory
from ._dds3 import initialize_static_memory
from ._dds3 import module_name
from ._dds3 import par
from ._dds3 import set_max_threads
Expand All @@ -26,7 +26,7 @@
from _dds3 import calc_par
from _dds3 import calc_par_from_table
from _dds3 import dealer_par
from _dds3 import initialise_static_memory
from _dds3 import initialize_static_memory
from _dds3 import module_name
from _dds3 import par
from _dds3 import set_max_threads
Expand All @@ -45,7 +45,7 @@
"calc_par",
"calc_par_from_table",
"dealer_par",
"initialise_static_memory",
"initialize_static_memory",
"module_name",
"par",
"set_max_threads",
Expand Down
16 changes: 8 additions & 8 deletions python/src/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,33 +609,33 @@ auto register_calc_par_bindings(py::module_& module) -> void

auto register_analysis_bindings(py::module_& module) -> void
{
// initialise_static_memory: allocate the solver's static memory pools and
// perform one-time lookup-table initialisation. This does NOT control the
// initialize_static_memory: allocate the solver's static memory pools and
// perform one-time lookup-table initialization. This does NOT control the
// worker-thread count; use solve_all_boards_* (which parallelise across the
// machine's hardware threads automatically) or one SolverContext per worker
// thread for per-board concurrency.
module.def(
"initialise_static_memory",
"initialize_static_memory",
[]() {
py::gil_scoped_release release;
InitializeStaticMemory();
},
"Initialise the solver's static memory.\n\n"
"Initialize the solver's static memory.\n\n"
"Allocates the transposition-table memory pools and performs one-time\n"
"lookup-table initialisation. This does NOT control the number of worker\n"
"lookup-table initialization. This does NOT control the number of worker\n"
"threads: solve_all_boards_* parallelise across the machine's hardware\n"
"threads automatically, and for per-board concurrency from Python you\n"
"create one SolverContext per worker thread and pass it to solve_board /\n"
"solve_board_pbn.");

// set_max_threads: DEPRECATED alias of initialise_static_memory. The thread
// set_max_threads: DEPRECATED alias of initialize_static_memory. The thread
// count argument is ignored; retained only for backward compatibility.
module.def(
"set_max_threads",
[](const int user_threads) {
if (PyErr_WarnEx(
PyExc_DeprecationWarning,
"set_max_threads() is deprecated; use initialise_static_memory(). "
"set_max_threads() is deprecated; use initialize_static_memory(). "
"The user_threads argument is ignored.",
1) != 0) {
throw py::error_already_set();
Expand All @@ -644,7 +644,7 @@ auto register_analysis_bindings(py::module_& module) -> void
SetMaxThreads(user_threads);
},
py::arg("user_threads") = 0,
"DEPRECATED: use initialise_static_memory() instead.\n\n"
"DEPRECATED: use initialize_static_memory() instead.\n\n"
"Legacy thread-resource hook (wraps the deprecated SetMaxThreads C API,\n"
"now a thin alias of InitializeStaticMemory). Calling this emits a\n"
"DeprecationWarning.\n\n"
Expand Down
2 changes: 2 additions & 0 deletions python/tests/test_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dds3 import calc_dd_table
from dds3 import calc_par
from dds3 import calc_par_from_table
from dds3 import initialize_static_memory
from dds3 import module_name
from dds3 import par
from dds3 import SolverContext
Expand All @@ -27,6 +28,7 @@ def test_import_and_api_root(self) -> None:
self.assertTrue(callable(par))
self.assertTrue(callable(calc_par))
self.assertTrue(callable(calc_par_from_table))
self.assertTrue(callable(initialize_static_memory))
self.assertIsNotNone(SolverContext)

# Verify SolverContext can be instantiated.
Expand Down
10 changes: 5 additions & 5 deletions specs/lookup-tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ last-updated: 2026-07-18

> **Specs vs. doxygen.** Each table's exact indexing and return encoding is
> documented inline in `lookup_tables.hpp`. This spec records what the tables are
> collectively, their initialisation/immutability contract, and who depends on
> collectively, their initialization/immutability contract, and who depends on
> them.

## Purpose
Expand All @@ -34,14 +34,14 @@ inner loops of [move-generation](move-generation.md) and the search index these
`win_ranks[8192][14]` (bitmask of the top-N cards), and `group_data[8192]`
(`MoveGroupType` run decomposition — up to 7 runs of adjacent ranks with their
top card, tail sequence, full sequence, and inter-run gaps).
- **Initialised once, eagerly, at startup.** `init_lookup_tables()` fills the
storage via static initialisation (`DdsLutInitGuard`), guarded by
- **Initialized once, eagerly, at startup.** `init_lookup_tables()` fills the
storage via static initialization (`DdsLutInitGuard`), guarded by
`std::call_once`. It is **thread-safe, idempotent, and a no-op after startup** —
explicit calls are safe but redundant. No consumer needs to initialise them.
explicit calls are safe but redundant. No consumer needs to initialize them.
- **Read-only and immutable after init.** The tables are exposed as `const`
references to fixed-size arrays, giving zero-overhead direct indexing
(`highest_rank[aggr]`, `rel_rank[aggr][rank]`). Any thread may read them
concurrently; nothing mutates them post-initialisation.
concurrently; nothing mutates them post-initialization.
- **`MoveGroupType` is the run-decomposition contract** consumed by move
generation: `last_group_` (−1 for empty, up to 6), and per-group `rank_`,
`sequence_`, `fullseq_`, and `gap_` arrays. `rank_`, `sequence_` and
Expand Down
2 changes: 1 addition & 1 deletion specs/move-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ and transposition-table hits. `Moves` is an internal component — it is not par
void situation (0–3 hands void), 13 categories total. It indexes the statistics
tables and the heuristic's per-situation tracking.
- **Invariants are assertion-checked.** Public methods assume valid input and
prior initialisation; violations trip asserts in debug builds. The move-finding
prior initialization; violations trip asserts in debug builds. The move-finding
methods signal "no move" by returning `nullptr`, not by throwing.
- **Statistics/printing are diagnostic-only** and emit under `DDS_MOVES` /
`DDS_MOVES_DETAILS` (see [constants-and-debug](constants-and-debug.md)); they are off the hot path in
Expand Down
4 changes: 2 additions & 2 deletions specs/python-binding.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ context API and the flat API from [dds-public-api](dds-public-api.md).
- **Public surface is the package `__all__`.** `python/dds3/__init__.py` re-exports
the extension symbols; see that list and `docs/python_interface.md` rather than
duplicating names here. Notable capability-wide pieces: a Python `SolverContext`
for TT reuse, and `initialise_static_memory` for lookup-table setup. Note
for TT reuse, and `initialize_static_memory` for lookup-table setup. Note
`set_max_threads` is exported but **deprecated** — it is an alias of
`initialise_static_memory` that ignores its argument and warns; it does not set
`initialize_static_memory` that ignores its argument and warns; it does not set
a worker count.
- **In-package native staging is platform-specific.** `_dds3_in_package` copies
the built extension into `dds3/` under the filename Python expects —
Expand Down