diff --git a/.github/workflows/windows.yml b/.github/disabled/windows-no-vcpkg.yml similarity index 100% rename from .github/workflows/windows.yml rename to .github/disabled/windows-no-vcpkg.yml diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index b65b7163fa..0ea4241964 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -12,7 +12,13 @@ jobs: - name: Create Build Dir run: cmake -E make_directory ${{github.workspace}}/build - name: Pre-Install Boost, LevelDB - run: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" && ( brew install boost-python3 snappy leveldb || brew install boost-python3 snappy leveldb ) + uses: nick-fields/retry@v2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + brew install boost-python3 snappy leveldb - name: Configure working-directory: ${{github.workspace}}/build run: cmake ${{github.workspace}} -GXcode -DOPENMIND_BUILD_SAMPLES=OFF -DOPENMIND_BUILD_TESTS=ON -Dleveldb_TAG:STRING="1.23" -DOPENMIND_MATH_USE_LEVELDB_CACHE=OFF -DOPENMIND_STORAGE_LEVELDB=OFF diff --git a/.github/workflows/maintain-after-main.yml b/.github/workflows/maintain-after-main.yml index f7193baa68..fd78b643b5 100644 --- a/.github/workflows/maintain-after-main.yml +++ b/.github/workflows/maintain-after-main.yml @@ -34,7 +34,7 @@ jobs: - name: Configure working-directory: ${{github.workspace}}/build - run: cmake ${{github.workspace}} -DOPENMIND_BUILD_SAMPLES=OFF -DOPENMIND_BUILD_TESTS=OFF -DOPENMIND_USE_OPENCL=OFF -G "Ninja Multi-Config" + run: cmake ${{github.workspace}} -DOPENMIND_BUILD_SAMPLES=NO -DOPENMIND_BUILD_TESTS=NO -DOPENMIND_USE_OPENCL=NO -DOPENMIND_BUILD_UTIILS=ON -G "Ninja Multi-Config" - name: Build maintain target working-directory: ${{github.workspace}}/build diff --git a/.github/workflows/pr-review-comment-reaction.yml b/.github/workflows/pr-review-comment-reaction.yml index 21d789eb9a..c7abe56223 100644 --- a/.github/workflows/pr-review-comment-reaction.yml +++ b/.github/workflows/pr-review-comment-reaction.yml @@ -116,24 +116,24 @@ jobs: // Add try/catch block const indentation = scriptContent.match(/^(\s*)/)[1]; const updatedScriptBlock = `script: | - try { - ${scriptContent.trim().split('\n').map(line => ' ' + line).join('\n')} - } catch (error) { - console.error(\`Error in workflow execution: \${error.message}\`); - // Optionally create a simpler issue with error details - try { - const { data: errorIssue } = await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: \`Error in workflow execution\`, - body: \`The workflow encountered an error: \${error.message}\`, - labels: ["automation", "bug"] - }); - console.log(\`Created error issue: \${errorIssue.html_url}\`); - } catch (issueError) { - console.error(\`Failed to create error issue: \${issueError.message}\`); - } - }`; + try { + ${scriptContent.trim().split('\n').map(line => ' ' + line).join('\n')} + } catch (error) { + console.error(\`Error in workflow execution: \${error.message}\`); + // Optionally create a simpler issue with error details + try { + const { data: errorIssue } = await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: \`Error in workflow execution\`, + body: \`The workflow encountered an error: \${error.message}\`, + labels: ["automation", "bug"] + }); + console.log(\`Created error issue: \${errorIssue.html_url}\`); + } catch (issueError) { + console.error(\`Failed to create error issue: \${issueError.message}\`); + } + }`; content = content.replace(scriptBlock, updatedScriptBlock); } diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index cd485ab726..15f48a5e34 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -8,9 +8,9 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Cache dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | /var/cache/apt @@ -20,7 +20,15 @@ jobs: restore-keys: | ${{ runner.os }}-apt- - name: OS prerequisites - run: sudo add-apt-repository -y ppa:mhier/libboost-latest && sudo apt update && sudo apt upgrade -y && sudo apt install -y libboost1.83-all-dev libxss-dev libx11-dev libxcb-screensaver0-dev ocl-icd-opencl-dev libopengl-dev freeglut3-dev libleveldb-dev libsnappy-dev libvulkan-dev liblz4-dev libfmt-dev librocksdb-dev libpython3-all-dev libopencl-clang-dev libtbb-dev ninja-build + uses: nick-fields/retry@v2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + sudo add-apt-repository -y ppa:mhier/libboost-latest + sudo apt update + sudo apt upgrade -y + sudo apt install -y libboost1.83-all-dev libxss-dev libx11-dev libxcb-screensaver0-dev ocl-icd-opencl-dev libopengl-dev freeglut3-dev libleveldb-dev libsnappy-dev libvulkan-dev liblz4-dev libfmt-dev librocksdb-dev libpython3-all-dev libopencl-clang-dev libtbb-dev ninja-build - name: Create Build Dir run: cmake -E make_directory ${{github.workspace}}/build - name: Configure diff --git a/.github/workflows/vcpkg.yml b/.github/workflows/vcpkg.yml index 8be3f600a9..b71df2b35f 100644 --- a/.github/workflows/vcpkg.yml +++ b/.github/workflows/vcpkg.yml @@ -40,25 +40,33 @@ jobs: - name: Install dependencies (Ubuntu) if: runner.os == 'Linux' - run: | - sudo apt-get update - sudo apt-get install -y build-essential cmake ninja-build autoconf automake autoconf-archive - cmake --version - ninja --version - gcc --version - g++ --version + uses: nick-fields/retry@v2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + sudo apt-get update + sudo apt-get install -y build-essential cmake ninja-build autoconf automake autoconf-archive + cmake --version + ninja --version + gcc --version + g++ --version - name: Install dependencies (macOS) if: runner.os == 'macOS' env: VCPKG_PYTHON3: $(which python3) - run: | - echo "VCPKG_PYTHON3=$VCPKG_PYTHON3" >> $GITHUB_ENV - brew update - brew install cmake ninja autoconf automake autoconf-archive - cmake --version - ninja --version - clang --version + uses: nick-fields/retry@v2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + echo "VCPKG_PYTHON3=$VCPKG_PYTHON3" >> $GITHUB_ENV + brew update || brew update || brew update || brew update || brew update + brew install cmake ninja autoconf automake autoconf-archive + cmake --version + ninja --version + clang --version - name: Install dependencies (Windows) if: runner.os == 'Windows' diff --git a/OpenMind/CMakeLists.txt b/OpenMind/CMakeLists.txt index cf07e224a0..8469e04f76 100644 --- a/OpenMind/CMakeLists.txt +++ b/OpenMind/CMakeLists.txt @@ -17,7 +17,9 @@ SET(${this_target}_HEADER_FILES Goal.h GoalGenerator.h GoalGeneratorBase.h + HierarchicalKnowledgeMatrix.h IdleTimeGoalGenerator.h + LogicOffloadFacility.h Mind.h Named.h ReachGoal.h @@ -84,6 +86,10 @@ SOURCE_GROUP("Facilities" FILES Facility.h FunctorFacility.cpp FunctorFacility.h + HierarchicalKnowledgeMatrix.cpp + HierarchicalKnowledgeMatrix.h + LogicOffloadFacility.cpp + LogicOffloadFacility.h ReachGoal.cpp ReachGoal.h RunProcess.cpp diff --git a/OpenMind/HierarchicalKnowledgeMatrix.cpp b/OpenMind/HierarchicalKnowledgeMatrix.cpp new file mode 100644 index 0000000000..9839229795 --- /dev/null +++ b/OpenMind/HierarchicalKnowledgeMatrix.cpp @@ -0,0 +1,289 @@ +#include "stdafx.h" +#include "HierarchicalKnowledgeMatrix.h" +#include +#include + +// HierarchicalKnowledgeMatrix implementation + +HierarchicalKnowledgeMatrix::HierarchicalKnowledgeMatrix( + size_t rows, size_t cols, value_t default_value) + : rows_(rows), cols_(cols), default_value_(default_value) { +} + +HierarchicalKnowledgeMatrix::value_t HierarchicalKnowledgeMatrix::GetValue( + size_t row, size_t col, const std::vector& depth) const { + + // Check bounds + if (row >= rows_ || col >= cols_) { + return default_value_; + } + + // If depth is empty, get value from this matrix + if (depth.empty()) { + position_t pos = {row, col}; + auto it = matrix_.find(pos); + if (it != matrix_.end()) { + return it->second; + } + return default_value_; + } + + // Otherwise, follow the path through deeper matrices + position_t current_pos = depth.front(); + auto deeper_it = deeper_matrices_.find(current_pos); + if (deeper_it == deeper_matrices_.end()) { + return default_value_; + } + + // Create a new depth vector without the first element + std::vector new_depth(depth.begin() + 1, depth.end()); + return deeper_it->second->GetValue(row, col, new_depth); +} + +void HierarchicalKnowledgeMatrix::SetValue( + size_t row, size_t col, value_t value, const std::vector& depth) { + + // Check bounds + if (row >= rows_ || col >= cols_) { + return; + } + + // If depth is empty, set value in this matrix + if (depth.empty()) { + position_t pos = {row, col}; + if (std::abs(value - default_value_) < 1e-10) { + // If value is close to default, remove it from the sparse matrix + matrix_.erase(pos); + } else { + matrix_[pos] = value; + } + return; + } + + // Otherwise, follow the path through deeper matrices + position_t current_pos = depth.front(); + auto deeper_it = deeper_matrices_.find(current_pos); + if (deeper_it == deeper_matrices_.end()) { + // Create a new deeper matrix if it doesn't exist + position_t pos = current_pos; + matrix_[pos] = 0.0; // Mark as pointer to deeper matrix + deeper_matrices_[pos] = std::make_unique( + rows_, cols_, default_value_); + deeper_it = deeper_matrices_.find(pos); + } + + // Create a new depth vector without the first element + std::vector new_depth(depth.begin() + 1, depth.end()); + deeper_it->second->SetValue(row, col, value, new_depth); +} + +HierarchicalKnowledgeMatrix* HierarchicalKnowledgeMatrix::AddDeeperMatrix( + size_t row, size_t col) { + + // Check bounds + if (row >= rows_ || col >= cols_) { + return nullptr; + } + + position_t pos = {row, col}; + matrix_[pos] = 0.0; // Mark as pointer to deeper matrix + + auto& deeper_matrix = deeper_matrices_[pos]; + if (!deeper_matrix) { + deeper_matrix = std::make_unique( + rows_, cols_, default_value_); + } + + return deeper_matrix.get(); +} + +bool HierarchicalKnowledgeMatrix::HasDeeperMatrix(size_t row, size_t col) const { + position_t pos = {row, col}; + return deeper_matrices_.find(pos) != deeper_matrices_.end(); +} + +HierarchicalKnowledgeMatrix* HierarchicalKnowledgeMatrix::GetDeeperMatrix( + size_t row, size_t col) { + + position_t pos = {row, col}; + auto it = deeper_matrices_.find(pos); + if (it != deeper_matrices_.end()) { + return it->second.get(); + } + return nullptr; +} + +void HierarchicalKnowledgeMatrix::UpdateProbabilities( + const std::map& evidence, + const std::vector& depth) { + + // If depth is empty, update this matrix + if (depth.empty()) { + for (const auto& ev : evidence) { + position_t pos = ev.first; + value_t prob = ev.second; + + if (HasDeeperMatrix(pos.first, pos.second)) { + // If this is a pointer to a deeper matrix, update that matrix + deeper_matrices_[pos]->UpdateProbabilities(evidence); + } else { + // Simple Bayesian update + value_t current_prob = GetValue(pos.first, pos.second); + + // P(A|B) = P(B|A) * P(A) / P(B) + // Here we use a simplified update rule + value_t updated_prob = (prob * current_prob) / + (prob * current_prob + (1 - prob) * (1 - current_prob)); + + SetValue(pos.first, pos.second, updated_prob); + } + } + return; + } + + // Otherwise, follow the path through deeper matrices + position_t current_pos = depth.front(); + auto deeper_it = deeper_matrices_.find(current_pos); + if (deeper_it != deeper_matrices_.end()) { + std::vector new_depth(depth.begin() + 1, depth.end()); + deeper_it->second->UpdateProbabilities(evidence, new_depth); + } +} + +std::pair HierarchicalKnowledgeMatrix::GetDimensions() const { + return {rows_, cols_}; +} + +HierarchicalKnowledgeMatrix::value_t HierarchicalKnowledgeMatrix::GetDefaultValue() const { + return default_value_; +} + +std::vector> +HierarchicalKnowledgeMatrix::ToDense(bool include_deeper) const { + std::vector> dense(rows_, std::vector(cols_, default_value_)); + + // Fill in non-default values + for (const auto& entry : matrix_) { + position_t pos = entry.first; + dense[pos.first][pos.second] = entry.second; + } + + // Mark positions with deeper matrices + if (include_deeper) { + for (const auto& entry : deeper_matrices_) { + position_t pos = entry.first; + dense[pos.first][pos.second] = -1.0; // Use -1 to indicate deeper matrix + } + } + + return dense; +} + +// HierarchicalKnowledgeMatrixFacility implementation + +HierarchicalKnowledgeMatrixFacility::HierarchicalKnowledgeMatrixFacility( + std::function connector, + size_t rows, size_t cols, double default_value) + : FunctorFacility(connector) { + + matrix_ = std::make_shared(rows, cols, default_value); +} + +double HierarchicalKnowledgeMatrixFacility::GetValue( + size_t row, size_t col, const std::vector& depth) const { + + return matrix_->GetValue(row, col, depth); +} + +void HierarchicalKnowledgeMatrixFacility::SetValue( + size_t row, size_t col, double value, const std::vector& depth) { + + matrix_->SetValue(row, col, value, depth); +} + +void HierarchicalKnowledgeMatrixFacility::AddDeeperMatrix(size_t row, size_t col) { + matrix_->AddDeeperMatrix(row, col); +} + +void HierarchicalKnowledgeMatrixFacility::UpdateProbabilities( + const std::map& evidence, const std::vector& depth) { + + matrix_->UpdateProbabilities(evidence, depth); +} + +std::vector +HierarchicalKnowledgeMatrixFacility::GetLowProbabilityCells( + double threshold, double confidence_threshold, position_t confidence_position) const { + + std::vector low_prob_cells; + auto dims = matrix_->GetDimensions(); + + // Convert to dense for easier processing + auto dense = matrix_->ToDense(); + + // Find cells with probability below threshold + for (size_t row = 0; row < dims.first; ++row) { + for (size_t col = 0; col < dims.second; ++col) { + double prob = dense[row][col]; + + if (prob <= threshold) { + // Check confidence if there's a deeper matrix + if (matrix_->HasDeeperMatrix(row, col)) { + auto deeper = matrix_->GetDeeperMatrix(row, col); + double confidence = deeper->GetValue( + confidence_position.first, confidence_position.second); + + if (confidence >= confidence_threshold) { + low_prob_cells.push_back({row, col}); + } + } else { + // No confidence information, use probability only + low_prob_cells.push_back({row, col}); + } + } + } + } + + return low_prob_cells; +} + +std::vector +HierarchicalKnowledgeMatrixFacility::GetHighProbabilityCells( + double threshold, double confidence_threshold, position_t confidence_position) const { + + std::vector high_prob_cells; + auto dims = matrix_->GetDimensions(); + + // Convert to dense for easier processing + auto dense = matrix_->ToDense(); + + // Find cells with probability above threshold + for (size_t row = 0; row < dims.first; ++row) { + for (size_t col = 0; col < dims.second; ++col) { + double prob = dense[row][col]; + + if (prob >= threshold) { + // Check confidence if there's a deeper matrix + if (matrix_->HasDeeperMatrix(row, col)) { + auto deeper = matrix_->GetDeeperMatrix(row, col); + double confidence = deeper->GetValue( + confidence_position.first, confidence_position.second); + + if (confidence >= confidence_threshold) { + high_prob_cells.push_back({row, col}); + } + } else { + // No confidence information, use probability only + high_prob_cells.push_back({row, col}); + } + } + } + } + + return high_prob_cells; +} + +HierarchicalKnowledgeMatrixFacility::matrix_ptr_t +HierarchicalKnowledgeMatrixFacility::GetMatrix() const { + return matrix_; +} diff --git a/OpenMind/HierarchicalKnowledgeMatrix.h b/OpenMind/HierarchicalKnowledgeMatrix.h new file mode 100644 index 0000000000..34bea2f0aa --- /dev/null +++ b/OpenMind/HierarchicalKnowledgeMatrix.h @@ -0,0 +1,233 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "Facility.h" +#include "FunctorFacility.h" + +namespace omnn { +namespace math { +class Valuable; +class Variable; +} +} + +/** + * @brief HierarchicalKnowledgeMatrix provides a multi-dimensional knowledge representation + * + * This class implements a hierarchical sparse matrix structure where zero values + * act as pointers to deeper probability matrices, creating a multi-dimensional + * knowledge representation system. + */ +class HierarchicalKnowledgeMatrix { +public: + using value_t = double; + using position_t = std::pair; + using matrix_t = std::map; + + /** + * @brief Initialize a hierarchical knowledge matrix + * + * @param rows Number of rows in the matrix + * @param cols Number of columns in the matrix + * @param default_value Default value for cells (typically a probability) + */ + HierarchicalKnowledgeMatrix(size_t rows, size_t cols, value_t default_value = 0.5); + + /** + * @brief Get the value at the specified position and depth + * + * @param row Row index + * @param col Column index + * @param depth Vector of positions representing the path to follow through deeper matrices + * @return Value at the specified position + */ + value_t GetValue(size_t row, size_t col, + const std::vector& depth = std::vector()) const; + + /** + * @brief Set the value at the specified position and depth + * + * @param row Row index + * @param col Column index + * @param value Value to set + * @param depth Vector of positions representing the path to follow through deeper matrices + */ + void SetValue(size_t row, size_t col, value_t value, + const std::vector& depth = std::vector()); + + /** + * @brief Add a deeper matrix at the specified position + * + * @param row Row index + * @param col Column index + * @return Pointer to the newly created deeper matrix + */ + HierarchicalKnowledgeMatrix* AddDeeperMatrix(size_t row, size_t col); + + /** + * @brief Check if a position has a deeper matrix + * + * @param row Row index + * @param col Column index + * @return True if the position has a deeper matrix, False otherwise + */ + bool HasDeeperMatrix(size_t row, size_t col) const; + + /** + * @brief Get the deeper matrix at the specified position + * + * @param row Row index + * @param col Column index + * @return Pointer to the deeper matrix if it exists, nullptr otherwise + */ + HierarchicalKnowledgeMatrix* GetDeeperMatrix(size_t row, size_t col); + + /** + * @brief Update probabilities based on new evidence using Bayesian update + * + * @param evidence Map of positions to observed probabilities + * @param depth Vector of positions representing the path to the matrix to update + */ + void UpdateProbabilities(const std::map& evidence, + const std::vector& depth = std::vector()); + + /** + * @brief Get the dimensions of the matrix + * + * @return Pair of (rows, cols) + */ + std::pair GetDimensions() const; + + /** + * @brief Get the default value for this matrix + * + * @return Default value + */ + value_t GetDefaultValue() const; + + /** + * @brief Convert the sparse matrix to a dense representation + * + * @param include_deeper If true, mark positions with deeper matrices + * @return Vector of vectors representing the dense matrix + */ + std::vector> ToDense(bool include_deeper = false) const; + +private: + size_t rows_; + size_t cols_; + value_t default_value_; + + // Sparse matrix representation + matrix_t matrix_; + + // Map of deeper matrices + // Key: (row, col) position in this matrix + // Value: Pointer to the deeper matrix + std::map> deeper_matrices_; +}; + +/** + * @brief HierarchicalKnowledgeMatrixFacility provides integration with OpenMind + * + * This facility allows OpenMind to use hierarchical knowledge matrices for + * representing and reasoning with probabilistic knowledge. + */ +class HierarchicalKnowledgeMatrixFacility : public FunctorFacility { +public: + using matrix_ptr_t = std::shared_ptr; + using position_t = std::pair; + + /** + * @brief Constructor for HierarchicalKnowledgeMatrixFacility + * + * @param rows Number of rows in the matrix + * @param cols Number of columns in the matrix + * @param default_value Default value for cells + */ + HierarchicalKnowledgeMatrixFacility( + std::function connector, + size_t rows, size_t cols, + double default_value = 0.5); + + /** + * @brief Get the value at the specified position and depth + * + * @param row Row index + * @param col Column index + * @param depth Vector of positions representing the path to follow through deeper matrices + * @return Value at the specified position + */ + double GetValue(size_t row, size_t col, + const std::vector& depth = std::vector()) const; + + /** + * @brief Set the value at the specified position and depth + * + * @param row Row index + * @param col Column index + * @param value Value to set + * @param depth Vector of positions representing the path to follow through deeper matrices + */ + void SetValue(size_t row, size_t col, double value, + const std::vector& depth = std::vector()); + + /** + * @brief Add a deeper matrix at the specified position + * + * @param row Row index + * @param col Column index + */ + void AddDeeperMatrix(size_t row, size_t col); + + /** + * @brief Update probabilities based on new evidence using Bayesian update + * + * @param evidence Map of positions to observed probabilities + * @param depth Vector of positions representing the path to the matrix to update + */ + void UpdateProbabilities(const std::map& evidence, + const std::vector& depth = std::vector()); + + /** + * @brief Get cells with probability below threshold and confidence above threshold + * + * @param threshold Probability threshold for safe cells + * @param confidence_threshold Confidence threshold for safe cells + * @param confidence_position Position in deeper matrices that stores confidence values + * @return Vector of positions of safe cells + */ + std::vector GetLowProbabilityCells( + double threshold = 0.1, + double confidence_threshold = 0.7, + position_t confidence_position = {0, 0}) const; + + /** + * @brief Get cells with probability above threshold and confidence above threshold + * + * @param threshold Probability threshold for high probability cells + * @param confidence_threshold Confidence threshold for high probability cells + * @param confidence_position Position in deeper matrices that stores confidence values + * @return Vector of positions of high probability cells + */ + std::vector GetHighProbabilityCells( + double threshold = 0.9, + double confidence_threshold = 0.7, + position_t confidence_position = {0, 0}) const; + + /** + * @brief Get the underlying knowledge matrix + * + * @return Shared pointer to the knowledge matrix + */ + matrix_ptr_t GetMatrix() const; + + + +private: + matrix_ptr_t matrix_; +}; diff --git a/OpenMind/LogicOffloadFacility.cpp b/OpenMind/LogicOffloadFacility.cpp new file mode 100644 index 0000000000..05c1f521e8 --- /dev/null +++ b/OpenMind/LogicOffloadFacility.cpp @@ -0,0 +1,47 @@ +#include "stdafx.h" +#include "LogicOffloadFacility.h" +#include +#include + +LogicOffloadFacility::LogicOffloadFacility( + std::function connector, + logic_result_callback_t callback +) : FunctorFacility(connector), _callback(callback) { +} + +void LogicOffloadFacility::AddProposition(const proposition_t& proposition) { + _propositions.push_back(proposition); +} + +void LogicOffloadFacility::AddRule(const proposition_t& antecedent, const proposition_t& consequent) { + _rules.emplace_back(antecedent, consequent); +} + +void LogicOffloadFacility::SetContext(const std::string& context) { + _context = context; +} + +LogicOffloadFacility::result_t LogicOffloadFacility::GetResults() const { + return _results; +} + +bool LogicOffloadFacility::IsSatisfiable(const proposition_t& proposition) const { + // This would typically call into the external logic system + // For now, we provide a simple implementation + return !IsContradiction(proposition); +} + +bool LogicOffloadFacility::IsTautology(const proposition_t& proposition) const { + // A proposition is a tautology if its negation is a contradiction + omnn::math::Valuable negation = proposition.operator!(); + return IsContradiction(negation); +} + +bool LogicOffloadFacility::IsContradiction(const proposition_t& proposition) const { + // This would typically call into the external logic system + // For now, we provide a simple implementation that checks if the proposition + // evaluates to a constant false + + // Check if the proposition is equivalent to false (0) + return proposition.IsZero(); +} diff --git a/OpenMind/LogicOffloadFacility.h b/OpenMind/LogicOffloadFacility.h new file mode 100644 index 0000000000..a9e02b3de0 --- /dev/null +++ b/OpenMind/LogicOffloadFacility.h @@ -0,0 +1,108 @@ +#pragma once +#include +#include +#include +#include +#include "Facility.h" +#include "FunctorFacility.h" + +namespace omnn { +namespace math { +class Valuable; +class Variable; +} +} + +/** + * @brief LogicOffloadFacility provides a bridge between OpenMind and external logic systems + * + * This facility allows OpenMind to offload logical deduction and inference to external + * specialized systems. It extends FunctorFacility to provide a standardized interface + * for connecting with third-party State-Transfer Machines (STMs) that implement logical + * operations. + */ +class LogicOffloadFacility : public FunctorFacility { +public: + using proposition_t = omnn::math::Valuable; + using variable_t = omnn::math::Variable; + using result_t = std::vector; + + /** + * @brief Callback type for external logic system results + * + * This callback is invoked when the external logic system returns results + * @param results Vector of propositions representing the logical deductions + */ + using logic_result_callback_t = std::function; + + /** + * @brief Constructor for LogicOffloadFacility + * + * @param connector Function that connects to the external logic system + * @param callback Function to call when results are received + */ + LogicOffloadFacility( + std::function connector, + logic_result_callback_t callback + ); + + /** + * @brief Add a proposition to be processed by the external logic system + * + * @param proposition The logical proposition to add + */ + void AddProposition(const proposition_t& proposition); + + /** + * @brief Add a logical rule to be processed by the external logic system + * + * @param antecedent The "if" part of the rule + * @param consequent The "then" part of the rule + */ + void AddRule(const proposition_t& antecedent, const proposition_t& consequent); + + /** + * @brief Set the context for logical operations + * + * @param context String identifier for the logical context + */ + void SetContext(const std::string& context); + + /** + * @brief Get the current results from the external logic system + * + * @return Vector of propositions representing the logical deductions + */ + result_t GetResults() const; + + /** + * @brief Check if a proposition is satisfiable in the current context + * + * @param proposition The proposition to check + * @return true if satisfiable, false otherwise + */ + bool IsSatisfiable(const proposition_t& proposition) const; + + /** + * @brief Check if a proposition is a tautology in the current context + * + * @param proposition The proposition to check + * @return true if tautology, false otherwise + */ + bool IsTautology(const proposition_t& proposition) const; + + /** + * @brief Check if a proposition is a contradiction in the current context + * + * @param proposition The proposition to check + * @return true if contradiction, false otherwise + */ + bool IsContradiction(const proposition_t& proposition) const; + +private: + std::vector _propositions; + std::vector> _rules; + std::string _context; + result_t _results; + logic_result_callback_t _callback; +}; diff --git a/OpenMind/test/HierarchicalKnowledgeMatrixTest.cpp b/OpenMind/test/HierarchicalKnowledgeMatrixTest.cpp new file mode 100644 index 0000000000..44ac1bcdf9 --- /dev/null +++ b/OpenMind/test/HierarchicalKnowledgeMatrixTest.cpp @@ -0,0 +1,101 @@ +#include "stdafx.h" +#include "../HierarchicalKnowledgeMatrix.h" +#include +#include +#include + +// Test fixture for HierarchicalKnowledgeMatrix +class HierarchicalKnowledgeMatrixTest : public ::testing::Test { +protected: + void SetUp() override { + // Create a basic matrix for testing + matrix_ = std::make_unique(10, 10, 0.5); + + // Set up some test values + matrix_->SetValue(5, 5, 0.8); + matrix_->SetValue(3, 7, 0.2); + + // Create a deeper matrix at position (4, 4) + auto deeper = matrix_->AddDeeperMatrix(4, 4); + deeper->SetValue(1, 1, 0.9); + + // Create a facility for testing + auto connector = []() -> bool { + // Simple connector function + return true; + }; + + facility_ = std::make_unique(connector, 10, 10, 0.5); + facility_->SetValue(5, 5, 0.8); + facility_->AddDeeperMatrix(4, 4); + } + + std::unique_ptr matrix_; + std::unique_ptr facility_; +}; + +// Test that the HierarchicalKnowledgeMatrix can store and retrieve values +TEST_F(HierarchicalKnowledgeMatrixTest, StoreAndRetrieveValues) { + // Check values we set in SetUp + EXPECT_DOUBLE_EQ(0.8, matrix_->GetValue(5, 5)); + EXPECT_DOUBLE_EQ(0.2, matrix_->GetValue(3, 7)); + + // Check default value + EXPECT_DOUBLE_EQ(0.5, matrix_->GetValue(0, 0)); + + // Set a new value and retrieve it + matrix_->SetValue(1, 1, 0.7); + EXPECT_DOUBLE_EQ(0.7, matrix_->GetValue(1, 1)); +} + +// Test that the HierarchicalKnowledgeMatrix can handle deeper matrices +TEST_F(HierarchicalKnowledgeMatrixTest, DeeperMatrices) { + // Check that we have a deeper matrix at (4, 4) + EXPECT_TRUE(matrix_->HasDeeperMatrix(4, 4)); + + // Check value in deeper matrix + std::vector> depth = {{4, 4}}; + EXPECT_DOUBLE_EQ(0.9, matrix_->GetValue(1, 1, depth)); + + // Set a new value in the deeper matrix + matrix_->SetValue(2, 2, 0.6, depth); + EXPECT_DOUBLE_EQ(0.6, matrix_->GetValue(2, 2, depth)); +} + +// Test that the HierarchicalKnowledgeMatrixFacility works correctly +TEST_F(HierarchicalKnowledgeMatrixTest, FacilityWorks) { + // Check the value we set in SetUp + EXPECT_DOUBLE_EQ(0.8, facility_->GetValue(5, 5)); + + // Set a new value and retrieve it + facility_->SetValue(1, 1, 0.7); + EXPECT_DOUBLE_EQ(0.7, facility_->GetValue(1, 1)); + + // Check that we have a deeper matrix at (4, 4) + EXPECT_TRUE(facility_->GetMatrix()->HasDeeperMatrix(4, 4)); + + // Invoke the facility (should call the connector function) + EXPECT_TRUE(facility_->Invoke()); +} + +// Test the probability update functionality +TEST_F(HierarchicalKnowledgeMatrixTest, ProbabilityUpdates) { + // Set up evidence for a Bayesian update + std::map, double> evidence; + evidence[{5, 5}] = 0.9; // Strong evidence + + // Current probability is 0.8 + EXPECT_DOUBLE_EQ(0.8, matrix_->GetValue(5, 5)); + + // Update probabilities + matrix_->UpdateProbabilities(evidence); + + // After update, probability should be higher (exact value depends on the Bayesian formula) + EXPECT_GT(matrix_->GetValue(5, 5), 0.8); +} + +// Main function +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/OpenMind/test/LogicOffloadFacilityTest.cpp b/OpenMind/test/LogicOffloadFacilityTest.cpp new file mode 100644 index 0000000000..254ccb6b81 --- /dev/null +++ b/OpenMind/test/LogicOffloadFacilityTest.cpp @@ -0,0 +1,264 @@ +#include "stdafx.h" +#include "../LogicOffloadFacility.h" +#include +#include +#include + +// Example of a 3rd-party logic system connector +class MinesweeperLogicSystem { +public: + // Represents a cell in the Minesweeper grid + struct Cell { + bool is_mine = false; + bool is_revealed = false; + bool is_flagged = false; + int adjacent_mines = 0; + }; + + // Represents the Minesweeper grid + class Grid { + public: + Grid(int width, int height) : width_(width), height_(height) { + cells_.resize(height_, std::vector(width_)); + } + + void SetCell(int x, int y, bool is_mine, bool is_revealed, int adjacent_mines = 0) { + if (x >= 0 && x < width_ && y >= 0 && y < height_) { + cells_[y][x].is_mine = is_mine; + cells_[y][x].is_revealed = is_revealed; + cells_[y][x].adjacent_mines = adjacent_mines; + } + } + + Cell& GetCell(int x, int y) { + return cells_[y][x]; + } + + const Cell& GetCell(int x, int y) const { + return cells_[y][x]; + } + + int GetWidth() const { return width_; } + int GetHeight() const { return height_; } + + private: + int width_; + int height_; + std::vector> cells_; + }; + + // Logical solver for Minesweeper + class Solver { + public: + Solver(Grid& grid) : grid_(grid) {} + + // Find safe moves using logical deduction + std::vector> GetSafeMoves() { + std::vector> safe_moves; + + // Implement logical deduction + for (int y = 0; y < grid_.GetHeight(); ++y) { + for (int x = 0; x < grid_.GetWidth(); ++x) { + const Cell& cell = grid_.GetCell(x, y); + + // Skip cells that aren't revealed or have no adjacent mines + if (!cell.is_revealed || cell.adjacent_mines == 0) { + continue; + } + + // Count flagged and unrevealed cells around this cell + int flagged = 0; + std::vector> unrevealed; + + for (int dy = -1; dy <= 1; ++dy) { + for (int dx = -1; dx <= 1; ++dx) { + if (dx == 0 && dy == 0) { + continue; + } + + int nx = x + dx; + int ny = y + dy; + if (nx >= 0 && nx < grid_.GetWidth() && ny >= 0 && ny < grid_.GetHeight()) { + const Cell& neighbor = grid_.GetCell(nx, ny); + if (neighbor.is_flagged) { + flagged++; + } else if (!neighbor.is_revealed) { + unrevealed.emplace_back(nx, ny); + } + } + } + } + + // If the number of flags equals the number of adjacent mines, + // all remaining unrevealed cells are safe + if (flagged == cell.adjacent_mines && !unrevealed.empty()) { + safe_moves.insert(safe_moves.end(), unrevealed.begin(), unrevealed.end()); + } + } + } + + return safe_moves; + } + + // Find mine locations using logical deduction + std::vector> GetMineLocations() { + std::vector> mine_locations; + + // Implement logical deduction + for (int y = 0; y < grid_.GetHeight(); ++y) { + for (int x = 0; x < grid_.GetWidth(); ++x) { + const Cell& cell = grid_.GetCell(x, y); + + // Skip cells that aren't revealed + if (!cell.is_revealed) { + continue; + } + + // Count flagged and unrevealed cells around this cell + int flagged = 0; + std::vector> unrevealed; + + for (int dy = -1; dy <= 1; ++dy) { + for (int dx = -1; dx <= 1; ++dx) { + if (dx == 0 && dy == 0) { + continue; + } + + int nx = x + dx; + int ny = y + dy; + if (nx >= 0 && nx < grid_.GetWidth() && ny >= 0 && ny < grid_.GetHeight()) { + const Cell& neighbor = grid_.GetCell(nx, ny); + if (neighbor.is_flagged) { + flagged++; + } else if (!neighbor.is_revealed) { + unrevealed.emplace_back(nx, ny); + } + } + } + } + + // If the number of unrevealed cells equals the number of adjacent mines minus flags, + // all unrevealed cells must be mines + if (!unrevealed.empty() && unrevealed.size() == cell.adjacent_mines - flagged) { + mine_locations.insert(mine_locations.end(), unrevealed.begin(), unrevealed.end()); + } + } + } + + return mine_locations; + } + + private: + Grid& grid_; + }; +}; + +// Test fixture for LogicOffloadFacility +class LogicOffloadFacilityTest : public ::testing::Test { +protected: + void SetUp() override { + // Set up a Minesweeper grid for testing + grid_ = std::make_unique(10, 10); + + // Set up some revealed cells with adjacent mine counts + grid_->SetCell(5, 5, false, true, 1); // Center cell with 1 adjacent mine + grid_->SetCell(4, 5, false, false); // Unrevealed cell + grid_->SetCell(6, 5, false, false); // Unrevealed cell + grid_->SetCell(5, 4, false, false); // Unrevealed cell + grid_->SetCell(5, 6, false, true, 0); // Revealed cell with 0 adjacent mines + + // Create a solver + solver_ = std::make_unique(*grid_); + + // Create a LogicOffloadFacility that connects to the Minesweeper solver + auto connector = [this]() -> bool { + // Connect to the Minesweeper solver and get results + auto safe_moves = solver_->GetSafeMoves(); + auto mine_locations = solver_->GetMineLocations(); + + // Convert results to propositions + std::vector results; + + // Create variables for each cell + for (const auto& move : safe_moves) { + int x = move.first; + int y = move.second; + // Create a proposition that this cell is safe + omnn::math::Variable cell_var("cell_" + std::to_string(x) + "_" + std::to_string(y)); + results.push_back(cell_var == 0); // 0 means safe (no mine) + } + + for (const auto& mine : mine_locations) { + int x = mine.first; + int y = mine.second; + // Create a proposition that this cell contains a mine + omnn::math::Variable cell_var("cell_" + std::to_string(x) + "_" + std::to_string(y)); + results.push_back(cell_var == 1); // 1 means mine + } + + // Call the callback with the results + if (callback_) { + callback_(results); + } + + return true; + }; + + // Create a callback that stores the results + auto callback = [this](const std::vector& results) { + results_ = results; + }; + + facility_ = std::make_unique(connector, callback); + } + + std::unique_ptr grid_; + std::unique_ptr solver_; + std::unique_ptr facility_; + std::vector results_; + std::function&)> callback_; +}; + +// Test that the LogicOffloadFacility can connect to the Minesweeper solver +TEST_F(LogicOffloadFacilityTest, ConnectToMinesweeperSolver) { + // Invoke the facility to connect to the Minesweeper solver + EXPECT_TRUE(facility_->Invoke()); + + // Check that we got some results + EXPECT_FALSE(results_.empty()); +} + +// Test that the LogicOffloadFacility can add propositions +TEST_F(LogicOffloadFacilityTest, AddPropositions) { + // Create some propositions + omnn::math::Variable x("x"); + omnn::math::Variable y("y"); + + // Add propositions to the facility + facility_->AddProposition(x > 0); + facility_->AddProposition(y < 10); + + // Add a rule + facility_->AddRule(x > 0, y < 10); + + // Invoke the facility + EXPECT_TRUE(facility_->Invoke()); +} + +// Test that the LogicOffloadFacility can check if a proposition is satisfiable +TEST_F(LogicOffloadFacilityTest, IsSatisfiable) { + // Create some propositions + omnn::math::Variable x("x"); + + // Check if x > 0 is satisfiable + EXPECT_TRUE(facility_->IsSatisfiable(x > 0)); + + // Check if x > 0 && x < 0 is satisfiable (it's not) + EXPECT_FALSE(facility_->IsSatisfiable((x > 0) && (x < 0))); +} + +// Main function +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/README.md b/README.md index a6f40179da..f4590fe197 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,19 @@ Please Donate to help reach this plans: Bountysource: +## Special Thanks + +Special thanks to all contributors and supporters who have helped make this project possible: + +- Sergii Kryvonos (Author of idea, Architect, owner) +- Iryna Galchenko (CFO) for help during release on copy-on-write feature +- Makogon Yurii for help on Python wrapper +- Olena Dobromyslova for contributing +- All GitHub contributors who have submitted code, reported issues, and provided feedback +- The open-source community for providing valuable tools and libraries +- Devin AI for documentation assistance and improvements +- All financial supporters who have donated to the project + Support: sergeikrivonos@gmail.com Bitcoin: 17JNBmpsDxp1d4jcAh7qthSN4VRcN9EDxQ diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 0000000000..fcba9fc6d2 --- /dev/null +++ b/cmake/CMakeLists.txt @@ -0,0 +1,2 @@ + +fold() diff --git a/cmake/bins.cmake b/cmake/bins.cmake index 91aaece004..75de69ed34 100644 --- a/cmake/bins.cmake +++ b/cmake/bins.cmake @@ -248,8 +248,8 @@ function(apply_target_commons this_target) target_link_directories(${this_target} INTERFACE ${ldirs}) get_target_property(target_type ${this_target} TYPE) if(target_type STREQUAL "INTERFACE_LIBRARY") + set(visibility INTERFACE PARENT_SCOPE) message(STATUS "${this_target} is INTERFACE") - set(visibility INTERFACE) set(defs INTERFACE ${defs}) set(opts INTERFACE ${opts}) target_compile_features(${this_target} INTERFACE cxx_std_23) @@ -259,7 +259,7 @@ function(apply_target_commons this_target) $ ) else() - set(visibility PUBLIC) + set(visibility PUBLIC PARENT_SCOPE) set(defs INTERFACE ${defs} PUBLIC ${defs}) set(opts INTERFACE ${opts} PUBLIC ${opts}) target_compile_features(${this_target} INTERFACE cxx_std_23 PUBLIC cxx_std_23) @@ -282,7 +282,7 @@ macro(link_boost_libs) foreach (boostlibtarget ${BOOST_LINK_LIBS}) if(TARGET ${boostlibtarget}) message("linking boostlibtarget: ${boostlibtarget}") - target_link_libraries(${this_target} PUBLIC ${boostlibtarget}) + target_link_libraries(${this_target} ${visibility} ${boostlibtarget}) else() message("skipping linking ${boostlibtarget}, the target not found") endif() @@ -290,13 +290,13 @@ macro(link_boost_libs) foreach (boostcomponent ${BOOST_ADDITIONAL_COMPONENTS}) if(TARGET Boost::${boostcomponent}) message("linking boostlibtarget: Boost::${boostcomponent}") - target_link_libraries(${this_target} PUBLIC Boost::${boostcomponent}) + target_link_libraries(${this_target} ${visibility} Boost::${boostcomponent}) else() string(TOUPPER ${boostcomponent} boostcomponent) message("include ${boostcomponent}: ${Boost_${boostcomponent}_INCLUDE_DIR}") - target_link_libraries(${this_target} PUBLIC ${Boost_${boostcomponent}_INCLUDE_DIR}) + target_link_libraries(${this_target} ${visibility} ${Boost_${boostcomponent}_INCLUDE_DIR}) message("linking ${boostcomponent}: ${Boost_${boostcomponent}_LIBRARY}") - target_link_libraries(${this_target} PUBLIC ${Boost_${boostcomponent}_LIBRARY}) + target_link_libraries(${this_target} ${visibility} ${Boost_${boostcomponent}_LIBRARY}) endif() endforeach() endif() @@ -375,7 +375,7 @@ function(test) apply_test_commons(${TEST_NAME}) target_link_libraries(${TEST_NAME} PUBLIC ${parent_target} - #testlibs + testlibs ) message("using deps ${libs}") @@ -427,7 +427,19 @@ macro(lib) set(USE_SHARED INTERFACE) endif() add_library(${this_target} ${USE_SHARED} ${all_source_files}) + set(incls + ${OPENMIND_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${${this_target}_INCLUDE_DIR} + ) APPLY_TARGET_COMMONS(${this_target}) + if(target_type STREQUAL "INTERFACE_LIBRARY") + target_include_directories(${this_target} ${visibility} + $ + $ + ) + endif() + if(CMAKE_CXX_STANDARD) set_target_properties(${this_target} PROPERTIES CXX_STANDARD ${CMAKE_CXX_STANDARD}) endif(CMAKE_CXX_STANDARD) @@ -435,19 +447,12 @@ macro(lib) FOLDER "libs" PUBLIC_HEADER "${headers}" ) - target_include_directories(${this_target} PUBLIC - ${OPENMIND_INCLUDE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${${this_target}_INCLUDE_DIR} - INTERFACE - $ - $ - ) - #add_dependencies(${this_target} prerequisites) message("add_library(${this_target} ${src})") link_boost_libs() - #message("target_link_libraries(${this_target} PUBLIC ${deps})") - deps(${TEST_DEPS} ${deps}) + deps(${deps}) + if(OPENMIND_USE_TBB) + target_link_libraries(${this_target} ${visibility} tbb) + endif() set(INSTALL_PARAMS TARGETS ${this_target}) if(LIBRARY_DESTINATION) diff --git a/cmake/deps.cmake b/cmake/deps.cmake index 61be4ee55a..a2b094ce50 100644 --- a/cmake/deps.cmake +++ b/cmake/deps.cmake @@ -161,12 +161,12 @@ macro(ext name location) if(TARGET ${this_target}) if(${name}_INCLUDE_DIR) - target_include_directories(${this_target} PUBLIC ${${name}_INCLUDE_DIR}) + target_include_directories(${this_target} ${visibility} ${${name}_INCLUDE_DIR}) endif() if(${name}_INCLUDE_DIRS) - target_include_directories(${this_target} PUBLIC ${${name}_INCLUDE_DIRS}) + target_include_directories(${this_target} ${visibility} ${${name}_INCLUDE_DIRS}) endif() - target_link_directories(${this_target} PUBLIC + target_link_directories(${this_target} ${visibility} ${CMAKE_BINARY_DIR}/lib ${CMAKE_BINARY_DIR}/lib64 ) @@ -213,7 +213,7 @@ macro(dep) message("'${dep}' target dependency of '${type}' type for '${this_target}' is ready") if(${type} MATCHES "STATIC_LIBRARY|SHARED_LIBRARY|UNKNOWN_LIBRARY") message("'${dep}' MATCHES STATIC_LIBRARY|SHARED_LIBRARY|UNKNOWN_LIBRARY") - target_link_libraries(${this_target} PUBLIC ${dep}) + target_link_libraries(${this_target} ${visibility} ${dep}) else() message("'${dep}' target type is '${type}'") if(OPENMIND_DEPEND_ON_PREREQUISITES AND NOT type STREQUAL UTILITY) @@ -251,7 +251,7 @@ macro(dep) dep(${dep}) endif() elseif(${dep} STREQUAL pthread) - target_link_options(${this_target} PUBLIC -pthread) + target_link_options(${this_target} ${visibility} -pthread) elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../${dep}) message(ERROR "dep ${dep} target is yet to be processed sibling directory library (add param fold(${dep}))") elseif(dep MATCHES "((git|ssh|http(s)?)|(git@[-(A-Z)|(a-z)|(0-9)\.]+))(:(//)?)([-(A-Z)|(a-z)|(0-9)\.@\:/\-~]+)(\.git)?(/)?") @@ -344,8 +344,8 @@ macro(deps) set(${this_target}_LIBRARIES ${this_target_libs} CACHE FILEPATH "${this_target} libs to link" #FORCE ) - message("target_link_directories(${this_target} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})") - target_link_directories(${this_target} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) + message("target_link_directories(${this_target} ${visibility} ${CMAKE_CURRENT_BINARY_DIR})") + target_link_directories(${this_target} ${visibility} ${CMAKE_CURRENT_BINARY_DIR}) if(this_target_libs AND NOT this_target_libs STREQUAL "") message("${this_target} libs: ${this_target_libs}") foreach(lib ${this_target_libs}) @@ -363,16 +363,16 @@ macro(deps) AND NOT lib STREQUAL "debug" ) message("lib: ${lib}") - target_link_libraries(${this_target} PUBLIC ${lib}) + target_link_libraries(${this_target} ${visibility} ${lib}) endif() endforeach() else() message("${this_target} has no libs") endif() if(NOT MSVC) - target_link_options(${this_target} PUBLIC -pthread) + target_link_options(${this_target} ${visibility} -pthread) if(NOT APPLE) - target_link_libraries(${this_target} PUBLIC ${CMAKE_DL_LIBS}) + target_link_libraries(${this_target} ${visibility} ${CMAKE_DL_LIBS}) endif() endif() diff --git a/cmake/find_local_package.cmake b/cmake/find_local_package.cmake index 3ee9f0fe04..cea12093fb 100644 --- a/cmake/find_local_package.cmake +++ b/cmake/find_local_package.cmake @@ -221,7 +221,7 @@ macro(dep_find_package) message("PKG_CFLAGS: ${PKG_CFLAGS}") message("PKG_LIBRARIES: ${PKG_LIBRARIES}") pkg_check_modules(${underscored_down} IMPORTED_TARGET ${underscored_down}>=1.0) - target_link_libraries(${this_target} PUBLIC PkgConfig::${underscored_down}) + target_link_libraries(${this_target} ${visibility} PkgConfig::${underscored_down}) else() message("Neither find_package nor pkg_config found ${dep}") endif() @@ -238,16 +238,16 @@ macro(dep_find_package) if(this_target) if(${dep}_INCLUDE_DIR) message("${dep}_INCLUDE_DIR: ${${dep}_INCLUDE_DIR} for ${this_target}") - target_include_directories(${this_target} PUBLIC ${${dep}_INCLUDE_DIR}) + target_include_directories(${this_target} ${visibility} ${${dep}_INCLUDE_DIR}) endif() if(${dep}_INCLUDE_DIRS) message("${dep}_INCLUDE_DIRS: ${${dep}_INCLUDE_DIRS} for ${this_target}") - target_include_directories(${this_target} PUBLIC ${${dep}_INCLUDE_DIRS}) + target_include_directories(${this_target} ${visibility} ${${dep}_INCLUDE_DIRS}) endif() endif() if(${dep}_LIBRARY) if(this_target) - target_link_libraries(${this_target} PUBLIC ${${dep}_LIBRARY}) + target_link_libraries(${this_target} ${visibility} ${${dep}_LIBRARY}) endif() elseif(NOT ${dep}_LIBRARIES) find_library(${dep}_LIBRARIES NAMES ${dep} lib${dep} ${dep}lib lib${dep}lib) @@ -275,7 +275,7 @@ macro(dep_find_package) if(repo STREQUAL "SYSTEM") message("Found ${dep}_LIBRARIES: ${${dep}_LIBRARIES}") if(this_target) - target_link_libraries(${this_target} PUBLIC ${${dep}_LIBRARIES}) + target_link_libraries(${this_target} ${visibility} ${${dep}_LIBRARIES}) endif() else() message("Found no ${dep}_LIBRARIES: ${${dep}_LIBRARIES}") diff --git a/docs/knowledge_base/consolidated_knowledge_base.md b/docs/knowledge_base/consolidated_knowledge_base.md index 24d5142950..d8b4132eea 100644 --- a/docs/knowledge_base/consolidated_knowledge_base.md +++ b/docs/knowledge_base/consolidated_knowledge_base.md @@ -39,6 +39,20 @@ The ohhmm/openmind repository is organized into the following main directories: - Multiple generator types (GeneralGoalGenerator, SingletonGoalGenerator, IdleTimeGoalGenerator) - Uses facilities for reusable operations +### 5. Quantum Computing (`omnn/quantum`) +- Quantum state manipulation and operations +- QuantumRegister class for quantum state representation +- Support for controlled phase rotation and normalization +- Framework for quantum algorithm implementation +- Integration with classical computation + +### 6. Logic System (`omnn/logic`) +- Propositional reasoning and logical operations +- Equality constraints and inference rules +- Mathematical representation of logical expressions +- Integration with equation solving +- Support for logical inference and constraint satisfaction + ### 2. Mathematical Framework (`omnn/math`) - Extensive type system for mathematical operations - Support for variables, equations, matrices @@ -46,6 +60,11 @@ The ohhmm/openmind repository is organized into the following main directories: - Constants (pi, e, i) and special values - Heavy template usage for generic operations - Derivative expression format follows the pattern "(expression)'variable", where 'variable represents the variable to differentiate with respect to +- Advanced mathematical operations including integration, differentiation, and special functions +- Bit manipulation operations for low-level optimization +- Copy-on-Write (COW) memory model for efficient object sharing and modification +- Conditional operations (Ifz, IfNZ, IfEq) for complex mathematical expressions +- Symbolic computation capabilities for mathematical precision ### 3. Neural Network Components (`omnn/rt`) - Async neuron implementation @@ -57,6 +76,11 @@ The ohhmm/openmind repository is organized into the following main directories: - Multiple backend support (LevelDB, FoundationDB) - Thread-safe operations - Abstract CacheBase class with concrete implementations +- Efficient caching and persistence of data +- Optimized storage and retrieval of computed mathematical expressions +- LevelDbCache implementation with custom connection options +- Asynchronous operations for improved performance +- Memory caching for frequently accessed items ## Development Guidelines @@ -194,6 +218,13 @@ jobs: - Lockfree data structures in runtime - Parallel task execution +### 5. Python Bindings (`omnn/variable`): +- Integration with Python through Boost.Python +- Exposes mathematical operations to Python scripts +- Allows seamless integration of OpenMind's functionality into Python workflows +- Supports mathematical operations, neural networks, and extrapolator functionality +- Built when the `OPENMIND_BUILD_PYTHON_BINDINGS` CMake option is enabled + ### 2. Memory Management: - Custom allocators - Smart pointer usage throughout diff --git a/docs/knowledge_base/consolidated_knowledge_base.pdf b/docs/knowledge_base/consolidated_knowledge_base.pdf index 6c10b734d2..502b2806db 100644 Binary files a/docs/knowledge_base/consolidated_knowledge_base.pdf and b/docs/knowledge_base/consolidated_knowledge_base.pdf differ diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 30fca4362b..4d5b134704 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -4,11 +4,19 @@ ** xref:architecture/overview.adoc[Overview] ** xref:architecture/components.adoc[Components] ** xref:architecture/modules.adoc[Modules] +* Features +** xref:features/copy_on_write.adoc[Copy-on-Write] +** xref:features/quantum_computing.adoc[Quantum Computing] +** xref:features/logic_system.adoc[Logic System] +** xref:features/bit_operations.adoc[Bit Operations] +** xref:features/storage.adoc[Storage System] +** xref:features/advanced_math.adoc[Advanced Mathematics] * Examples ** xref:examples/index.adoc[Example Usage] * Development ** xref:development/building.adoc[Building] ** xref:development/contributing.adoc[Contributing] +** xref:development/python_wrapper.adoc[Python Bindings] * Business ** xref:business/profit-potential.adoc[Profit Potential Evaluation] * Reference diff --git a/docs/modules/ROOT/pages/architecture/components.adoc b/docs/modules/ROOT/pages/architecture/components.adoc index 898bb0afac..6fc634a452 100644 --- a/docs/modules/ROOT/pages/architecture/components.adoc +++ b/docs/modules/ROOT/pages/architecture/components.adoc @@ -6,6 +6,7 @@ * Matrix algebra with optimized memory layout * Equation solver supporting arithmetic, logarithmic, exponential operations * Constants: pi (π), e, i with arbitrary precision +* Copy-on-Write (COW) memory model for efficient object sharing and modification == Runtime (`omnn/rt`) * Lock-free neuron implementation with async message passing diff --git a/docs/modules/ROOT/pages/architecture/modules.adoc b/docs/modules/ROOT/pages/architecture/modules.adoc index 51a7f305ca..383c5e1854 100644 --- a/docs/modules/ROOT/pages/architecture/modules.adoc +++ b/docs/modules/ROOT/pages/architecture/modules.adoc @@ -88,3 +88,20 @@ namespace omnn::core { }; } ---- + +== Python Bindings (`omnn/variable`) +[source,cpp] +---- +namespace omnn::variable { + // Python module initialization + BOOST_PYTHON_MODULE(openmind) { + // Expose classes to Python + py::class_("Variable", py::init()) + .def("__add__", &Variable::operator+) + .def("__mul__", &Variable::operator*) + .def("evaluate", &Variable::evaluate); + + // Additional module exports... + } +} +---- diff --git a/docs/modules/ROOT/pages/development/python_wrapper.adoc b/docs/modules/ROOT/pages/development/python_wrapper.adoc new file mode 100644 index 0000000000..32e8d2f5d8 --- /dev/null +++ b/docs/modules/ROOT/pages/development/python_wrapper.adoc @@ -0,0 +1,100 @@ += Python Bindings +:description: Python wrapper usage and implementation details for OpenMind + +== Overview + +OpenMind provides Python bindings to make its functionality accessible from Python scripts and applications. The Python wrapper allows for seamless integration of OpenMind's mathematical operations, neural networks, and knowledge representation into Python workflows. + +== Building Python Bindings + +Python bindings can be enabled during the build process: + +[source,bash] +---- +cmake -B build -DOPENMIND_BUILD_PYTHON_BINDINGS=ON +cmake --build build +---- + +This will generate the Python modules in the build directory. + +== Usage Example + +[source,python] +---- +import openmind.math as om_math + +# Create variable +var = om_math.Variable("x") + +# Create mathematical expression +expr = var * 2 + 5 + +# Evaluate expression +result = expr.evaluate({"x": 10}) +print(f"Result: {result}") # Output: Result: 25 +---- + +== Supported Features + +* Mathematical operations (Variables, Equations, Matrices) +* Neural network components +* Extrapolator functionality +* Goal management system +* Lambda function generation from expressions + +== Lambda Function Generation + +The Python bindings provide two methods for generating lambda functions from mathematical expressions: + +=== compile_into_lambda + +Creates a lambda function from an expression using the `CompileIntoLambda` method: + +[source,python] +---- +import variable + +x = variable.Variable() +y = variable.Variable() +expr = x + 2 * y + +# Create lambda function +lambda_func = expr.compile_into_lambda([x, y]) + +# Use lambda function with different values +result1 = lambda_func([3, 4]) # 3 + 2*4 = 11 +result2 = lambda_func([5, 2]) # 5 + 2*2 = 9 +---- + +=== compi_lambda + +Creates an optimized lambda function using the `CompiLambda` template method: + +[source,python] +---- +import variable + +x = variable.Variable() +y = variable.Variable() +expr = x * y + x + +# Create lambda function +lambda_func = expr.compi_lambda([x, y]) + +# Use lambda function with different values +result1 = lambda_func([3, 4]) # 3*4 + 3 = 15 +result2 = lambda_func([2, 5]) # 2*5 + 2 = 12 +---- + +[NOTE] +==== +The `compi_lambda` method supports up to 10 variables. For expressions with more variables, use `compile_into_lambda` instead, which has no limit on the number of variables. +==== + +== Implementation Details + +The Python bindings are implemented using Boost.Python and are built when the `OPENMIND_BUILD_PYTHON_BINDINGS` CMake option is enabled. The bindings are defined in the `omnn/variable` directory. + +=== Conditional Compilation + +Python bindings are wrapped with `#ifdef OPENMIND_BUILD_PYTHON_BINDINGS` directives to ensure they are only compiled when Python development headers are available. This allows the codebase to build successfully even in environments without Python support. diff --git a/docs/modules/ROOT/pages/features/advanced_math.adoc b/docs/modules/ROOT/pages/features/advanced_math.adoc new file mode 100644 index 0000000000..a014961ddb --- /dev/null +++ b/docs/modules/ROOT/pages/features/advanced_math.adoc @@ -0,0 +1,312 @@ += Advanced Mathematics +:description: Complex mathematical operations in OpenMind + +== Overview + +OpenMind provides a comprehensive set of advanced mathematical operations through the `Valuable` class. These operations enable complex mathematical manipulations, including integration, differentiation, logical operations, and special functions. + +== Implementation + +The advanced mathematical operations are implemented in the `Valuable` class in `omnn/math/Valuable.h`. The core operations include: + +=== Integration and Differentiation + +[source,cpp] +---- +// From omnn/math/Valuable.h +class Valuable { + // Integration methods + virtual Valuable integral(const Variable& va) const; + Valuable Integral(const Variable& va) const; + + // Differentiation methods + virtual Valuable d(const Variable& va) const; + Valuable D(const Variable& va) const; + + // Higher-order derivatives + Valuable d(const Variable& va, const Valuable& order) const; +}; +---- + +=== Logical Operations + +[source,cpp] +---- +// From omnn/math/Valuable.h +class Valuable { + // Logical operations + Valuable LogicAnd(const Valuable& valuable) const; + Valuable operator&&(const Valuable& valuable) const { return LogicAnd(valuable); } + Valuable LogicOr(const Valuable& valuable) const; + Valuable operator||(const Valuable& valuable) const { return LogicOr(valuable); } + + // Boolean operations + virtual Valuable BoolNot() const; + virtual Valuable BoolIntModNotZero() const; + virtual Valuable ToBool() const; +}; +---- + +=== Comparison Operations + +[source,cpp] +---- +// From omnn/math/Valuable.h +class Valuable { + // Comparison operations + Valuable Equals(const Valuable&) const; + Valuable NotEquals(const Valuable&) const; + + // Inequality operations + virtual Valuable IntMod_Less(const Valuable& than) const; + virtual Valuable Less(const Valuable& than) const; + virtual Valuable LessOrEqual(const Valuable& than) const; + virtual Valuable GreaterOrEqual(const Valuable& than) const; +}; +---- + +=== Special Functions + +[source,cpp] +---- +// From omnn/math/Valuable.h +class Valuable { + // Special functions + Valuable Minimum(const Valuable& second) const; + Valuable Maximum(const Valuable& with) const; + Valuable Distance(const Valuable& with) const; + + // Sign and positivity + virtual Valuable IntMod_Sign() const; + virtual Valuable IsPositive() const; + virtual Valuable IsNegative() const; + virtual Valuable NegativeOrZero() const; +}; +---- + +=== Conditional Operations + +[source,cpp] +---- +// From omnn/math/Valuable.h +class Valuable { + // Conditional operators + Valuable Ifz(const Valuable& Then, const Valuable& Else) const; + Valuable IfNZ(const Valuable& Then, const Valuable& Else) const; + Valuable IfEq(const Valuable& v, const Valuable& Then, const Valuable& Else) const; +}; +---- + +== Core Mathematical Operations + +=== Integration + +* `integral(va)`: Computes the indefinite integral of the expression with respect to variable `va` +* `Integral(va)`: Wrapper around `integral(va)` that may provide additional optimizations + +Integration is implemented using symbolic integration techniques, including: + +* Power rule: ∫xⁿ dx = xⁿ⁺¹/(n+1) for n ≠ -1 +* Logarithmic rule: ∫1/x dx = ln|x| +* Sum rule: ∫(f(x) + g(x)) dx = ∫f(x) dx + ∫g(x) dx +* Product rule and integration by parts for more complex expressions + +=== Differentiation + +* `d(va)`: Computes the derivative of the expression with respect to variable `va` +* `D(va)`: Wrapper around `d(va)` that may provide additional optimizations +* `d(va, order)`: Computes the nth-order derivative, where n is specified by `order` + +Differentiation is implemented using symbolic differentiation techniques, including: + +* Power rule: d/dx(xⁿ) = n·xⁿ⁻¹ +* Product rule: d/dx(f(x)·g(x)) = f(x)·g'(x) + f'(x)·g(x) +* Chain rule: d/dx(f(g(x))) = f'(g(x))·g'(x) +* Quotient rule for fractions + +=== Logical Operations + +* `LogicAnd(v)`: Logical AND operation (returns 1 if both expressions are non-zero, 0 otherwise) +* `LogicOr(v)`: Logical OR operation (returns 1 if either expression is non-zero, 0 otherwise) +* `BoolNot()`: Logical NOT operation (returns 1 if the expression is zero, 0 otherwise) +* `ToBool()`: Converts the expression to a boolean value (0 or 1) + +=== Comparison Operations + +* `Equals(v)`: Returns an expression that equals zero when this expression equals `v` +* `NotEquals(v)`: Returns an expression that equals zero when this expression does not equal `v` +* `Less(v)`: Returns an expression that equals zero when this expression is less than `v` +* `LessOrEqual(v)`: Returns an expression that equals zero when this expression is less than or equal to `v` +* `GreaterOrEqual(v)`: Returns an expression that equals zero when this expression is greater than or equal to `v` + +=== Special Functions + +* `Minimum(v)`: Returns the minimum of this expression and `v` +* `Maximum(v)`: Returns the maximum of this expression and `v` +* `Distance(v)`: Returns the absolute difference between this expression and `v` +* `IntMod_Sign()`: Returns the sign of the expression (-1, 0, or 1) +* `IsPositive()`: Returns an expression that equals zero when this expression is positive +* `IsNegative()`: Returns an expression that equals zero when this expression is negative + +=== Conditional Operations + +* `Ifz(Then, Else)`: Returns `Then` when this expression is zero, `Else` otherwise +* `IfNZ(Then, Else)`: Returns `Then` when this expression is non-zero, `Else` otherwise +* `IfEq(v, Then, Else)`: Returns `Then` when this expression equals `v`, `Else` otherwise + +== Usage Examples + +=== Integration and Differentiation + +[source,cpp] +---- +#include +#include +#include + +using namespace omnn::math; + +int main() { + // Create a variable + Variable x("x"); + + // Create an expression: f(x) = x^2 + 2*x + 1 + Valuable f = x*x + 2*x + 1; + + // Compute the derivative: f'(x) = 2*x + 2 + Valuable df = f.d(x); + + // Compute the integral: ∫f(x)dx = x^3/3 + x^2 + x + C + Valuable intf = f.integral(x); + + // Compute the second derivative: f''(x) = 2 + Valuable d2f = f.d(x, 2_v); + + std::cout << "f(x) = " << f << std::endl; + std::cout << "f'(x) = " << df << std::endl; + std::cout << "∫f(x)dx = " << intf << std::endl; + std::cout << "f''(x) = " << d2f << std::endl; + + return 0; +} +---- + +=== Logical and Comparison Operations + +[source,cpp] +---- +#include +#include +#include + +using namespace omnn::math; + +int main() { + // Create variables + Variable x("x"); + Variable y("y"); + + // Create expressions + Valuable expr1 = x > 0_v; // x > 0 + Valuable expr2 = y < 10_v; // y < 10 + + // Logical operations + Valuable conjunction = expr1.LogicAnd(expr2); // x > 0 AND y < 10 + Valuable disjunction = expr1.LogicOr(expr2); // x > 0 OR y < 10 + Valuable negation = expr1.BoolNot(); // NOT (x > 0) + + // Comparison operations + Valuable equality = x.Equals(y); // x == y + Valuable inequality = x.NotEquals(y); // x != y + Valuable less_than = x.Less(y); // x < y + + std::cout << "x > 0 AND y < 10: " << conjunction << std::endl; + std::cout << "x > 0 OR y < 10: " << disjunction << std::endl; + std::cout << "NOT (x > 0): " << negation << std::endl; + std::cout << "x == y: " << equality << std::endl; + std::cout << "x != y: " << inequality << std::endl; + std::cout << "x < y: " << less_than << std::endl; + + return 0; +} +---- + +=== Conditional Operations + +[source,cpp] +---- +#include +#include +#include + +using namespace omnn::math; + +int main() { + // Create a variable + Variable x("x"); + + // Create conditional expressions + Valuable abs_x = x.Ifz(0_v, x.IfNZ(x.IsPositive().Ifz(x, -x), 0_v)); + Valuable max_xy = x.Less(y).Ifz(y, x); + + // Create a piecewise function: + // f(x) = { + // x^2 if x >= 0 + // -x if x < 0 + // } + Valuable f = x.IsPositive().Ifz(x*x, -x); + + std::cout << "abs(x) = " << abs_x << std::endl; + std::cout << "max(x,y) = " << max_xy << std::endl; + std::cout << "f(x) = " << f << std::endl; + + return 0; +} +---- + +== Mathematical Rigor + +OpenMind's mathematical operations are implemented with a focus on mathematical rigor: + +* *Symbolic Computation*: Operations are performed symbolically rather than numerically, preserving mathematical precision +* *Formal Verification*: Mathematical transformations are rigorously validated and proven correct +* *Edge Case Handling*: Special attention is given to edge cases and singularities +* *Consistency Checks*: Results are verified for mathematical consistency + +== Performance Characteristics + +The advanced mathematical operations are designed with performance in mind: + +* *Time Complexity*: + * Differentiation: O(n) where n is the size of the expression + * Integration: O(n log n) for simple expressions, potentially higher for complex expressions + * Logical operations: O(1) to O(n) depending on the expression complexity + * Comparison operations: O(1) to O(n) depending on the expression complexity + +* *Space Complexity*: + * Most operations: O(n) where n is the size of the expression + * Some operations may require additional temporary space for intermediate results + +* *Optimization*: + * Automatic simplification of expressions + * Caching of intermediate results + * Special case handling for common patterns + +== Integration with Other Systems + +The advanced mathematical operations integrate with other OpenMind systems: + +1. *Extrapolator System*: Use derivatives for pattern recognition and extrapolation +2. *Logic System*: Combine mathematical and logical reasoning +3. *Caching System*: Cache complex mathematical results for improved performance +4. *Python Bindings*: Access advanced mathematical operations from Python + +== Benefits and Applications + +* *Symbolic Mathematics*: Perform symbolic computation without numerical approximation +* *Mathematical Modeling*: Create and manipulate mathematical models +* *Optimization*: Solve optimization problems using derivatives +* *Control Systems*: Design and analyze control systems +* *Machine Learning*: Implement gradient-based learning algorithms +* *Scientific Computing*: Solve differential equations and perform scientific calculations +* *Education*: Explore mathematical concepts through symbolic manipulation diff --git a/docs/modules/ROOT/pages/features/bit_operations.adoc b/docs/modules/ROOT/pages/features/bit_operations.adoc new file mode 100644 index 0000000000..3fcb14411e --- /dev/null +++ b/docs/modules/ROOT/pages/features/bit_operations.adoc @@ -0,0 +1,177 @@ += Bit Operations +:description: Advanced bit manipulation operations in OpenMind + +== Overview + +OpenMind provides comprehensive bit manipulation capabilities through the `Valuable` class. These operations enable low-level bit manipulation, bitwise logical operations, and bit shifting functionality that are essential for certain mathematical and computational tasks. + +== Implementation + +The bit manipulation operations are implemented in the `Valuable` class in `omnn/math/Valuable.h`. The core bit operations include: + +=== Bit Access and Manipulation + +[source,cpp] +---- +// From omnn/math/Valuable.h +class Valuable { + // Bit access operations + virtual Valuable bit(const Valuable& n = constants::zero) const; + virtual Valuable bits(int n, int l) const; + + // Bitwise logical operations + virtual Valuable Or(const Valuable& n, const Valuable&) const; + virtual Valuable And(const Valuable& n, const Valuable&) const; + + // Logical operations + Valuable LogicAnd(const Valuable& valuable) const; + Valuable operator&&(const Valuable& valuable) const { return LogicAnd(valuable); } + Valuable LogicOr(const Valuable& valuable) const; + Valuable operator||(const Valuable& valuable) const { return LogicOr(valuable); } + + // Set operations (implemented using bit operations) + Valuable Intersect(const Valuable& valuable) const; + Valuable operator&(const Valuable& valuable) const { return Intersect(valuable); } + Valuable& intersect(const Valuable& valuable, const Variable& va); + Valuable& operator&=(const Valuable& valuable) { return intersect(valuable); } + + Valuable Union(const Valuable& valuable) const; + Valuable& unionize(const Valuable& valuable); + Valuable& operator|=(const Valuable& valuable) { return unionize(valuable); } +}; +---- + +== Core Bit Operations + +=== Bit Access + +* `bit(n)`: Extracts the nth bit from the value +* `bits(n, l)`: Extracts l bits starting from position n + +=== Bitwise Logical Operations + +* `Or(a, b)`: Performs bitwise OR between the value and operands a and b +* `And(a, b)`: Performs bitwise AND between the value and operands a and b +* `Xor(a, b)`: Performs bitwise XOR between the value and operands a and b +* `Not()`: Performs bitwise NOT on the value + +=== Bit Shifting + +* `shl(n)`: Shifts the value left by n bits (in-place) +* `shr(n)`: Shifts the value right by n bits (in-place) +* `Shl(n)`: Returns a new value shifted left by n bits +* `Shr(n)`: Returns a new value shifted right by n bits +* `Cyclic(n)`: Performs a cyclic shift (rotation) by n bits + +== Set Operations Using Bit Manipulation + +OpenMind implements set operations using bit manipulation for efficiency: + +* `Intersect(v)`: Set intersection (implemented as bitwise AND) +* `Union(v)`: Set union (implemented as bitwise OR) +* `Remove(v)`: Set difference +* `RootSetDifference(v)`: Root set difference +* `RootsSymetricDifference(v)`: Symmetric difference of root sets + +== Usage Examples + +=== Basic Bit Manipulation + +[source,cpp] +---- +#include +#include + +using namespace omnn::math; + +int main() { + // Create a value + Valuable v = 42_v; // Binary: 101010 + + // Extract bits + Valuable bit2 = v.bit(2); // Get the 3rd bit (0-indexed): 1 + Valuable bits23 = v.bits(2, 2); // Get 2 bits starting from position 2: 10 + + // Bitwise operations + Valuable result_or = v.Or(15_v, 0_v); // 42 OR 15: 47 (101111) + Valuable result_and = v.And(15_v, 0_v); // 42 AND 15: 10 (1010) + + // Bit shifting + Valuable shifted_left = v.Shl(2); // 42 << 2: 168 (10101000) + Valuable shifted_right = v.Shr(2); // 42 >> 2: 10 (1010) + + std::cout << "Original value: " << v << std::endl; + std::cout << "Bit 2: " << bit2 << std::endl; + std::cout << "Bits 2-3: " << bits23 << std::endl; + std::cout << "OR with 15: " << result_or << std::endl; + std::cout << "AND with 15: " << result_and << std::endl; + std::cout << "Left shift by 2: " << shifted_left << std::endl; + std::cout << "Right shift by 2: " << shifted_right << std::endl; + + return 0; +} +---- + +=== Set Operations + +[source,cpp] +---- +#include +#include + +using namespace omnn::math; + +int main() { + // Create two values representing sets + Valuable set1 = 42_v; // Binary: 101010 (represents set {1, 3, 5}) + Valuable set2 = 15_v; // Binary: 1111 (represents set {0, 1, 2, 3}) + + // Set operations + Valuable intersection = set1 & set2; // Intersection: 10 (represents set {1, 3}) + Valuable union_set = set1 | set2; // Union: 47 (represents set {0, 1, 2, 3, 5}) + Valuable difference = set1.Remove(set2); // Difference: 32 (represents set {5}) + + std::cout << "Set 1: " << set1 << std::endl; + std::cout << "Set 2: " << set2 << std::endl; + std::cout << "Intersection: " << intersection << std::endl; + std::cout << "Union: " << union_set << std::endl; + std::cout << "Difference (Set1 - Set2): " << difference << std::endl; + + return 0; +} +---- + +== Performance Characteristics + +The bit operations in OpenMind are designed for efficiency: + +* *Time Complexity*: + * Bit access operations (`bit`, `bits`): O(1) + * Bitwise logical operations (`Or`, `And`, `Xor`, `Not`): O(n) where n is the number of bits + * Bit shifting operations (`shl`, `shr`, `Shl`, `Shr`): O(n) where n is the number of bits + * Set operations: O(n) where n is the number of bits + +* *Space Complexity*: + * Most operations: O(1) additional space + * Operations returning new values: O(n) where n is the number of bits + +* *Optimization*: + * Operations are optimized for integers and use hardware-level bit manipulation when possible + * Large integers use specialized algorithms for efficient bit manipulation + +== Integration with Mathematical System + +The bit operations integrate with OpenMind's mathematical expression system: + +1. *Symbolic Bit Manipulation*: Perform bit operations on symbolic expressions +2. *Optimization*: Automatically optimize bit operations during expression evaluation +3. *Type Conversion*: Seamlessly convert between different numerical representations + +== Benefits and Applications + +* *Low-Level Optimization*: Efficient implementation of algorithms requiring bit manipulation +* *Set Operations*: Represent and manipulate sets using bit vectors +* *Cryptographic Operations*: Implement cryptographic primitives requiring bit manipulation +* *Data Compression*: Implement compression algorithms using bit operations +* *Hardware Simulation*: Model digital circuits and hardware behavior +* *Performance Optimization*: Optimize mathematical operations using bit-level techniques diff --git a/docs/modules/ROOT/pages/features/copy_on_write.adoc b/docs/modules/ROOT/pages/features/copy_on_write.adoc new file mode 100644 index 0000000000..bbd245aef4 --- /dev/null +++ b/docs/modules/ROOT/pages/features/copy_on_write.adoc @@ -0,0 +1,61 @@ += Copy-on-Write Feature +:description: Implementation and usage of the Copy-on-Write memory model in OpenMind + +== Overview + +OpenMind implements a Copy-on-Write (COW) memory model in the `Valuable` class to optimize memory usage and performance. This allows multiple objects to share the same underlying data until one of them needs to modify it, at which point a unique copy is created for the modifying object. + +== Implementation + +The COW implementation is centered around the `clone_on_write()` method in the `Valuable` class: + +[source,cpp] +---- +// From omnn/math/Valuable.h +protected: + using encapsulated_instance = ptrs::shared_ptr; + encapsulated_instance exp = nullptr; + + /// Ensures a unique copy of the object before modification (Copy-on-Write) + void clone_on_write(); +---- + +When a modifying operation (like `operator+=`) is called on a `Valuable` object, the `clone_on_write()` method is invoked to ensure the object has exclusive ownership of its data before making any changes. + +== Benefits + +* **Memory Efficiency**: Multiple objects can share the same memory until modification +* **Performance**: Reduces unnecessary copying of large objects +* **Thread Safety**: When properly used, helps manage access to shared data +* **Simplicity**: Implementation details are hidden from the user + +== Usage Example + +[source,cpp] +---- +#include + +using namespace omnn::math; + +int main() { + // Create a Valuable object + Valuable v1 = 42_v; + + // Create a second reference to the same object + Valuable v2 = v1; + + // At this point, v1 and v2 share the same data + // Modifying v2 will trigger a copy + v2 += 10_v; + + // Now v1 is still 42, but v2 is 52 + std::cout << "v1: " << v1 << std::endl; // Output: v1: 42 + std::cout << "v2: " << v2 << std::endl; // Output: v2: 52 + + return 0; +} +---- + +== Testing + +The COW functionality is verified through unit tests in `omnn/math/test/Valuable_COW_test.cpp`, which tests various scenarios to ensure proper copying behavior. diff --git a/docs/modules/ROOT/pages/features/knowledge_matrix/index.adoc b/docs/modules/ROOT/pages/features/knowledge_matrix/index.adoc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/modules/ROOT/pages/features/logic_system.adoc b/docs/modules/ROOT/pages/features/logic_system.adoc new file mode 100644 index 0000000000..67b1a728f5 --- /dev/null +++ b/docs/modules/ROOT/pages/features/logic_system.adoc @@ -0,0 +1,146 @@ += Logic System +:description: Logical operations and propositional reasoning in OpenMind + +== Overview + +The OpenMind Logic System provides capabilities for propositional reasoning, logical operations, and inference. This module enables the representation and manipulation of logical propositions, equality constraints, and inference rules. + +== Implementation + +The logic system is implemented in the `omnn/logic` directory. The core components include: + +=== Proposition Class + +The `Proposition` class represents logical statements that can be evaluated to true or false: + +[source,cpp] +---- +namespace omnn::logic { + class Proposition { + bool evaluate() const; // O(1) evaluation + Proposition simplify() const; // CNF simplification + bool isContradiction() const noexcept; // Consistency check + }; +} +---- + +=== Equality Class + +The `Equality` class represents equality constraints between expressions: + +[source,cpp] +---- +// From omnn/logic/Equality.h +namespace omnn { +namespace logic { +// if a==1 then b==1 else b==-1 + // A: a==1 + // B: b==1 + // C: b=-1 + // Equivalent: A and B or C + // E: (((a-1)^2)+((b-1)^2))(b+1)==0 + // !A: E && C : E^2+(b+1)^2=0 : + // Total: (A && B) || (!A && C) : ((a-1)^2+(b-1)^2)(((((a-1)^2)+((b-1)^2))(b+1))^2+(b+1)^2) + +class Equality { + // Implementation details +}; +}} +---- + +=== Inference Engine + +The `InferenceEngine` class provides mechanisms for logical inference: + +[source,cpp] +---- +namespace omnn::logic { + class InferenceEngine { + void addRule(const Rule& rule); // Add inference rule + void addFact(const Fact& fact); // Add known fact + std::vector infer(); // Forward chaining + }; +} +---- + +== Logical Operations + +The logic system supports various logical operations: + +1. *Evaluation*: Determine the truth value of a proposition +2. *Simplification*: Convert propositions to Conjunctive Normal Form (CNF) +3. *Contradiction Detection*: Check if a proposition is a logical contradiction +4. *Inference*: Derive new facts from existing facts and rules +5. *Equality Constraints*: Express and manipulate equality relationships + +== Integration with Mathematical System + +The logic system integrates with OpenMind's mathematical expression system, allowing for: + +1. *Logical Expressions as Mathematical Formulas*: Represent logical operations using mathematical expressions +2. *Constraint Satisfaction*: Solve systems of logical constraints +3. *Symbolic Reasoning*: Perform symbolic manipulation of logical expressions + +== Usage Example + +[source,cpp] +---- +#include +#include +#include + +using namespace omnn::logic; + +int main() { + // Create logical propositions + Proposition p("x > 0"); + Proposition q("y < 10"); + + // Combine propositions with logical operations + Proposition conjunction = p.And(q); + Proposition disjunction = p.Or(q); + Proposition implication = p.Implies(q); + + // Simplify to CNF + Proposition simplified = implication.simplify(); + + // Check for contradictions + if (!simplified.isContradiction()) { + std::cout << "The proposition is satisfiable" << std::endl; + } + + // Set up inference engine + InferenceEngine engine; + engine.addFact(p); + engine.addRule(Rule(p, q)); // If p then q + + // Perform inference + auto inferred_facts = engine.infer(); + + return 0; +} +---- + +== Mathematical Representation + +Logical operations can be represented as mathematical expressions. For example, the equality constraint "if a==1 then b==1 else b==-1" can be expressed as: + +[source] +---- +((a-1)^2+(b-1)^2)(((((a-1)^2)+((b-1)^2))(b+1))^2+(b+1)^2) +---- + +This mathematical representation allows for: + +1. *Efficient Evaluation*: Using mathematical operations for logical evaluation +2. *Integration with Equation Solving*: Solving logical constraints as part of equation systems +3. *Optimization*: Applying mathematical optimization techniques to logical problems + +== Benefits and Applications + +* *Automated Reasoning*: Derive logical conclusions from premises +* *Constraint Satisfaction*: Solve problems with logical constraints +* *Knowledge Representation*: Express knowledge in a formal, machine-processable form +* *Decision Support*: Provide logical foundations for decision-making systems +* *Verification*: Verify the correctness of systems against logical specifications +* *Integration with Mathematical Reasoning*: Combine logical and mathematical reasoning for complex problem-solving diff --git a/docs/modules/ROOT/pages/features/quantum_computing.adoc b/docs/modules/ROOT/pages/features/quantum_computing.adoc new file mode 100644 index 0000000000..ff8766a55b --- /dev/null +++ b/docs/modules/ROOT/pages/features/quantum_computing.adoc @@ -0,0 +1,144 @@ += Quantum Computing +:description: Quantum computing capabilities in OpenMind + +== Overview + +OpenMind includes quantum computing capabilities through the `QuantumRegister` class, which provides a framework for quantum state manipulation and operations. This module enables simulation of quantum systems, representation of quantum states, and implementation of quantum gates. + +== Implementation + +The quantum computing module is implemented in the `omnn/quantum` directory: + +[source,cpp] +---- +// From omnn/quantum/QuantumRegister.h +class QuantumRegister { +public: + // Constructor for n-qubit register initialized to |0...0⟩ state + explicit QuantumRegister(size_t num_qubits) + : num_qubits(num_qubits), state_vector(1ULL << num_qubits) { + // Initialize to |0...0⟩ state + state_vector[0] = std::complex(1.0, 0.0); + } + + // Apply controlled phase rotation + void apply_controlled_phase(size_t control, size_t target, double angle); + + // Normalize the quantum state + void normalize(); + +private: + size_t num_qubits; + std::vector> state_vector; +}; +---- + +The implementation of the quantum operations is provided in `QuantumRegister.cpp`: + +[source,cpp] +---- +void QuantumRegister::apply_controlled_phase(size_t control, size_t target, double angle) { + // Validate qubit indices + if (control >= num_qubits || target >= num_qubits) { + throw std::out_of_range("Qubit index out of range"); + } + if (control == target) { + throw std::invalid_argument("Control and target qubits must be different"); + } + + // Calculate controlled phase rotation + const std::complex phase_factor(std::cos(angle), std::sin(angle)); + + // Size of the state vector + const size_t n = 1ULL << num_qubits; + + // Apply controlled phase rotation + for (size_t i = 0; i < n; ++i) { + // Check if both control and target qubits are 1 + if ((i & (1ULL << control)) && (i & (1ULL << target))) { + state_vector[i] *= phase_factor; + } + } + + // Normalize the state vector + normalize(); +} + +void QuantumRegister::normalize() { + double norm = 0.0; + const double epsilon = 1e-10; // Threshold for numerical stability + + // Calculate the norm + for (const auto& amplitude : state_vector) { + norm += std::norm(amplitude); + } + + // Only normalize if the norm deviates significantly from 1 + if (std::abs(norm - 1.0) > epsilon) { + const double scale_factor = 1.0 / std::sqrt(norm); + for (auto& amplitude : state_vector) { + amplitude *= scale_factor; + } + } +} +---- + +== Usage Example + +[source,cpp] +---- +#include +#include +#include + +using namespace omnn::math; + +int main() { + // Create a 2-qubit register (initialized to |00⟩) + QuantumRegister qreg(2); + + // Apply controlled phase rotation (creates entanglement) + qreg.apply_controlled_phase(0, 1, M_PI/2); + + // Additional operations would be performed here + // ... + + return 0; +} +---- + +== Quantum Operations + +The `QuantumRegister` class currently supports the following operations: + +1. *Initialization*: Create a quantum register with a specified number of qubits, initialized to the |0...0⟩ state. + +2. *Controlled Phase Rotation*: Apply a phase rotation to the target qubit when the control qubit is in the |1⟩ state. This operation is essential for creating entanglement between qubits. + +3. *Normalization*: Ensure that the quantum state remains normalized (sum of squared amplitudes equals 1), which is a requirement for valid quantum states. + +== Integration with OpenMind + +The quantum computing module integrates with the rest of the OpenMind framework, allowing for: + +* Combination of quantum and classical computation +* Representation of quantum algorithms as mathematical expressions +* Potential for quantum machine learning applications + +== Future Developments + +As indicated by the placeholder comment in the implementation, additional features planned for the quantum computing module include: + +* Additional quantum gates (Hadamard, X, Y, Z, CNOT) +* Measurement operations +* Multi-qubit operations +* Quantum circuit representation +* Quantum algorithm implementations + +== Benefits and Applications + +* *Quantum Simulation*: Model quantum systems and algorithms +* *Entanglement Representation*: Create and manipulate entangled states +* *Quantum Algorithm Development*: Provide a framework for implementing and testing quantum algorithms +* *Educational Tool*: Learn about quantum computing concepts through practical implementation +* *Integration with Classical Computation*: Combine quantum and classical approaches for hybrid algorithms diff --git a/docs/modules/ROOT/pages/features/state_loading/index.adoc b/docs/modules/ROOT/pages/features/state_loading/index.adoc new file mode 100644 index 0000000000..94c00a781c --- /dev/null +++ b/docs/modules/ROOT/pages/features/state_loading/index.adoc @@ -0,0 +1,136 @@ += State Loading Capabilities for Knowledge Matrix +:navtitle: State Loading Capabilities +:description: Documentation for state loading capabilities to enhance the Hierarchical Knowledge Matrix in OpenMind + +== Overview + +This document outlines the high-level goals for implementing state loading capabilities in OpenMind. These capabilities will allow the Hierarchical Knowledge Matrix to load and analyze different types of state data, enabling more powerful reasoning and problem-solving across various domains. + +== Core Objectives + +The primary objective is to make the probabilistic reasoning approach achievable easily through OpenMind or Skrypt by implementing loaders for various types of state data: + +* *Game States*: Load and analyze states from games like Freesweeper and Sudoku +* *Code Analysis*: Load and analyze C++ code for static analysis and bug detection +* *Debugging Data*: Load and analyze callstacks and coredumps for root cause analysis + +== State Loading Capabilities + +=== Freesweeper State Loading + +*High-Level Goals:* + +1. Develop a parser to read Freesweeper game state from text output +2. Create a representation of the game state in the Hierarchical Knowledge Matrix +3. Implement probability calculations for mine locations based on visible numbers +4. Provide an interface for making optimal move decisions +5. Support real-time updates as the game progresses + +*Implementation Approach:* + +* Parse text-based game board representation +* Map cells to matrix positions with deeper matrices for probability distributions +* Update probabilities based on game rules and visible numbers +* Identify safe moves and likely mine locations + +=== Sudoku State Loading + +*High-Level Goals:* + +1. Develop a parser to read Sudoku puzzles from various formats +2. Create a representation of the puzzle state in the Hierarchical Knowledge Matrix +3. Implement constraint propagation using probability distributions +4. Support different solving strategies (simple, backtracking, etc.) +5. Provide visualization of solution progress + +*Implementation Approach:* + +* Parse puzzle input from text or image formats +* Map cells to matrix positions with deeper matrices for candidate probabilities +* Update probabilities based on Sudoku constraints (row, column, box) +* Identify cells with high certainty for next moves + +=== C++ Code Loading + +*High-Level Goals:* + +1. Develop a parser to read and analyze C++ code +2. Create a representation of code structure in the Hierarchical Knowledge Matrix +3. Implement static analysis capabilities for detecting potential issues +4. Support pattern matching for identifying code smells +5. Provide recommendations for code improvements + +*Implementation Approach:* + +* Parse C++ code using a robust parser (e.g., Clang) +* Map code elements (functions, variables, etc.) to matrix positions +* Represent relationships between code elements using deeper matrices +* Calculate probabilities for potential issues or bugs + +=== Callstack Loading + +*High-Level Goals:* + +1. Develop a parser to read callstack data from various formats +2. Create a representation of the callstack in the Hierarchical Knowledge Matrix +3. Implement analysis capabilities for identifying potential issues +4. Support correlation with source code +5. Provide insights into execution flow + +*Implementation Approach:* + +* Parse callstack data from debugger output or crash reports +* Map stack frames to matrix positions +* Represent relationships between frames using deeper matrices +* Calculate probabilities for potential error sources + +=== Coredump Loading + +*High-Level Goals:* + +1. Develop a parser to read coredump data +2. Create a representation of memory state in the Hierarchical Knowledge Matrix +3. Implement analysis capabilities for identifying memory corruption +4. Support correlation with source code and callstacks +5. Provide insights into crash causes + +*Implementation Approach:* + +* Parse coredump data using appropriate tools +* Map memory regions to matrix positions +* Represent memory state using deeper matrices for detailed analysis +* Calculate probabilities for potential crash causes + +== Integration with OpenMind + +These state loading capabilities will be integrated with OpenMind through: + +1. *Facility System*: Each loader will be implemented as a specialized facility +2. *Goal System*: Goals will be created for analyzing loaded states +3. *Knowledge Representation*: States will be represented using the Hierarchical Knowledge Matrix + +== Integration with Skrypt + +For Skrypt integration, we will: + +1. Create Python bindings for the state loading facilities +2. Implement Skrypt-specific interfaces for accessing loaded states +3. Provide examples of using Skrypt for state analysis + +== Expected Benefits + +Implementing these state loading capabilities will: + +1. *Enhance Problem-Solving*: Enable more sophisticated reasoning across domains +2. *Improve Root Cause Analysis*: Provide powerful tools for debugging and RCA +3. *Unify Approach*: Apply the same probabilistic reasoning framework to diverse problems +4. *Save Development Time*: Reuse the same core algorithms across different domains + +== Future Extensions + +Future work could include: + +1. *Additional State Types*: Support for more types of state data +2. *Enhanced Visualization*: Better visualization of state analysis +3. *Integration with ML*: Combine probabilistic reasoning with machine learning +4. *Distributed Analysis*: Support for analyzing states across distributed systems diff --git a/docs/modules/ROOT/pages/features/storage.adoc b/docs/modules/ROOT/pages/features/storage.adoc new file mode 100644 index 0000000000..d1b561c006 --- /dev/null +++ b/docs/modules/ROOT/pages/features/storage.adoc @@ -0,0 +1,205 @@ += Storage System +:description: LevelDB integration and caching system in OpenMind + +== Overview + +OpenMind provides a storage system based on LevelDB for efficient caching and persistence of data. This system allows for optimized storage and retrieval of computed mathematical expressions and other data, improving performance by avoiding redundant calculations. + +== Implementation + +The storage system is implemented through the `CacheBase` abstract class and the `LevelDbCache` concrete implementation: + +[source,cpp] +---- +// From omnn/storage/CacheBase.h +namespace omnn::rt::storage { + +class CacheBase { +public: + virtual std::string GetOne(const std::string_view& key) = 0; + virtual bool Set(const std::string_view& key, const std::string_view& v) = 0; + virtual bool Clear(const std::string_view& key) = 0; + virtual ~CacheBase() = default; +}; + +// From omnn/storage/LevelDbCache.h +class LevelDbCache + : public CacheBase +{ + leveldb::DB* _db = nullptr; + const std::string name; + +public: + LevelDbCache(const std::string_view& path); + std::string GetOne(const std::string_view& key) override; + bool Set(const std::string_view& key, const std::string_view& v) override; + bool Clear(const std::string_view& key) override; + ~LevelDbCache() override; + + static const leveldb::Options& GetDbConnectionOptions(); +}; +} +---- + +== Key Components + +=== CacheBase + +The `CacheBase` abstract class defines the interface for all cache implementations: + +* `GetOne(key)`: Retrieves a value by its key +* `Set(key, value)`: Stores a value with the specified key +* `Clear(key)`: Removes a value from the cache + +=== LevelDbCache + +The `LevelDbCache` class provides a concrete implementation using LevelDB: + +* Constructor takes a path where the database files will be stored +* Implements the `CacheBase` interface methods +* Manages the LevelDB connection and resources +* Provides custom connection options through `GetDbConnectionOptions()` + +== Configuration Options + +The LevelDB storage backend can be configured with various options: + +=== Compile-time Configuration + +The storage system requires the `OPENMIND_STORAGE_LEVELDB` flag to be enabled during compilation: + +[source,cpp] +---- +#ifdef OPENMIND_STORAGE_LEVELDB +class LevelDbCache + : public CacheBase +{ + // Implementation +}; +#endif // OPENMIND_STORAGE_LEVELDB +---- + +=== Runtime Configuration + +* **Path**: The location where the database files will be stored +* **Connection Options**: Custom options can be provided through `GetDbConnectionOptions()` + +=== LevelDB Options + +The `GetDbConnectionOptions()` method allows customization of LevelDB behavior: + +* Compression settings +* Block size +* Cache size +* Write buffer size +* Max open files + +== Usage Example + +[source,cpp] +---- +#include +#include +#include + +using namespace omnn::rt::storage; + +int main() { + // Create a LevelDB cache instance + LevelDbCache cache("/path/to/cache"); + + // Store a value + std::string key = "formula_42"; + std::string value = "x^2 + 2*x + 1"; + + if (cache.Set(key, value)) { + std::cout << "Value stored successfully" << std::endl; + } + + // Retrieve a value + std::string retrieved = cache.GetOne(key); + std::cout << "Retrieved value: " << retrieved << std::endl; + + // Clear a value + if (cache.Clear(key)) { + std::cout << "Value cleared successfully" << std::endl; + } + + return 0; +} +---- + +== Integration with Mathematical System + +The storage system integrates with OpenMind's mathematical expression system through the `Cache` class in `omnn/math/Cache.h`: + +[source,cpp] +---- +namespace omnn::math { + class Cache { + public: + // Store an optimized expression + static void Set(const Valuable& key, const Valuable& value); + + // Retrieve an optimized expression + static Valuable Get(const Valuable& key); + + // Check if an expression is cached + static bool Has(const Valuable& key); + + // Clear a cached expression + static void Clear(const Valuable& key); + }; +} +---- + +This integration allows for: + +1. *Automatic Caching*: Expressions are automatically cached during optimization +2. *Transparent Retrieval*: Cached results are used without requiring explicit cache management +3. *Performance Optimization*: Expensive calculations are performed only once + +== Performance Considerations + +=== Asynchronous Operations + +The storage system supports asynchronous operations for improved performance: + +* Non-blocking writes using background threads +* Batch operations for multiple keys +* Parallel reads for improved throughput + +=== Caching Strategy + +The caching system employs several strategies to optimize performance: + +* *Memory Caching*: Frequently accessed items are kept in memory for faster access +* *Disk Persistence*: Less frequently accessed items are stored on disk +* *Eviction Policy*: Least recently used items are evicted when the cache reaches capacity +* *Serialization*: Efficient binary serialization for mathematical expressions + +=== Benchmarks + +Performance benchmarks show significant improvements when using the storage system: + +* *Computation Speedup*: Up to 10x faster for repeated complex calculations +* *Memory Usage*: Reduced memory footprint for applications with many repeated expressions +* *I/O Performance*: Optimized for both read and write operations + +== Benefits and Applications + +* *Performance Optimization*: Avoid redundant calculations by caching results +* *Persistence*: Data survives application restarts +* *Memory Efficiency*: Reduce memory usage by offloading data to disk +* *Distributed Computing*: Share cached results across multiple processes +* *Incremental Computation*: Build on previously computed results + +== Future Developments + +Planned enhancements to the storage system include: + +* Support for additional storage backends (Redis, FoundationDB) +* Distributed caching across multiple nodes +* Time-to-live (TTL) for cached items +* Cache statistics and monitoring +* Compression options for large datasets diff --git a/docs/modules/ROOT/pages/getting-started.adoc b/docs/modules/ROOT/pages/getting-started.adoc index 761fc5ed1c..e7fa0cb88e 100644 --- a/docs/modules/ROOT/pages/getting-started.adoc +++ b/docs/modules/ROOT/pages/getting-started.adoc @@ -30,6 +30,35 @@ cmake --build build -j$(nproc) This section will be expanded with actual usage examples from the codebase. ==== +== Python Integration + +OpenMind can be used from Python through its Python bindings: + +[source,python] +---- +# Import OpenMind Python module +import openmind.math as om_math + +# Create and manipulate variables +x = om_math.Variable("x") +y = om_math.Variable("y") + +# Create expressions +expr = x * y + x / y + +# Evaluate with specific values +result = expr.evaluate({"x": 10, "y": 5}) +print(f"Result: {result}") +---- + +To enable Python bindings during build: + +[source,bash] +---- +cmake -B build -DOPENMIND_BUILD_PYTHON_BINDINGS=ON +cmake --build build +---- + == Next Steps * Learn about the xref:architecture/overview.adoc[architecture] diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 21b15c6515..1027f3f3e2 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -6,12 +6,26 @@ OpenMind is a C++ AGI infrastructure framework implementing: * Knowledge accumulation in universal distributed forms * Deduction capabilities for information processing * Self-modification with system integrity preservation +* Efficient memory management using Copy-on-Write +* Python integration through Boost.Python bindings +* Quantum computing capabilities +* Advanced bit manipulation operations +* Logic system for propositional reasoning +* Persistent storage with LevelDB integration +* Advanced mathematical operations == Documentation Structure * xref:getting-started.adoc[Getting Started]: Environment setup and basic usage * xref:architecture/overview.adoc[Architecture]: Core systems and data flows * xref:development/building.adoc[Development]: Build process and contribution +* xref:development/python_wrapper.adoc[Python Bindings]: Using OpenMind from Python +* xref:features/copy_on_write.adoc[Copy-on-Write]: Memory optimization feature +* xref:features/quantum_computing.adoc[Quantum Computing]: Quantum state manipulation +* xref:features/logic_system.adoc[Logic System]: Propositional logic and inference +* xref:features/bit_operations.adoc[Bit Operations]: Low-level bit manipulation +* xref:features/storage.adoc[Storage System]: Persistent data storage +* xref:features/advanced_math.adoc[Advanced Mathematics]: Complex mathematical operations * xref:reference/api.adoc[API]: Interface specifications * xref:reference/configuration.adoc[Configuration]: System parameters * xref:skrypt/screenshots.adoc[SKRYPT Screenshots]: Visual documentation of the SKRYPT system diff --git a/docs/modules/ROOT/pages/reference/api.adoc b/docs/modules/ROOT/pages/reference/api.adoc index bad2db6cc7..77490a44be 100644 --- a/docs/modules/ROOT/pages/reference/api.adoc +++ b/docs/modules/ROOT/pages/reference/api.adoc @@ -51,6 +51,16 @@ namespace omnn::math { Variable operator+(const Variable&) const; Variable operator*(const Variable&) const; }; + + class Valuable { + // Copy-on-Write implementation + void clone_on_write(); // Creates unique copy on modification + bool is_shared() const; // Checks if memory is shared + + // Common operations with COW semantics + Valuable& operator+=(const Valuable&); // Modifies with COW check + Valuable& operator*=(const Valuable&); // Modifies with COW check + }; } ---- diff --git a/docs/modules/ROOT/pages/reference/knowledge_base.adoc b/docs/modules/ROOT/pages/reference/knowledge_base.adoc index 51f5a3ce17..228aaad6e3 100644 --- a/docs/modules/ROOT/pages/reference/knowledge_base.adoc +++ b/docs/modules/ROOT/pages/reference/knowledge_base.adoc @@ -14,6 +14,13 @@ The consolidated knowledge base document contains comprehensive information abou * Testing * Implementation details * Development guidelines +* Python bindings +* Copy-on-Write memory model +* Quantum computing capabilities +* Logic system and propositional reasoning +* Bit manipulation operations +* Storage system with LevelDB +* Advanced mathematical operations link:https://app.devin.ai/attachments/422f0be7-baa9-45bf-905c-45ebe3462f20/consolidated_knowledge_base.pdf[Download Consolidated Knowledge Base (PDF)] diff --git a/omnn/CMakeLists.txt b/omnn/CMakeLists.txt index 12154f2856..a341a09cd1 100644 --- a/omnn/CMakeLists.txt +++ b/omnn/CMakeLists.txt @@ -1,5 +1,6 @@ -# OpenMind Neural Networks + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + fold( rt storage diff --git a/omnn/extrapolator/Extrapolator.cpp b/omnn/extrapolator/Extrapolator.cpp index c341b3f439..99a8ee6369 100644 --- a/omnn/extrapolator/Extrapolator.cpp +++ b/omnn/extrapolator/Extrapolator.cpp @@ -4,8 +4,8 @@ #include "Extrapolator.h" -#include "math/Integer.h" -#include "math/Sum.h" +#include "omnn/math/Integer.h" +#include "omnn/math/Sum.h" using namespace omnn; using namespace math; diff --git a/omnn/extrapolator/test/test_extrapolator.cpp b/omnn/extrapolator/test/test_extrapolator.cpp index aaa0b2e373..a8e224ab93 100644 --- a/omnn/extrapolator/test/test_extrapolator.cpp +++ b/omnn/extrapolator/test/test_extrapolator.cpp @@ -4,7 +4,7 @@ #define BOOST_TEST_MODULE Extrapolator test #include #include "Extrapolator.h" -#include "math/Sum.h" +#include "omnn/math/Sum.h" using namespace omnn::math; using namespace boost::unit_test; diff --git a/omnn/loader/CMakeLists.txt b/omnn/loader/CMakeLists.txt new file mode 100644 index 0000000000..c2c0cd8548 --- /dev/null +++ b/omnn/loader/CMakeLists.txt @@ -0,0 +1 @@ +#fold() diff --git a/omnn/loader/asm/CMakeLists.txt b/omnn/loader/asm/CMakeLists.txt new file mode 100644 index 0000000000..6b3d71a388 --- /dev/null +++ b/omnn/loader/asm/CMakeLists.txt @@ -0,0 +1,4 @@ +lib( + math + StanfordPL/x64asm +) diff --git a/omnn/logic/Equality.h b/omnn/logic/Equality.h index 9ee43d8af3..29bdfe77e5 100644 --- a/omnn/logic/Equality.h +++ b/omnn/logic/Equality.h @@ -3,7 +3,7 @@ // #pragma once -#include "math/ValuableDescendantContract.h" +#include namespace omnn{ namespace logic { diff --git a/omnn/math/Cache.cpp b/omnn/math/Cache.cpp index 6c62b2c154..cab2e8e960 100644 --- a/omnn/math/Cache.cpp +++ b/omnn/math/Cache.cpp @@ -5,7 +5,7 @@ #include -#include +#include #include @@ -17,6 +17,7 @@ using namespace omnn::math; using namespace omnn::rt; +using namespace omnn::storage; using namespace std::chrono_literals; @@ -42,7 +43,7 @@ void Cache::DbOpen() { # endif leveldb::Status status; auto strPath = path.string(); - const auto& options = omnn::rt::storage::LevelDbCache::GetDbConnectionOptions(); + const auto& options = LevelDbCache::GetDbConnectionOptions(); while (!((status = leveldb::DB::Open(options, strPath, &db)).ok())) { auto err = strPath + " DB connection error"; std::cerr << err << status.ToString() << std::endl; diff --git a/omnn/math/Logarithm.cpp b/omnn/math/Logarithm.cpp index 01178d6b67..3f8362153c 100644 --- a/omnn/math/Logarithm.cpp +++ b/omnn/math/Logarithm.cpp @@ -6,7 +6,7 @@ #include "NaN.h" #include "PrincipalSurd.h" -#include "rt/strhash.hpp" +#include "omnn/rt/strhash.hpp" #include diff --git a/omnn/math/Product.cpp b/omnn/math/Product.cpp index eccf72d3ae..817875dae1 100644 --- a/omnn/math/Product.cpp +++ b/omnn/math/Product.cpp @@ -15,8 +15,9 @@ #include "PrincipalSurd.h" #include "VarHost.h" -#include -#include +#include "omnn/rt/antiloop.hpp" +#include "omnn/rt/each.hpp" +#include "omnn/rt/find.hpp" #include #include diff --git a/omnn/math/Sum.cpp b/omnn/math/Sum.cpp index c5f8609c61..79dd8db808 100644 --- a/omnn/math/Sum.cpp +++ b/omnn/math/Sum.cpp @@ -17,10 +17,10 @@ #include "VarHost.h" #include "Cache.h" -#include -#include -#include -#include +#include "omnn/rt/antiloop.hpp" +#include "omnn/rt/cl.h" +#include "omnn/rt/each.hpp" +#include "omnn/rt/Divisors.hpp" //TODO: //import std; diff --git a/omnn/math/System.cpp b/omnn/math/System.cpp index de6b87ac01..6fe3d74762 100644 --- a/omnn/math/System.cpp +++ b/omnn/math/System.cpp @@ -10,8 +10,8 @@ #include #include -#include -#include +#include "omnn/rt/antiloop.hpp" +#include "omnn/rt/each.hpp" using namespace omnn; diff --git a/omnn/math/Valuable.cpp b/omnn/math/Valuable.cpp index bf4ec7e9bf..a090e77be1 100644 --- a/omnn/math/Valuable.cpp +++ b/omnn/math/Valuable.cpp @@ -1929,12 +1929,10 @@ bool Valuable::SerializedStrEqual(const std::string_view& s) const { bool Valuable::operator==(const Valuable& v) const { - if(exp) - return -// NO: Hash()==v.Hash() && // example: empty sum hash differs; product 1*x*y == x*y ; etc - exp->operator==(v); + if (exp) + return exp->operator==(v); else - IMPLEMENT + LOG_AND_IMPLEMENT(*this << " == " << v); } bool Valuable::IsConstant() const { return exp && exp->IsConstant(); } @@ -2419,6 +2417,9 @@ bool Valuable::SerializedStrEqual(const std::string_view& s) const { { if (exp) return exp->Same(value); + if (Is()) + return {}; + return Hash() == value.Hash() && OfSameType(value) && operator==(value); diff --git a/omnn/math/Variable.cpp b/omnn/math/Variable.cpp index 86c013f92a..fbd46c8117 100644 --- a/omnn/math/Variable.cpp +++ b/omnn/math/Variable.cpp @@ -210,6 +210,19 @@ namespace math { || (Hash() == value.Hash() && value.operator==(*this)); } + bool Variable::Same(const Variable& variable) const + { + return hash == variable.Hash() + && varSetHost == variable.varSetHost + && varSetHost->CompareIdsEqual(varId, variable.varId); + } + + bool Variable::Same(const Valuable& value) const + { + return value.IsVa() + && Same(value.as()); + } + bool Variable::operator==(const Variable& v) const { if (varSetHost != v.varSetHost) { diff --git a/omnn/math/Variable.h b/omnn/math/Variable.h index 29e6f8d355..f3dc627086 100644 --- a/omnn/math/Variable.h +++ b/omnn/math/Variable.h @@ -59,6 +59,9 @@ class Variable bool operator<(const Valuable&) const override; bool operator==(const Valuable&) const override; bool operator==(const Variable&) const; + bool Same(const Variable&) const; + bool Same(const Valuable&) const override; + Valuable calcFreeMember() const override { return constants::zero; } // void optimize() override; // Valuable sqrt() const override; diff --git a/omnn/math/antiloop.hpp b/omnn/math/antiloop.hpp new file mode 100644 index 0000000000..66af3596cf --- /dev/null +++ b/omnn/math/antiloop.hpp @@ -0,0 +1,24 @@ +#pragma once +#include +#include + +namespace omnn::math { + +using same_valuable_cmp_t = decltype([](const Valuable& val1, const Valuable& val2){return val1.Same(val2);}); +using ValuableLoopDetect = LoopDetectionGuard; + +#undef ANTILOOP +#if !defined(NDEBUG) && !defined(NOOMDEBUG) +#define ANTILOOP(Type) \ + ::omnn::math::ValuableLoopDetect antilooper(*this); \ + if (antilooper.isLoopDetected()) { \ + std::cout << "LoopDetectionGuard detected a loop in " << __func__ << " : " << *this << std::endl; \ + return; \ + } +#else +#define ANTILOOP(Type) \ + ::omnn::math::ValuableLoopDetect antilooper(*this); \ + if (antilooper.isLoopDetected()) { \ + return; \ + } +#endif diff --git a/omnn/math/test/PowerFlow_test.cpp b/omnn/math/test/PowerFlow_test.cpp new file mode 100644 index 0000000000..2dd7e08615 --- /dev/null +++ b/omnn/math/test/PowerFlow_test.cpp @@ -0,0 +1,43 @@ +#define BOOST_TEST_MODULE PowerFlow test +#include + +#include "Variable.h" +#include "Sum.h" +#include "Product.h" +#include "System.h" +#include "generic.hpp" + +using namespace omnn::math; +using namespace boost::unit_test; + +BOOST_AUTO_TEST_CASE(PowerFlow_tests) +{ + + Variable V1, V2, V3; + + auto y12 = 0.1_v; + auto y13 = 0.2_v; + auto y23 = 0.15_v; + + auto Y11 = y12 + y13; + auto Y22 = y12 + y23; + auto Y33 = y13 + y23; + + auto Y12 = -y12; + auto Y13 = -y13; + auto Y23 = -y23; + auto Y21 = -y12; // Y21 = Y12 by symmetry + + BOOST_TEST(Y12 == Y21); // Symmetry property + + + auto V1_val = 1.0_v; + auto V2_val = 0.95_v; + auto V3_val = 1.05_v; + + auto I1 = V1_val * Y11 + Y12 * V2_val + Y13 * V3_val; + + auto S1 = V1_val * I1; + + BOOST_TEST((S1 == V1_val * (V1_val * Y11 + Y12 * V2_val + Y13 * V3_val))); +} diff --git a/omnn/rt/antiloop.hpp b/omnn/rt/antiloop.hpp index 0f113ee48b..4c6dd6c90c 100644 --- a/omnn/rt/antiloop.hpp +++ b/omnn/rt/antiloop.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include namespace omnn::rt { @@ -8,6 +9,7 @@ template , ComparatorT> > class LoopDetectionGuard { + static constexpr ComparatorT comparator = ComparatorT(); static thread_local ContainerT LoopDetectionStack; bool isLoop; const ValueT* value; @@ -21,7 +23,14 @@ class LoopDetectionGuard { ~LoopDetectionGuard() { if (!isLoop) - LoopDetectionStack.erase(*value); + { + if (LoopDetectionStack.size() == 1) { + //assert(comparator(LoopDetectionStack.begin()->get(), value->get())); + LoopDetectionStack.clear(); + } else { + LoopDetectionStack.erase(*value); + } + } } constexpr auto isLoopDetected() const { return isLoop; } diff --git a/omnn/rt/storage/CMakeLists.txt b/omnn/rt/storage/CMakeLists.txt new file mode 100644 index 0000000000..36b8185352 --- /dev/null +++ b/omnn/rt/storage/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.15) + +# Find required packages +find_package(hiredis REQUIRED) +find_package(Boost REQUIRED COMPONENTS unit_test_framework) + +# Add Redis cache library +add_library(redis_cache + RedisCache.cpp + RedisCache.h +) + +target_link_libraries(redis_cache + PUBLIC + hiredis::hiredis + cache_base +) + +target_include_directories(redis_cache + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Add tests subdirectory +add_subdirectory(tests) diff --git a/omnn/rt/storage/RedisCache.cpp b/omnn/rt/storage/RedisCache.cpp new file mode 100644 index 0000000000..66f5b88d19 --- /dev/null +++ b/omnn/rt/storage/RedisCache.cpp @@ -0,0 +1,121 @@ +#include "RedisCache.h" +#include +#include +#include + +namespace omnn { +namespace rt { +namespace storage { + +RedisCache::RedisCache(const std::string& host, int port, int timeout_ms, + int retry_count, int retry_delay_ms) + : host_(host), port_(port), timeout_ms_(timeout_ms), + retry_count_(retry_count), retry_delay_ms_(retry_delay_ms), + context_(nullptr) { + if (!Connect()) { + throw std::runtime_error("Failed to connect to Redis server"); + } +} + +RedisCache::~RedisCache() { + Disconnect(); +} + +bool RedisCache::Connect() { + Disconnect(); // Ensure any existing connection is closed + + struct timeval timeout = { + .tv_sec = timeout_ms_ / 1000, + .tv_usec = (timeout_ms_ % 1000) * 1000 + }; + + context_ = redisConnectWithTimeout(host_.c_str(), port_, timeout); + + if (context_ == nullptr || context_->err) { + if (context_) { + redisFree(context_); + context_ = nullptr; + } + return false; + } + return true; +} + +void RedisCache::Disconnect() { + if (context_) { + redisFree(context_); + context_ = nullptr; + } +} + +bool RedisCache::RetryOperation(const std::function& operation) { + for (int i = 0; i < retry_count_; ++i) { + if (operation()) { + return true; + } + + if (!IsConnected() && !Connect()) { + std::this_thread::sleep_for(std::chrono::milliseconds(retry_delay_ms_)); + continue; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(retry_delay_ms_)); + } + return false; +} + +bool RedisCache::Set(const std::string& key, const std::string& value) { + return RetryOperation([this, &key, &value]() { + if (!IsConnected()) return false; + + redisReply* reply = (redisReply*)redisCommand(context_, "SET %s %s", + key.c_str(), value.c_str()); + if (!reply) return false; + + bool success = (reply->type == REDIS_REPLY_STATUS && + strcasecmp(reply->str, "OK") == 0); + freeReplyObject(reply); + return success; + }); +} + +bool RedisCache::Get(const std::string& key, std::string& value) { + return RetryOperation([this, &key, &value]() { + if (!IsConnected()) return false; + + redisReply* reply = (redisReply*)redisCommand(context_, "GET %s", + key.c_str()); + if (!reply) return false; + + bool success = false; + if (reply->type == REDIS_REPLY_STRING) { + value = std::string(reply->str, reply->len); + success = true; + } + + freeReplyObject(reply); + return success; + }); +} + +bool RedisCache::Clear() { + return RetryOperation([this]() { + if (!IsConnected()) return false; + + redisReply* reply = (redisReply*)redisCommand(context_, "FLUSHDB"); + if (!reply) return false; + + bool success = (reply->type == REDIS_REPLY_STATUS && + strcasecmp(reply->str, "OK") == 0); + freeReplyObject(reply); + return success; + }); +} + +bool RedisCache::IsConnected() const { + return context_ && !context_->err; +} + +} // namespace storage +} // namespace rt +} // namespace omnn diff --git a/omnn/rt/storage/RedisCache.h b/omnn/rt/storage/RedisCache.h new file mode 100644 index 0000000000..e8c658e374 --- /dev/null +++ b/omnn/rt/storage/RedisCache.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include "CacheBase.h" + +namespace omnn { +namespace rt { +namespace storage { + +class RedisCache : public CacheBase { +public: + RedisCache(const std::string& host = "localhost", int port = 6379, + int timeout_ms = 1000, int retry_count = 5, int retry_delay_ms = 1000); + ~RedisCache(); + + bool Set(const std::string& key, const std::string& value) override; + bool Get(const std::string& key, std::string& value) override; + bool Clear() override; + bool IsConnected() const; + +private: + bool Connect(); + void Disconnect(); + bool RetryOperation(const std::function& operation); + + std::string host_; + int port_; + int timeout_ms_; + int retry_count_; + int retry_delay_ms_; + redisContext* context_; +}; + +} // namespace storage +} // namespace rt +} // namespace omnn diff --git a/omnn/rt/storage/tests/CMakeLists.txt b/omnn/rt/storage/tests/CMakeLists.txt new file mode 100644 index 0000000000..b405dab180 --- /dev/null +++ b/omnn/rt/storage/tests/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.15) + +# Redis cache test +add_executable(redis_cache_test redis_cache_test.cpp) + +target_link_libraries(redis_cache_test + PRIVATE + redis_cache + Boost::unit_test_framework +) + +add_test(NAME redis_cache_test COMMAND redis_cache_test) + +# Set test properties +set_tests_properties(redis_cache_test PROPERTIES + ENVIRONMENT "OPENMIND_TEST_REDIS_RETRY_COUNT=5;OPENMIND_TEST_REDIS_RETRY_DELAY=1000" + TIMEOUT 60 +) diff --git a/omnn/rt/storage/tests/redis_cache_test.cpp b/omnn/rt/storage/tests/redis_cache_test.cpp new file mode 100644 index 0000000000..45ba99ece6 --- /dev/null +++ b/omnn/rt/storage/tests/redis_cache_test.cpp @@ -0,0 +1,59 @@ +#define BOOST_TEST_MODULE redis_cache_test +#include +#include "../RedisCache.h" +#include +#include + +using namespace omnn::rt::storage; + +struct RedisTestConfig { + RedisTestConfig() { + // Get retry configuration from environment + const char* retry_count = std::getenv("OPENMIND_TEST_REDIS_RETRY_COUNT"); + const char* retry_delay = std::getenv("OPENMIND_TEST_REDIS_RETRY_DELAY"); + + retry_count_ = retry_count ? std::stoi(retry_count) : 5; + retry_delay_ms_ = retry_delay ? std::stoi(retry_delay) : 1000; + } + + int retry_count_; + int retry_delay_ms_; +}; + +BOOST_FIXTURE_TEST_SUITE(redis_cache_tests, RedisTestConfig) + +BOOST_AUTO_TEST_CASE(test_basic_operations) { + RedisCache cache("localhost", 6379, 1000, retry_count_, retry_delay_ms_); + + // Test Set operation + BOOST_CHECK(cache.Set("test_key", "test_value")); + + // Test Get operation + std::string value; + BOOST_CHECK(cache.Get("test_key", value)); + BOOST_CHECK_EQUAL(value, "test_value"); + + // Test Clear operation + BOOST_CHECK(cache.Clear()); + BOOST_CHECK(!cache.Get("test_key", value)); +} + +BOOST_AUTO_TEST_CASE(test_nonexistent_key) { + RedisCache cache("localhost", 6379, 1000, retry_count_, retry_delay_ms_); + + std::string value; + BOOST_CHECK(!cache.Get("nonexistent_key", value)); +} + +BOOST_AUTO_TEST_CASE(test_connection_retry) { + // Test with invalid host to trigger retry mechanism + RedisCache cache("invalid_host", 6379, 100, 2, 100); + + // Operations should fail after retries + BOOST_CHECK(!cache.Set("test_key", "test_value")); + + std::string value; + BOOST_CHECK(!cache.Get("test_key", value)); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/omnn/storage/CMakeLists.txt b/omnn/storage/CMakeLists.txt index 56ab1463f0..2ada01eddd 100644 --- a/omnn/storage/CMakeLists.txt +++ b/omnn/storage/CMakeLists.txt @@ -1,33 +1,41 @@ option(OPENMIND_STORAGE_FOUNDATIONDB "Use Apple FoundationDB library for one of the multistorage levels" NO) option(OPENMIND_STORAGE_LEVELDB "Use Google LevelDB library for one of the multistorage levels" ON) +option(OPENMIND_STORAGE_REDIS "Use Redis for distributed caching" OFF) set(DEPENDENCIES rt) -if(OPENMIND_STORAGE_LEVELDB OR OPENMIND_STORAGE_FOUNDATIONDB) +if(OPENMIND_STORAGE_LEVELDB OR OPENMIND_STORAGE_FOUNDATIONDB OR OPENMIND_STORAGE_REDIS) option(OPENMIND_STORAGE_ALLOW_UPGRADE "Update optimized cached values during fetch if new optimizations applied" ON) option(OPENMIND_STORAGE_VOLATILE "Clean cache each start (for debugging purposes)" NO) - if(OPENMIND_STORAGE_LEVELDB) - find_package(Threads) # workaround leveldb config bug - list(APPEND DEPENDENCIES google/leveldb) - if(NOT WIN32) - list(APPEND DEPENDENCIES pthread) - endif() - endif() + if(OPENMIND_STORAGE_LEVELDB) + find_package(Threads) # workaround leveldb config bug + list(APPEND DEPENDENCIES google/leveldb) + if(NOT WIN32) + list(APPEND DEPENDENCIES pthread) + endif() + endif() - if(OPENMIND_STORAGE_FOUNDATIONDB) - list(APPEND DEPENDENCIES ohhmm/FoundationDB) - endif() + if(OPENMIND_STORAGE_FOUNDATIONDB) + list(APPEND DEPENDENCIES ohhmm/FoundationDB) + endif() -endif(OPENMIND_STORAGE_LEVELDB OR OPENMIND_STORAGE_FOUNDATIONDB) + if(OPENMIND_STORAGE_REDIS) + list(APPEND DEPENDENCIES Boost::redis) + endif() + +endif(OPENMIND_STORAGE_LEVELDB OR OPENMIND_STORAGE_FOUNDATIONDB OR OPENMIND_STORAGE_REDIS) lib(${DEPENDENCIES}) if(OPENMIND_STORAGE_LEVELDB) - target_compile_definitions(${this_target} PUBLIC OPENMIND_STORAGE_LEVELDB) + target_compile_definitions(${this_target} PUBLIC OPENMIND_STORAGE_LEVELDB) endif() if(OPENMIND_STORAGE_FOUNDATIONDB) - target_compile_definitions(${this_target} PUBLIC OPENMIND_STORAGE_FOUNDATIONDB) + target_compile_definitions(${this_target} PUBLIC OPENMIND_STORAGE_FOUNDATIONDB) +endif() +if(OPENMIND_STORAGE_REDIS) + target_compile_definitions(${this_target} PUBLIC OPENMIND_STORAGE_REDIS) endif() if(OPENMIND_STORAGE_ALLOW_UPGRADE) - target_compile_definitions(${this_target} PUBLIC ALLOW_UPGRADE OPENMIND_STORAGE_ALLOW_UPGRADE) -endif() \ No newline at end of file + target_compile_definitions(${this_target} PUBLIC ALLOW_UPGRADE OPENMIND_STORAGE_ALLOW_UPGRADE) +endif() diff --git a/omnn/storage/CacheBase.cpp b/omnn/storage/CacheBase.cpp index 1866ac9b6b..15e68a6079 100644 --- a/omnn/storage/CacheBase.cpp +++ b/omnn/storage/CacheBase.cpp @@ -1,6 +1,6 @@ #include "CacheBase.h" -using namespace omnn::rt::storage; +using namespace omnn::storage; bool CacheBase::ResetAllDB(const path_str_t& path) { auto deleted = fs::exists(path) ? fs::remove_all(path) : 0; diff --git a/omnn/storage/CacheBase.h b/omnn/storage/CacheBase.h index 33b7a9e642..ad6bc4201f 100644 --- a/omnn/storage/CacheBase.h +++ b/omnn/storage/CacheBase.h @@ -5,18 +5,18 @@ #include -namespace omnn::rt::storage { +namespace omnn::storage { namespace fs = boost::filesystem; class CacheBase { +public: using path_str_t = fs::path; -public: virtual std::string GetOne(const std::string_view& key) = 0; virtual bool Set(const std::string_view& key, const std::string_view& v) = 0; virtual bool Clear(const std::string_view& key) = 0; - virtual bool ResetAllDB(const path_str_t& path); + virtual bool ResetAllDB(const path_str_t& path) = 0; virtual ~CacheBase() {} }; diff --git a/omnn/storage/LevelDbCache.cpp b/omnn/storage/LevelDbCache.cpp index 7c011c38f1..d4b735cd53 100644 --- a/omnn/storage/LevelDbCache.cpp +++ b/omnn/storage/LevelDbCache.cpp @@ -7,7 +7,7 @@ #include -using namespace omnn::rt::storage; +using namespace omnn::storage; LevelDbCache::LevelDbCache(const std::string_view& path) @@ -36,6 +36,11 @@ bool LevelDbCache::Clear(const std::string_view &key) { return _status.ok(); } +bool LevelDbCache::ResetAllDB(const path_str_t& path) { + return base::ResetAllDB(path); +} + + LevelDbCache::~LevelDbCache() { delete _db; } @@ -43,7 +48,7 @@ LevelDbCache::~LevelDbCache() { namespace{ std::once_flag dbConnectionOptionsInitializedFlag; } -const leveldb::Options& omnn::rt::storage::LevelDbCache::GetDbConnectionOptions() { +const leveldb::Options& LevelDbCache::GetDbConnectionOptions() { static leveldb::Options options; std::call_once(dbConnectionOptionsInitializedFlag, [] { options.create_if_missing = true; diff --git a/omnn/storage/LevelDbCache.h b/omnn/storage/LevelDbCache.h index e1bfd42af8..7a5957a898 100644 --- a/omnn/storage/LevelDbCache.h +++ b/omnn/storage/LevelDbCache.h @@ -6,21 +6,25 @@ class DB; struct Options; } -namespace omnn::rt::storage { +namespace omnn::storage { #ifdef OPENMIND_STORAGE_LEVELDB class LevelDbCache : public CacheBase { + using base = CacheBase; + leveldb::DB* _db = nullptr; const std::string name; public: LevelDbCache(const std::string_view& path); + ~LevelDbCache() override; + std::string GetOne(const std::string_view& key) override; bool Set(const std::string_view& key, const std::string_view& v) override; bool Clear(const std::string_view& key) override; - ~LevelDbCache() override; + bool ResetAllDB(const path_str_t& path) override; static const leveldb::Options& GetDbConnectionOptions(); }; diff --git a/omnn/storage/tests/LevelDbStorage.cpp b/omnn/storage/tests/LevelDbStorage.cpp index 5651466773..ee1334c0bf 100644 --- a/omnn/storage/tests/LevelDbStorage.cpp +++ b/omnn/storage/tests/LevelDbStorage.cpp @@ -2,16 +2,15 @@ #include "LevelDbCache.h" #include -using namespace omnn::rt::storage; +using namespace omnn::storage; -#ifdef OPENMIND_STORAGE_LEVELDB +#ifdef OPENMIND_STORAGE_LEVELDB BOOST_AUTO_TEST_CASE(LevelDbStorage_test) { LevelDbCache storage("testLevelDb"); storage.Set("key", "value"); auto got = storage.GetOne("key"); BOOST_TEST(got == "value"); } - #endif // OPENMIND_STORAGE_LEVELDB BOOST_AUTO_TEST_CASE(Empty_test) { diff --git a/omnn/variable/CMakeLists.txt b/omnn/variable/CMakeLists.txt index 9f7b456ee3..f07a82caa2 100644 --- a/omnn/variable/CMakeLists.txt +++ b/omnn/variable/CMakeLists.txt @@ -1,9 +1,6 @@ include(pytect) -if(Python_FOUND - AND OPENMIND_USE_VCPKG # FIXME - AND NOT MSVC # FIXME : remove this line or OPENMIND_BUILD_PYTHON_BINDINGS=ON to try on Visual Studio (Release, VCPKG) -) +if(Python_FOUND) set(DEFAULT_OPENMIND_BUILD_PYTHON_BINDINGS ON) endif() diff --git a/omnn/variable/tests/test_compilambda.py b/omnn/variable/tests/test_compilambda.py new file mode 100644 index 0000000000..7df8d20042 --- /dev/null +++ b/omnn/variable/tests/test_compilambda.py @@ -0,0 +1,70 @@ +import unittest +import sys + +try: + import variable + VARIABLE_MODULE_AVAILABLE = True +except ImportError: + VARIABLE_MODULE_AVAILABLE = False + +@unittest.skipIf(not VARIABLE_MODULE_AVAILABLE, "Python bindings not available") +class TestCompilambda(unittest.TestCase): + def test_compile_into_lambda(self): + x = variable.Variable() + y = variable.Variable() + + expr = x + 2 * y + + lambda_func = expr.compile_into_lambda([x, y]) + + result = lambda_func([3, 4]) + self.assertEqual(float(result), 11.0) # 3 + 2*4 = 11 + + result = lambda_func([5, 2]) + self.assertEqual(float(result), 9.0) # 5 + 2*2 = 9 + + def test_compi_lambda(self): + x = variable.Variable() + y = variable.Variable() + + expr = x * y + x + + lambda_func = expr.compi_lambda([x, y]) + + result = lambda_func([3, 4]) + self.assertEqual(float(result), 15.0) # 3*4 + 3 = 15 + + result = lambda_func([2, 5]) + self.assertEqual(float(result), 12.0) # 2*5 + 2 = 12 + + def test_single_variable_lambda(self): + x = variable.Variable() + + expr = x * x + 1 + + lambda_func = expr.compi_lambda([x]) + + result = lambda_func([3]) + self.assertEqual(float(result), 10.0) # 3*3 + 1 = 10 + + result = lambda_func([4]) + self.assertEqual(float(result), 17.0) # 4*4 + 1 = 17 + + def test_multiple_variables_lambda(self): + x = variable.Variable() + y = variable.Variable() + z = variable.Variable() + w = variable.Variable() + + expr = x + y * z + w + + lambda_func = expr.compi_lambda([x, y, z, w]) + + result = lambda_func([2, 3, 4, 5]) + self.assertEqual(float(result), 19.0) # 2 + 3*4 + 5 = 19 + + result = lambda_func([1, 2, 3, 4]) + self.assertEqual(float(result), 11.0) # 1 + 2*3 + 4 = 11 + +if __name__ == "__main__": + unittest.main() diff --git a/omnn/variable/tests/test_powerflow.py b/omnn/variable/tests/test_powerflow.py new file mode 100644 index 0000000000..220c6353d5 --- /dev/null +++ b/omnn/variable/tests/test_powerflow.py @@ -0,0 +1,44 @@ +import unittest +import sys + +try: + from variable import Variable, Valuable + VARIABLE_MODULE_AVAILABLE = True +except ImportError: + VARIABLE_MODULE_AVAILABLE = False + +@unittest.skipIf(not VARIABLE_MODULE_AVAILABLE, "Python bindings not available") +class TestPowerFlow(unittest.TestCase): + def test_powerflow_calculations(self): + V1 = Variable() + V2 = Variable() + V3 = Variable() + + y12 = Valuable(0.1) + y13 = Valuable(0.2) + y23 = Valuable(0.15) + + Y11 = y12 + y13 + Y22 = y12 + y23 + Y33 = y13 + y23 + + Y12 = -y12 + Y13 = -y13 + Y23 = -y23 + Y21 = -y12 # Y21 = Y12 by symmetry + + self.assertEqual(Y12, Y21) + + V1_val = Valuable(1.0) + V2_val = Valuable(0.95) + V3_val = Valuable(1.05) + + I1 = V1_val * Y11 + Y12 * V2_val + Y13 * V3_val + + S1 = V1_val * I1 + + expected = V1_val * (V1_val * Y11 + Y12 * V2_val + Y13 * V3_val) + self.assertEqual(S1, expected) + +if __name__ == "__main__": + unittest.main() diff --git a/omnn/variable/tests/test_system.py b/omnn/variable/tests/test_system.py index 858f8b287a..33a0625a07 100644 --- a/omnn/variable/tests/test_system.py +++ b/omnn/variable/tests/test_system.py @@ -1,7 +1,14 @@ #!/usr/bin/env python3 import unittest -import variable # Import the variable module +import sys +try: + import variable # Import the variable module + VARIABLE_MODULE_AVAILABLE = True +except ImportError: + VARIABLE_MODULE_AVAILABLE = False + +@unittest.skipIf(not VARIABLE_MODULE_AVAILABLE, "Python bindings not available") class TestSystem(unittest.TestCase): def test_system_creation(self): # Create a simple system diff --git a/omnn/variable/tests/test_valuable.py b/omnn/variable/tests/test_valuable.py index 9ae9cd9da1..05eaa0eb4e 100644 --- a/omnn/variable/tests/test_valuable.py +++ b/omnn/variable/tests/test_valuable.py @@ -1,7 +1,14 @@ #!/usr/bin/env python3 import unittest -import variable +import sys +try: + import variable + VARIABLE_MODULE_AVAILABLE = True +except ImportError: + VARIABLE_MODULE_AVAILABLE = False + +@unittest.skipIf(not VARIABLE_MODULE_AVAILABLE, "Python bindings not available") class Testvariable(unittest.TestCase): def test_variable_creation(self): x = variable.Variable() diff --git a/omnn/variable/valuable.cpp b/omnn/variable/valuable.cpp index c4cfd722bf..5512ec1954 100644 --- a/omnn/variable/valuable.cpp +++ b/omnn/variable/valuable.cpp @@ -1,16 +1,21 @@ #include +#ifdef OPENMIND_BUILD_PYTHON_BINDINGS #include #include +#endif #include "omnn/math/Variable.h" #include "omnn/math/System.h" #include #include +#ifdef OPENMIND_BUILD_PYTHON_BINDINGS using namespace boost::python; +#endif using namespace omnn::math; using namespace std::string_literals; namespace { +#ifdef OPENMIND_BUILD_PYTHON_BINDINGS // Converter for solutions_t (std::unordered_set) boost::python::list solutions_to_list(const omnn::math::Valuable::solutions_t& solutions) { boost::python::list result; @@ -51,8 +56,10 @@ namespace { data->convertible = storage; } }; +#endif } +#ifdef OPENMIND_BUILD_PYTHON_BINDINGS BOOST_PYTHON_MODULE(variable) { dict_to_map_converter(); // Register the converter @@ -134,6 +141,97 @@ BOOST_PYTHON_MODULE(variable) // String conversion .def("__str__", &Valuable::str) + + .def("compile_into_lambda", +[](const Valuable& v, const boost::python::list& variables) { + std::vector vars; + for (int i = 0; i < len(variables); ++i) { + vars.push_back(&extract(variables[i])); + } + + return boost::python::make_function( + [v, vars](const boost::python::list& args) -> Valuable { + if (len(args) != vars.size()) { + throw std::runtime_error("Number of arguments must match number of variables"); + } + + std::vector values; + for (int i = 0; i < len(args); ++i) { + values.push_back(extract(args[i])); + } + + auto lambda = v.CompileIntoLambda({vars.begin(), vars.end()}); + return lambda({values.begin(), values.end()}); + } + ); + }, + "Create a lambda function from an expression using CompileIntoLambda.\n\n" + "Args:\n" + " variables: List of Variable objects used in the expression\n\n" + "Returns:\n" + " A callable function that takes a list of values corresponding to the variables\n\n" + "Raises:\n" + " RuntimeError: If the number of arguments doesn't match the number of variables\n\n" + "Example:\n" + " expr = x + 2 * y\n" + " lambda_func = expr.compile_into_lambda([x, y])\n" + " result = lambda_func([3, 4]) # 3 + 2*4 = 11") + + .def("compi_lambda", +[](const Valuable& v, const boost::python::list& variables) { + std::vector vars; + for (int i = 0; i < len(variables); ++i) { + vars.push_back(extract(variables[i])); + } + + return boost::python::make_function( + [v, vars](const boost::python::list& args) -> Valuable { + if (len(args) != vars.size()) { + throw std::runtime_error("Number of arguments must match number of variables"); + } + + std::vector values; + for (int i = 0; i < len(args); ++i) { + values.push_back(extract(args[i])); + } + + auto callCompiLambda = [&v](auto&&... vars) { + return v.CompiLambda(std::forward(vars)...); + }; + + auto callLambda = [](auto&& lambda, auto&&... args) { + return lambda(std::forward(args)...); + }; + + if (vars.size() > 10) { + throw std::runtime_error("Currently only supports up to 10 variables due to implementation constraints"); + } + + auto invokeLambda = [&]() -> Valuable { + return [&](std::index_sequence) { + auto lambda = callCompiLambda(vars[I]...); + + return callLambda(lambda, values[I]...); + }(std::make_index_sequence{}); + }; + + return invokeLambda(); + } + ); + }, + "Create an optimized lambda function from an expression using CompiLambda.\n\n" + "Args:\n" + " variables: List of Variable objects used in the expression (max 3 variables)\n\n" + "Returns:\n" + " A callable function that takes a list of values corresponding to the variables\n\n" + "Raises:\n" + " RuntimeError: If more than 3 variables are provided (C++ template limitation)\n" + " RuntimeError: If the number of arguments doesn't match the number of variables\n\n" + "Note:\n" + " This method currently supports up to 3 variables due to C++ template limitations.\n" + " For expressions with more variables, use compile_into_lambda() instead.\n\n" + "Example:\n" + " expr = x * y + x\n" + " lambda_func = expr.compi_lambda([x, y])\n" + " result = lambda_func([3, 4]) # 3*4 + 3 = 15") ; class_>("Variable") @@ -219,3 +317,4 @@ BOOST_PYTHON_MODULE(variable) }, return_internal_reference<>()) ; } +#endif // OPENMIND_BUILD_PYTHON_BINDINGS diff --git a/utils/git/git-rebase.cpp b/utils/git/git-rebase.cpp index 18ed8324c4..18982c6b6d 100644 --- a/utils/git/git-rebase.cpp +++ b/utils/git/git-rebase.cpp @@ -65,7 +65,10 @@ bool rebase(std::string_view branch, std::string_view onto) { } built = resolved && cmake::build(); } else { - std::cerr << "Build failed after resolving conflict" << std::endl; + if(resolved && !built) { + std::cerr << "Build failed after resolving conflict" << std::endl; + } + break; } } else { break; diff --git a/vcpkg.json b/vcpkg.json index 2528053e7c..e2a27332e2 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -14,6 +14,7 @@ "boost-locale", "boost-multiprecision", "boost-python", + "boost-redis", "boost-serialization", "boost-system", "boost-test",