Skip to content
Open
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
2 changes: 1 addition & 1 deletion docs/c++_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Primary entry points:

Fields:

- `tt_kind_`: `TTKind::Small` or `TTKind::Large`
- `tt_kind_`: `TTKind::Pattern` (default), `TTKind::Large` or `TTKind::Small`
- `tt_mem_default_mb_`: default TT memory in MB
- `tt_mem_maximum_mb_`: maximum TT memory in MB

Expand Down
3 changes: 2 additions & 1 deletion library/src/api/dds_c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ DLLEXPORT int dds_c_calc_par_pbn(DDS_C_SOLVER_CTX ctx,
is decomposed into scalars rather than mirrored as a struct: passing a struct
by value is exactly the ABI question this shim exists to avoid, and a mirror
type would be a second definition to keep in sync. tt_kind: 0 = Small,
1 = Large (matching enum class TTKind). Returns NULL on failure. */
1 = Large, 2 = Pattern (matching enum class TTKind). Returns NULL on
failure. */
DLLEXPORT DDS_C_SOLVER_CTX dds_c_create_solvercontext(int tt_kind,
int def_mb, int max_mb);

Expand Down
61 changes: 48 additions & 13 deletions library/src/solver_context/solver_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,51 @@
#include <api/dds_data_types.hpp>
//#include <api/dds_api.hpp>
#include <trans_table/trans_table_l.hpp>
#include <trans_table/trans_table_p.hpp>
#include <trans_table/trans_table_s.hpp>
#include <utility/debug.h>

namespace {

/// Optional DDS_TT_KIND=small|large|pattern override of the configured kind.
auto tt_kind_from_environment(TTKind configured) -> TTKind
{
const char* s = std::getenv("DDS_TT_KIND");
if (s == nullptr) return configured;
const std::string value(s);
if (value == "small") return TTKind::Small;
if (value == "large") return TTKind::Large;
if (value == "pattern") return TTKind::Pattern;
return configured;
}

auto tt_kind_of(const TransTable* tt) -> TTKind
{
if (dynamic_cast<const TransTableS*>(tt) != nullptr) return TTKind::Small;
if (dynamic_cast<const TransTableP*>(tt) != nullptr) return TTKind::Pattern;
return TTKind::Large;
}

auto tt_kind_letter(TTKind kind) -> char
{
switch (kind) {
case TTKind::Small: return 'S';
case TTKind::Pattern: return 'P';
case TTKind::Large: break;
}
return 'L';
}

auto make_trans_table(TTKind kind) -> std::unique_ptr<TransTable>
{
switch (kind) {
case TTKind::Small: return std::make_unique<TransTableS>();
case TTKind::Pattern: return std::make_unique<TransTableP>();
case TTKind::Large: break;
}
return std::make_unique<TransTableL>();
}

#if defined(DDS_TOP_LEVEL) || defined(DDS_AB_STATS) || defined(DDS_AB_HITS) || \
defined(DDS_TT_STATS) || defined(DDS_TIMING) || defined(DDS_MOVES)
std::string next_debug_file_suffix()
Expand Down Expand Up @@ -68,8 +108,8 @@ auto SolverContext::trans_table() const -> TransTable*
auto SolverContext::SearchContext::trans_table() -> TransTable* {
if (tt_) return tt_.get();
// Require owner (for config and utilities). If missing, fall back
// to Large with built-in defaults.
TTKind kind = (owner_ ? owner_->config().tt_kind_ : TTKind::Large);
// to the SolverConfig default with built-in memory limits.
TTKind kind = tt_kind_from_environment(owner_ ? owner_->config().tt_kind_ : SolverConfig{}.tt_kind_);
int defMB = (owner_ ? owner_->config().tt_mem_default_mb_ : 0);
int maxMB = (owner_ ? owner_->config().tt_mem_maximum_mb_ : 0);
// Final fallback to THREADMEM_* constants
Expand All @@ -93,19 +133,15 @@ auto SolverContext::SearchContext::trans_table() -> TransTable* {
}
if (maxMB < defMB) maxMB = defMB;

// Create appropriate concrete table
if (kind == TTKind::Small)
tt_ = std::unique_ptr<TransTable>(new TransTableS());
else
tt_ = std::unique_ptr<TransTable>(new TransTableL());
tt_ = make_trans_table(kind);

tt_->set_memory_default(defMB);
tt_->set_memory_maximum(maxMB);
tt_->make_tt();

#ifdef DDS_UTILITIES_LOG
{
const char kch = (kind == TTKind::Small ? 'S' : 'L');
const char kch = tt_kind_letter(kind);
char buf[96];
std::snprintf(buf, sizeof(buf), "tt:create|%c|%d|%d", kch, defMB, maxMB);
if (owner_) owner_->utilities().log_append(std::string(buf));
Expand All @@ -120,7 +156,7 @@ auto SolverContext::SearchContext::trans_table() -> TransTable* {
if (const char* dbg = std::getenv("DDS_DEBUG_TT_CREATE")) {
if (*dbg) {
std::cerr << "[DDS] TT create: kind="
<< (kind == TTKind::Small ? 'S' : 'L')
<< tt_kind_letter(kind)
<< " defMB=" << defMB
<< " maxMB=" << maxMB
<< std::endl;
Expand Down Expand Up @@ -250,10 +286,9 @@ auto SolverContext::configure_tt(TTKind kind, int defMB, int maxMB) -> void
auto* tt = search_.maybe_trans_table();
if (!tt) return; // Nothing to apply now; will take effect on lazy creation.

// If kind changes, dispose and recreate now to ensure effect is applied.
bool is_small = (dynamic_cast<TransTableS*>(tt) != nullptr);
TTKind current_kind = is_small ? TTKind::Small : TTKind::Large;
if (current_kind != kind) {
// If the effective kind (environment override included, as at creation)
// changes, dispose and recreate now to ensure effect is applied.
if (tt_kind_of(tt) != tt_kind_from_environment(kind)) {
dispose_trans_table();
// Force immediate creation with new config to keep behavior explicit.
(void)trans_table();
Expand Down
9 changes: 7 additions & 2 deletions library/src/solver_context/solver_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@

// Minimal configuration scaffold for future expansion.
// TT configuration without depending on Memory headers.
enum class TTKind { Small, Large };
/// Transposition table implementation:
/// - Small: pool-based, low memory (TransTableS)
/// - Large: paged, flat per-shape entry lists (TransTableL)
/// - Pattern: shape → generality-ordered relative-rank patterns (TransTableP)
/// The integer values are part of the C ABI (dds_c_create_solvercontext).
enum class TTKind { Small = 0, Large = 1, Pattern = 2 };

/**
* @brief Configuration options for SolverContext instances.
Expand All @@ -31,7 +36,7 @@ enum class TTKind { Small, Large };
*/
struct SolverConfig
{
TTKind tt_kind_ = TTKind::Large;
TTKind tt_kind_ = TTKind::Pattern;
int tt_mem_default_mb_ = 0;
int tt_mem_maximum_mb_ = 0;
};
Expand Down
4 changes: 4 additions & 0 deletions library/src/trans_table/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ cc_library(
name = "trans_table",
srcs = [
"trans_table_l.cpp",
"trans_table_p.cpp",
"trans_table_s.cpp",
],
hdrs = [
"trans_table.hpp",
"trans_table_l.hpp",
"trans_table_p.hpp",
"trans_table_s.hpp",
],
visibility = ["//visibility:public"],
Expand All @@ -28,11 +30,13 @@ cc_library(
name = "testable_trans_table",
srcs = [
"trans_table_l.cpp",
"trans_table_p.cpp",
"trans_table_s.cpp",
],
hdrs = [
"trans_table.hpp",
"trans_table_l.hpp",
"trans_table_p.hpp",
"trans_table_s.hpp",
],
copts = DDS_CPPOPTS,
Expand Down
21 changes: 13 additions & 8 deletions library/src/trans_table/trans_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
*/

/*
This is the parent class of TransTableS and TransTableL.
Those two are different implementations. The S version has a
much smaller memory and a somewhat slower execution time.
This is the parent class of TransTableP, TransTableL and TransTableS.
They are different implementations of the same interface: P (the
default) stores shape-keyed relative-rank patterns, L is the paged
table with harvesting, and S has a much smaller memory footprint and a
somewhat slower execution time.
*/

#pragma once
Expand Down Expand Up @@ -78,14 +80,17 @@ struct NodeCards // 8 bytes
///
/// TransTable defines the interface for managing cached positions during
/// double dummy analysis. The transposition table stores previously computed
/// results to avoid redundant search work. Two implementations are provided:
/// - TransTableS: Memory-efficient small transposition table
/// results to avoid redundant search work. Three implementations are provided:
/// - TransTableP: Shape-keyed relative-rank patterns (the default)
/// - TransTableL: Full-featured large transposition table with paging
/// - TransTableS: Memory-efficient small transposition table
///
/// \par Memory Management Strategy
/// Implementations use different memory strategies. TransTableS uses a pool-based
/// approach with malloc/calloc, while TransTableL uses paged memory with
/// harvesting. Both support configurable memory limits and graceful degradation.
/// Implementations use different memory strategies. TransTableP grows on
/// demand and clears itself when the next allocation would exceed the maximum,
/// TransTableL uses paged memory with harvesting, and TransTableS uses a
/// pool-based approach with malloc/calloc. All support configurable memory
/// limits and graceful degradation.
///
/// \par Thread Safety
/// Not thread-safe. The transposition table must be accessed from a single
Expand Down
Loading