From 9ab592ce3765d07b6dbdb9c1d9b62dc8045e784e Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Fri, 3 Apr 2026 02:46:12 +0800 Subject: feat: implement core term, symbol, and clause storage logic with canonicalization support --- include/atp/core/clause_store.h | 3 +++ include/atp/core/symbol_table.h | 4 ++++ include/atp/core/term.h | 20 +++++++++++--------- include/atp/core/term_bank.h | 38 +++++++++++++++++++++++++++++++++----- 4 files changed, 51 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/atp/core/clause_store.h b/include/atp/core/clause_store.h index 6e220cc..23db996 100644 --- a/include/atp/core/clause_store.h +++ b/include/atp/core/clause_store.h @@ -54,6 +54,9 @@ class ClauseStore { /// Iterate over all clauses with a visitor. void forEach(const std::function& visitor) const; + // function may have type erasure overhead, consider using a template + // template + // void forEach(Visitor&& visitor) const; private: std::vector clauses_; diff --git a/include/atp/core/symbol_table.h b/include/atp/core/symbol_table.h index ed27a4d..856c395 100644 --- a/include/atp/core/symbol_table.h +++ b/include/atp/core/symbol_table.h @@ -23,8 +23,10 @@ /// @brief Bidirectional mapping between symbol names and SymbolIds, /// with kind and sort metadata. +#include #include #include +#include #include "atp/core/types.h" @@ -63,6 +65,8 @@ class SymbolTable { private: // TODO: Phase 1 implementation + std::deque infos_; + std::unordered_map name_to_id_; }; } // namespace atp diff --git a/include/atp/core/term.h b/include/atp/core/term.h index e1edfcf..017882a 100644 --- a/include/atp/core/term.h +++ b/include/atp/core/term.h @@ -16,28 +16,30 @@ * along with this program. If not, see . */ - #pragma once /// @file term.h /// @brief Core Term data structure — hash-consed, immutable. +/// +/// V1 uses vector for args. +/// Future: flat arena with contiguous arg storage for cache locality. -#include +#include #include "atp/core/types.h" namespace atp { /// A term is a function/predicate application: f(t1, t2, ..., tn). -/// Stored in a flat arena; args are contiguous TermIds following the header. -/// Variables are represented as terms with a special symbol range. +/// Variables are 0-arity terms whose symbol has SymbolKind::kVariable. struct Term { - SymbolId symbol_id; ///< Index into the SymbolTable - uint16_t arity; ///< Number of arguments + SymbolId symbol_id; ///< Index into the SymbolTable + std::vector args; ///< Argument sub-term IDs - /// Access the argument TermIds (stored immediately after this struct in the arena). - [[nodiscard]] std::span args() const; - [[nodiscard]] std::span mutableArgs(); + /// Number of arguments. + [[nodiscard]] uint16_t arity() const { + return static_cast(args.size()); + } }; } // namespace atp diff --git a/include/atp/core/term_bank.h b/include/atp/core/term_bank.h index a121f8a..f909e2f 100644 --- a/include/atp/core/term_bank.h +++ b/include/atp/core/term_bank.h @@ -16,42 +16,70 @@ * along with this program. If not, see . */ - #pragma once /// @file term_bank.h /// @brief Hash-consing term pool — guarantees structural sharing. +#include "atp/core/symbol_table.h" #include "atp/core/term.h" #include "atp/core/types.h" #include +#include +#include namespace atp { /// Global term pool with hash-consing. /// Every structurally identical term maps to the same TermId. +/// +/// Holds a reference to SymbolTable for variable detection. class TermBank { public: - TermBank() = default; + /// TermBank needs the SymbolTable to distinguish variables from constants + /// (both have 0 args, but SymbolKind differs). + explicit TermBank(const SymbolTable& symbols) : symbols_(symbols) {} /// Create or retrieve a term. Returns the canonical TermId. TermId makeTerm(SymbolId symbol, std::span args); - /// Create a variable term. + /// Create a variable term. Convenience for makeTerm(var, {}). TermId makeVar(SymbolId var_symbol); /// Look up a term by its ID. [[nodiscard]] const Term& getTerm(TermId id) const; - /// Check if a TermId represents a variable. + /// Check if a TermId represents a variable (delegates to SymbolTable). [[nodiscard]] bool isVariable(TermId id) const; /// Total number of unique terms stored. [[nodiscard]] size_t size() const; + /// Access the underlying SymbolTable. + [[nodiscard]] const SymbolTable& symbols() const { return symbols_; } + private: - // TODO: Phase 1 implementation — flat arena + hash index + struct TermKey { + SymbolId symbol; + std::vector args; + + bool operator==(const TermKey& other) const = default; + }; + + struct TermKeyHash { + size_t operator()(const TermKey& key) const { + size_t seed = std::hash{}(key.symbol); + for (TermId arg : key.args) { + seed ^= std::hash{}(arg) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } + }; + + const SymbolTable& symbols_; + std::vector terms_; + std::unordered_map term_to_id_; }; } // namespace atp -- cgit v1.2.3