├── images ├── txeo.png └── logo_txeo.png ├── mkdocs ├── docs │ ├── assets │ │ ├── logo.png │ │ └── txeo.png │ ├── img │ │ └── favicon.ico │ ├── changelog.md │ ├── api-reference │ │ ├── logger-console.md │ │ ├── logger-file.md │ │ ├── logger.md │ │ ├── ols_gd_trainer.md │ │ ├── tensor-func.md │ │ ├── trainer.md │ │ ├── tensor-part.md │ │ ├── predictor.md │ │ ├── data-table.md │ │ ├── loss.md │ │ ├── data-table-norm.md │ │ ├── tensor-op.md │ │ ├── vector.md │ │ ├── tensor-shape.md │ │ ├── matrix.md │ │ ├── matrix-io.md │ │ └── tensor-agg.md │ ├── usage.md │ ├── index.md │ └── getting-started.md └── mkdocs.yml ├── tests ├── test_data │ ├── model_regression │ │ ├── fingerprint.pb │ │ ├── saved_model.pb │ │ ├── keras_metadata.pb │ │ └── variables │ │ │ ├── variables.index │ │ │ └── variables.data-00000-of-00001 │ └── files │ │ └── insurance.csv ├── txeo_tests.cpp ├── CMakeLists.txt ├── tLoggerConsole.cpp ├── tDataTable.cpp ├── tUtils.cpp ├── tTensorShape.cpp ├── tDataTableNorm.cpp ├── tMatrixIO.cpp ├── tLoggerFile.cpp ├── tLoss.cpp └── tPredictor.cpp ├── .clang-format ├── examples ├── txeo_example.cpp ├── CMakeLists.txt ├── txeo_olsGD.cpp ├── txeo_shapes.cpp ├── txeo_tensorio.cpp └── txeo_tensors.cpp ├── include └── txeo │ ├── detail │ ├── TensorPrivate.h │ ├── TensorShapePrivate.h │ ├── pch.h │ ├── PredictorPrivate.h │ └── utils.h │ ├── types.h │ ├── LoggerConsole.h │ ├── TensorIO.h │ ├── TensorIterator.h │ ├── LoggerFile.h │ ├── Logger.h │ ├── Trainer.h │ ├── Loss.h │ └── OlsGDTrainer.h ├── .gitignore ├── src ├── LoggerConsole.cpp ├── Logger.cpp ├── LoggerFile.cpp ├── Trainer.cpp ├── DataTableNorm.cpp ├── CMakeLists.txt ├── utils.cpp ├── Loss.cpp ├── TensorIO.cpp └── OlsGDTrainer.cpp ├── .github └── workflows │ └── ci.yml ├── LICENSE ├── .clangd ├── cmake └── FindTensorFlow.cmake ├── CMakeLists.txt └── CMakePresets.json /images/txeo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/images/txeo.png -------------------------------------------------------------------------------- /images/logo_txeo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/images/logo_txeo.png -------------------------------------------------------------------------------- /mkdocs/docs/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/mkdocs/docs/assets/logo.png -------------------------------------------------------------------------------- /mkdocs/docs/assets/txeo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/mkdocs/docs/assets/txeo.png -------------------------------------------------------------------------------- /mkdocs/docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/mkdocs/docs/img/favicon.ico -------------------------------------------------------------------------------- /tests/test_data/model_regression/fingerprint.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/tests/test_data/model_regression/fingerprint.pb -------------------------------------------------------------------------------- /tests/test_data/model_regression/saved_model.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/tests/test_data/model_regression/saved_model.pb -------------------------------------------------------------------------------- /tests/test_data/model_regression/keras_metadata.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/tests/test_data/model_regression/keras_metadata.pb -------------------------------------------------------------------------------- /tests/test_data/model_regression/variables/variables.index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/tests/test_data/model_regression/variables/variables.index -------------------------------------------------------------------------------- /tests/txeo_tests.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | int main(int argc, char **argv) { 4 | ::testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/test_data/model_regression/variables/variables.data-00000-of-00001: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdabra/txeo/HEAD/tests/test_data/model_regression/variables/variables.data-00000-of-00001 -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | { 2 | BasedOnStyle: LLVM, 3 | IndentAccessModifiers: true, 4 | IndentWidth: 2, 5 | ColumnLimit: 100, 6 | AllowShortFunctionsOnASingleLine: InlineOnly, 7 | AlwaysBreakTemplateDeclarations: Yes, 8 | } 9 | -------------------------------------------------------------------------------- /examples/txeo_example.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | 11 | std::ofstream x; 12 | 13 | std::cout << std::boolalpha << x.is_open() << std::endl; 14 | } 15 | -------------------------------------------------------------------------------- /tests/test_data/files/insurance.csv: -------------------------------------------------------------------------------- 1 | age,sex,bmi,children,smoker,region,charges 2 | 19,female,27.9,0,yes,southwest,16884.924 3 | 18,male,33.77,1,no,southeast,1725.5523 4 | 28,male,33.0,3,no,southeast,4449.462 5 | 33,male,22.705,0,no,northwest,21984.47061 6 | 32,male,28.88,0,no,northwest,3866.8552 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /include/txeo/detail/TensorPrivate.h: -------------------------------------------------------------------------------- 1 | #ifndef TENSOR_PRIVATE_H 2 | #define TENSOR_PRIVATE_H 3 | #pragma once 4 | 5 | #include 6 | 7 | #include "txeo/Tensor.h" 8 | #include "txeo/TensorShape.h" 9 | 10 | template 11 | struct txeo::Tensor::Impl { 12 | std::unique_ptr tf_tensor{nullptr}; 13 | txeo::TensorShape txeo_shape{}; 14 | }; 15 | 16 | #endif -------------------------------------------------------------------------------- /include/txeo/detail/TensorShapePrivate.h: -------------------------------------------------------------------------------- 1 | #ifndef TENSOR_SHAPE_PRIVATE_H 2 | #define TENSOR_SHAPE_PRIVATE_H 3 | #pragma once 4 | 5 | #include "txeo/TensorShape.h" 6 | #include 7 | 8 | struct txeo::TensorShape::Impl { 9 | std::unique_ptr tf_shape{nullptr}; 10 | const tensorflow::TensorShape *ext_tf_shape{nullptr}; 11 | std::vector stride; 12 | }; 13 | 14 | #endif -------------------------------------------------------------------------------- /include/txeo/detail/pch.h: -------------------------------------------------------------------------------- 1 | #ifndef PCH_H 2 | #define PCH_H 3 | #pragma once 4 | 5 | // Standard library 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // Project headers 15 | #include "txeo/Matrix.h" 16 | #include "txeo/Tensor.h" 17 | #include "txeo/TensorShape.h" 18 | #include "txeo/detail/utils.h" 19 | #include "txeo/types.h" 20 | 21 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Directories 35 | .out 36 | .vscode 37 | .xmake 38 | .my-xmake 39 | .idea 40 | build 41 | /docs 42 | 43 | # Files 44 | CMakeUserPresets.json 45 | tensor.txt 46 | -------------------------------------------------------------------------------- /src/LoggerConsole.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/LoggerConsole.h" 2 | #include "txeo/Logger.h" 3 | #include "txeo/detail/utils.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace txeo { 9 | 10 | LoggerConsole &txeo::LoggerConsole::instance() { 11 | static LoggerConsole logger; 12 | return logger; 13 | } 14 | 15 | void LoggerConsole::write(txeo::LogLevel level, const std::string &message) { 16 | std::lock_guard ld{_mutex}; 17 | std::cout << "[" << txeo::detail::current_time() << "] - " << txeo::Logger::log_level_str(level) 18 | << ": " << message << std::endl; 19 | } 20 | 21 | } // namespace txeo -------------------------------------------------------------------------------- /include/txeo/detail/PredictorPrivate.h: -------------------------------------------------------------------------------- 1 | #ifndef PREDICTOR_PRIVATE_H 2 | #define PREDICTOR_PRIVATE_H 3 | #pragma once 4 | 5 | #include "txeo/Predictor.h" 6 | 7 | #include 8 | #include 9 | 10 | template 11 | struct txeo::Predictor::Impl { 12 | tensorflow::SavedModelBundle model; 13 | tensorflow::SessionOptions session_options; 14 | tensorflow::RunOptions run_options; 15 | 16 | Predictor::TensorInfo in_name_shape_map; 17 | Predictor::TensorInfo out_name_shape_map; 18 | std::filesystem::path model_path{""}; 19 | }; 20 | 21 | #endif -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Deploy MkDocs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main # or your default branch name 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | deploy: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up Python 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: '3.x' 23 | 24 | - name: Install MkDocs dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install mkdocs mkdocs-material pymdown-extensions 28 | 29 | - name: Deploy to GitHub Pages 30 | working-directory: mkdocs 31 | run: mkdocs gh-deploy --force -------------------------------------------------------------------------------- /include/txeo/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace txeo { 9 | 10 | /** 11 | * @brief Bundle of device information 12 | * 13 | */ 14 | struct DeviceInfo { 15 | /** 16 | * @brief Device name 17 | * 18 | */ 19 | std::string name{}; 20 | 21 | /** 22 | * @brief Device type (CPU or GPU) 23 | * 24 | */ 25 | std::string device_type{}; 26 | 27 | /** 28 | * @brief Memory limit in bytes 29 | * 30 | */ 31 | size_t memory_limit{}; 32 | }; 33 | 34 | /** 35 | * @brief Normalization types to be used in normalization functions 36 | * 37 | */ 38 | enum class NormalizationType { MIN_MAX, Z_SCORE }; 39 | 40 | /** 41 | * @brief Types of loss functions 42 | * 43 | */ 44 | enum class LossFunc { MSE, MAE, MSLE, LCHE }; 45 | 46 | } // namespace txeo 47 | 48 | #endif -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | #################################################### Test Executable #################################################### 3 | 4 | find_package(GTest REQUIRED) 5 | 6 | add_executable( 7 | txeo_tests 8 | txeo_tests.cpp 9 | tUtils.cpp 10 | tTensorShape.cpp 11 | tTensor.cpp 12 | tMatrixIO.cpp 13 | tPredictor.cpp 14 | tTensorOp.cpp 15 | tTensorAgg.cpp 16 | tTensorPart.cpp 17 | tTensorFunc.cpp 18 | tMatrix.cpp 19 | tVector.cpp 20 | tLoss.cpp 21 | tOlsGDTrainer.cpp 22 | tDataTable.cpp 23 | tDataTableNorm.cpp 24 | tLoggerConsole.cpp 25 | tLoggerFile.cpp 26 | ) 27 | 28 | target_precompile_headers(txeo_tests PRIVATE 29 | "$<$:${CMAKE_SOURCE_DIR}/include/txeo/detail/pch.h>" 30 | ) 31 | 32 | target_link_libraries( 33 | txeo_tests 34 | GTest::gtest GTest::gtest_main txeo_shared 35 | ) 36 | 37 | 38 | include(GoogleTest) 39 | gtest_discover_tests(txeo_tests) 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # Txeo - TensorFlow C++ Wrapper 2 | 3 | Copyright (C) 2025 Roberto Dias Algarte 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | This project includes third-party components: 18 | 19 | - TensorFlow C++ API (Apache 2.0): 20 | - Protobuf (BSD 3-Clause): 21 | 22 | The original TensorFlow license is available in `third_party/tensorflow/LICENSE`. 23 | -------------------------------------------------------------------------------- /mkdocs/docs/changelog.md: -------------------------------------------------------------------------------- 1 | 2 | # Changelog 3 | 4 | ## 🚀 Txeo v1.1.0 - Tensor operations, math functions, Matrix and Vector 5 | 6 | Now, Txeo has the following new features: 7 | 8 | - **Matrix Multiplication (`product`)** - Perform tensor dot products. 9 | - **Broadcasting Support** - Support element-wise operations on different shapes. 10 | - **Reduction Operations (`sum`, `mean`, `max`)** - Compute statistics on tensors. 11 | - **Matrix and Vector** - Specific entities for second and first order tensors. 12 | 13 | --- 14 | 15 | ## 🚀 Txeo v1.0.0 - Initial Stable Release 16 | 17 | Txeo is now officially production-ready with the following features: 18 | 19 | - **Intuitive API** for TensorFlow C++ usage. 20 | - **High-Level Tensor Abstraction** with flexible Tensor IO. 21 | - **Near-Native Performance** - Only 0.6-1.2% overhead compared to native TensorFlow. 22 | - **XLA Acceleration Support** for advanced optimizations. 23 | - **Consistent Performance Across Compilers** - Intel, GCC, and Clang. -------------------------------------------------------------------------------- /src/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/Logger.h" 2 | 3 | namespace txeo { 4 | 5 | void Logger::log(txeo::LogLevel level, const std::string &message) { 6 | if (_is_turned_on && static_cast(level) >= static_cast(_output_level)) 7 | this->write(level, message); 8 | } 9 | 10 | void Logger::debug(const std::string &message) { 11 | this->log(txeo::LogLevel::DEBUG, message); 12 | } 13 | 14 | void Logger::info(const std::string &message) { 15 | this->log(txeo::LogLevel::INFO, message); 16 | } 17 | 18 | void Logger::warning(const std::string &message) { 19 | this->log(txeo::LogLevel::WARNING, message); 20 | } 21 | 22 | void Logger::error(const std::string &message) { 23 | this->log(txeo::LogLevel::ERROR, message); 24 | } 25 | 26 | std::string Logger::log_level_str(txeo::LogLevel level) { 27 | switch (level) { 28 | case txeo::LogLevel::DEBUG: 29 | return "[~] DEBUG"; 30 | case txeo::LogLevel::INFO: 31 | return "[✓] INFO"; 32 | case txeo::LogLevel::WARNING: 33 | return "[!] WARNING"; 34 | case txeo::LogLevel::ERROR: 35 | return "[x] ERROR"; 36 | } 37 | } 38 | 39 | } // namespace txeo -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(txeo_example txeo_example.cpp) 2 | add_executable(txeo_shapes txeo_shapes.cpp) 3 | add_executable(txeo_tensors txeo_tensors.cpp) 4 | add_executable(txeo_tensorio txeo_tensorio.cpp) 5 | add_executable(txeo_olsGD txeo_olsGD.cpp) 6 | 7 | target_precompile_headers(txeo_example PRIVATE 8 | "$<$:${CMAKE_SOURCE_DIR}/include/txeo/detail/pch.h>" 9 | ) 10 | target_precompile_headers(txeo_shapes PRIVATE 11 | "$<$:${CMAKE_SOURCE_DIR}/include/txeo/detail/pch.h>" 12 | ) 13 | target_precompile_headers(txeo_tensors PRIVATE 14 | "$<$:${CMAKE_SOURCE_DIR}/include/txeo/detail/pch.h>" 15 | ) 16 | target_precompile_headers(txeo_tensorio PRIVATE 17 | "$<$:${CMAKE_SOURCE_DIR}/include/txeo/detail/pch.h>" 18 | ) 19 | target_precompile_headers(txeo_olsGD PRIVATE 20 | "$<$:${CMAKE_SOURCE_DIR}/include/txeo/detail/pch.h>" 21 | ) 22 | 23 | target_link_libraries(txeo_example txeo_shared) 24 | target_link_libraries(txeo_shapes txeo_shared) 25 | target_link_libraries(txeo_tensors txeo_shared) 26 | target_link_libraries(txeo_tensorio txeo_shared) 27 | target_link_libraries(txeo_olsGD txeo_shared) 28 | -------------------------------------------------------------------------------- /src/LoggerFile.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/LoggerFile.h" 2 | #include 3 | 4 | namespace txeo { 5 | 6 | LoggerFile &txeo::LoggerFile::instance() { 7 | static LoggerFile logger{}; 8 | return logger; 9 | } 10 | 11 | LoggerFile::~LoggerFile() { 12 | if (_wf.is_open()) 13 | _wf.close(); 14 | } 15 | 16 | bool LoggerFile::open_file(const std::filesystem::path &file_path) { 17 | std::lock_guard lg{_mutex}; 18 | 19 | if (!this->_is_turned_on) 20 | return false; 21 | 22 | if (_wf.is_open()) 23 | return true; 24 | 25 | _wf = std::ofstream{file_path}; 26 | if (!_wf.is_open()) 27 | throw txeo::LoggerFileError("Log file could not be opened"); 28 | 29 | return _wf.is_open(); 30 | } 31 | 32 | void LoggerFile::close_file() { 33 | std::lock_guard lg{_mutex}; 34 | if (_wf.is_open()) 35 | _wf.close(); 36 | } 37 | 38 | void LoggerFile::write(txeo::LogLevel level, const std::string &message) { 39 | std::lock_guard lg{_mutex}; 40 | if (!this->_is_turned_on) 41 | return; 42 | 43 | if (!_wf.is_open()) 44 | throw txeo::LoggerFileError("Log file not opened"); 45 | 46 | _wf << "[" << txeo::detail::current_time() << "] - " << txeo::Logger::log_level_str(level) << ": " 47 | << message << std::endl; 48 | } 49 | 50 | } // namespace txeo -------------------------------------------------------------------------------- /examples/txeo_olsGD.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/MatrixIO.h" 2 | #include "txeo/OlsGDTrainer.h" 3 | #include "txeo/Tensor.h" 4 | #include "txeo/TensorAgg.h" 5 | #include "txeo/TensorPart.h" 6 | 7 | #include 8 | 9 | int main() { 10 | // ====================================================================================== 11 | // 1. Basic Training 12 | // ====================================================================================== 13 | 14 | // Data downloaded at 15 | // https://media.geeksforgeeks.org/wp-content/uploads/20240319120216/housing.csv 16 | auto train_data = 17 | txeo::MatrixIO::one_hot_encode_text_file("housing.csv", ',', true, "housing_one_hot.csv"); 18 | 19 | auto x_train = txeo::TensorPart::sub_matrix_cols_exclude( 20 | train_data.read_text_file(true), {8}); 21 | auto y_train = 22 | txeo::TensorPart::sub_matrix_cols(train_data.read_text_file(true), {8}); 23 | 24 | x_train.normalize_columns(txeo::NormalizationType::MIN_MAX); 25 | 26 | std::cout << "X: " << x_train.shape() << std::endl; 27 | std::cout << "Y: " << y_train.shape() << std::endl; 28 | 29 | txeo::OlsGDTrainer ols{x_train, y_train}; 30 | 31 | ols.enable_variable_lr(); 32 | ols.fit(100, txeo::LossFunc::MAE); 33 | 34 | std::cout << "Weight-Bias: " << ols.weight_bias() << std::endl; 35 | std::cout << "Minimum loss: " << ols.min_loss() << std::endl; 36 | std::cout << "min Y:" << txeo::TensorAgg::reduce_min(y_train, {0})() << std::endl; 37 | 38 | return 0; 39 | } -------------------------------------------------------------------------------- /src/Trainer.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/Trainer.h" 2 | #include "txeo/Loss.h" 3 | 4 | namespace txeo { 5 | enum class LossFunc; 6 | 7 | template 8 | void Trainer::fit(size_t epochs, LossFunc metric) { 9 | this->train(epochs, metric); 10 | _is_trained = true; 11 | }; 12 | 13 | template 14 | void Trainer::fit(size_t epochs, LossFunc metric, size_t patience) { 15 | _is_early_stop = true; 16 | _patience = patience; 17 | this->fit(epochs, metric); 18 | _is_early_stop = false; 19 | } 20 | 21 | template 22 | void Trainer::fit(size_t epochs, LossFunc metric, size_t patience, NormalizationType type) { 23 | this->enable_feature_norm(type); 24 | this->fit(epochs, metric, patience); 25 | } 26 | 27 | template 28 | T Trainer::compute_test_loss(LossFunc metric) const { 29 | if (!this->_is_trained) 30 | throw TrainerError("Trainer is not trained."); 31 | 32 | auto *x_test = this->_data_table->x_test(); 33 | auto *y_test = this->_data_table->y_test(); 34 | 35 | if (x_test == nullptr) 36 | throw TrainerError("Test data was not specified."); 37 | 38 | Loss loss{*y_test, metric}; 39 | 40 | return loss.get_loss(this->predict(*x_test)); 41 | } 42 | 43 | template 44 | void Trainer::enable_feature_norm(NormalizationType type) { 45 | _data_table_norm = DataTableNorm{*_data_table, type}; 46 | _is_norm_enabled = true; 47 | _is_trained = false; 48 | } 49 | 50 | template class Trainer; 51 | template class Trainer; 52 | template class Trainer; 53 | template class Trainer; 54 | template class Trainer; 55 | template class Trainer; 56 | template class Trainer; 57 | template class Trainer; 58 | 59 | } // namespace txeo -------------------------------------------------------------------------------- /include/txeo/LoggerConsole.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGERCONSOLE_H 2 | #define LOGGERCONSOLE_H 3 | #pragma once 4 | 5 | #include "txeo/Logger.h" 6 | 7 | #include 8 | 9 | namespace txeo { 10 | 11 | /** 12 | * @class LoggerConsole 13 | * @brief Thread-safe singleton logger for console output 14 | * 15 | * Provides colored console logging with timestamp and level information. 16 | * Inherits from txeo::Logger and implements thread-safe output operations. 17 | * 18 | * @note Automatically enabled on instantiation 19 | * @note Thread-safe through internal mutex locking 20 | * 21 | * **Example Usage:** 22 | * @code 23 | * // Get singleton instance 24 | * auto& console_logger = LoggerConsole::instance(); 25 | * 26 | * // Configure logging 27 | * console_logger.set_output_level(LogLevel::INFO); 28 | * 29 | * // Log messages 30 | * console_logger.debug("Debug data"); // Won't print with INFO level 31 | * console_logger.warning("Low memory!"); // Will print with warning color 32 | * @endcode 33 | */ 34 | class LoggerConsole : public txeo::Logger { 35 | public: 36 | LoggerConsole(const LoggerConsole &) = delete; 37 | LoggerConsole &operator=(const LoggerConsole &) = delete; 38 | LoggerConsole(LoggerConsole &&) noexcept = delete; 39 | LoggerConsole &operator=(LoggerConsole &&) noexcept = delete; 40 | ~LoggerConsole() = default; 41 | 42 | /** 43 | * @brief Access the singleton instance 44 | * @return Reference to the global LoggerConsole instance 45 | * 46 | * **Example Usage:** 47 | * @code 48 | * // Typical usage pattern 49 | * LoggerConsole::instance().info("System initialized"); 50 | * @endcode 51 | */ 52 | static LoggerConsole &instance(); 53 | 54 | private: 55 | LoggerConsole() = default; 56 | void write(txeo::LogLevel level, const std::string &message) override; 57 | std::mutex _mutex; 58 | }; 59 | } // namespace txeo 60 | #endif -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | CompileFlags: 2 | Add: [-I/opt/clang/lib/clang/20/include/] # Do not specify pch flags for clangd, just include the missed headers 3 | 4 | Diagnostics: 5 | ClangTidy: 6 | Add: 7 | [ 8 | modernize*, 9 | clang-diagnostic-*, 10 | clang-analyzer-*, 11 | cppcoreguidelines-*, 12 | modernize-*, 13 | ] 14 | Remove: 15 | [ 16 | cppcoreguidelines-pro-type-vararg, 17 | modernize-use-trailing-return-type, 18 | cppcoreguidelines-avoid-magic-numbers, 19 | cppcoreguidelines-non-private-member-variables-in-classes, 20 | cppcoreguidelines-avoid-c-arrays, 21 | modernize-avoid-c-arrays, 22 | cppcoreguidelines-pro-bounds-pointer-arithmetic, 23 | cppcoreguidelines-owning-memory, 24 | ] 25 | FastCheckFilter: None 26 | CheckOptions: 27 | FormatStyle: LLVM, 28 | cert-dcl16-c.NewSuffixes: "L;LL;LU;LLU" 29 | cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField: "0" 30 | cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors: "1" 31 | cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: "1" 32 | google-readability-braces-around-statements.ShortStatementLines: "1" 33 | google-readability-function-size.StatementThreshold: "800" 34 | google-readability-namespace-comments.ShortNamespaceLines: "10" 35 | google-readability-namespace-comments.SpacesBeforeComments: "2" 36 | modernize-loop-convert.MaxCopySize: "16" 37 | modernize-loop-convert.MinConfidence: reasonable 38 | modernize-loop-convert.NamingStyle: CamelCase 39 | modernize-pass-by-value.IncludeStyle: llvm 40 | modernize-replace-auto-ptr.IncludeStyle: llvm 41 | modernize-use-nullptr.NullMacros: "NULL" 42 | 43 | InlayHints: # Turning off parameter hints (boring) 44 | Designators: true 45 | Enabled: true 46 | ParameterNames: false 47 | DeducedTypes: true 48 | -------------------------------------------------------------------------------- /src/DataTableNorm.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/DataTableNorm.h" 2 | #include "txeo/TensorFunc.h" 3 | 4 | namespace txeo { 5 | 6 | template 7 | DataTableNorm::DataTableNorm(const txeo::DataTable &data, txeo::NormalizationType type) 8 | : _type{type}, _data_table(&data), 9 | _funcs(txeo::TensorFunc::make_normalize_functions(data.x_train(), 0, _type)) { 10 | } 11 | 12 | template 13 | void DataTableNorm::set_data_table(const txeo::DataTable &data) { 14 | _data_table = &data; 15 | _funcs = txeo::TensorFunc::make_normalize_functions(data.x_train(), 0, _type); 16 | } 17 | 18 | template 19 | txeo::Matrix DataTableNorm::normalize(txeo::Matrix &&x) const { 20 | if (x.col_size() != _funcs.size()) 21 | throw txeo::DataTableNormError("Inconsistent feature matrix."); 22 | 23 | txeo::Matrix resp{std::move(x)}; 24 | 25 | for (size_t j{0}; j < resp.col_size(); ++j) 26 | for (size_t i{0}; i < resp.row_size(); ++i) 27 | resp(i, j) = _funcs[j](resp(i, j)); 28 | 29 | return resp; 30 | } 31 | 32 | template 33 | txeo::Matrix DataTableNorm::x_train_normalized() { 34 | return this->normalize(_data_table->x_train()); 35 | } 36 | 37 | template 38 | txeo::Matrix DataTableNorm::x_eval_normalized() { 39 | if (!_data_table->has_eval()) 40 | throw txeo::DataTableNormError("No evaluation data was defined."); 41 | 42 | return this->normalize(*_data_table->x_eval()); 43 | } 44 | 45 | template 46 | txeo::Matrix DataTableNorm::x_test_normalized() { 47 | if (!_data_table->has_test()) 48 | throw txeo::DataTableNormError("No test data was defined."); 49 | 50 | return this->normalize(*_data_table->x_test()); 51 | } 52 | 53 | template class DataTableNorm; 54 | template class DataTableNorm; 55 | template class DataTableNorm; 56 | template class DataTableNorm; 57 | template class DataTableNorm; 58 | template class DataTableNorm; 59 | template class DataTableNorm; 60 | template class DataTableNorm; 61 | 62 | } // namespace txeo -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(TXEO_SOURCES 3 | utils.cpp 4 | TensorShape.cpp 5 | Tensor.cpp 6 | Matrix.cpp 7 | Vector.cpp 8 | TensorOp.cpp 9 | TensorAgg.cpp 10 | TensorIO.cpp 11 | MatrixIO.cpp 12 | TensorPart.cpp 13 | TensorFunc.cpp 14 | Predictor.cpp 15 | Trainer.cpp 16 | OlsGDTrainer.cpp 17 | Loss.cpp 18 | DataTable.cpp 19 | DataTableNorm.cpp 20 | Logger.cpp 21 | LoggerConsole.cpp 22 | LoggerFile.cpp) 23 | 24 | 25 | #################################################### Finding Tensorflow #################################################### 26 | 27 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 28 | find_package(TensorFlow REQUIRED COMPONENTS CXX SHARED) 29 | 30 | 31 | #################################################### Static Library #################################################### 32 | 33 | add_library(txeo_static STATIC ${TXEO_SOURCES}) 34 | target_precompile_headers(txeo_static PRIVATE 35 | "$<$:${CMAKE_SOURCE_DIR}/include/txeo/detail/pch.h>" 36 | ) 37 | target_include_directories(txeo_static PUBLIC 38 | $ 39 | $ 40 | ) 41 | target_link_libraries(txeo_static PUBLIC TensorFlow::TensorFlow) 42 | set_target_properties(txeo_static PROPERTIES OUTPUT_NAME "txeo") 43 | 44 | 45 | #################################################### Dynamic Library #################################################### 46 | set(CMAKE_BUILD_WITH_INSTALL_RPATH OFF) 47 | 48 | #Avoiding incompatibility issues between Ninja and Intel compiler 49 | if(CMAKE_GENERATOR STREQUAL "Ninja" AND $ENV{CXX} STREQUAL "icpx") 50 | set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) 51 | set(CMAKE_SKIP_RPATH FALSE) 52 | endif() 53 | 54 | add_library(txeo_shared SHARED ${TXEO_SOURCES}) 55 | target_precompile_headers(txeo_shared PRIVATE 56 | "$<$:${CMAKE_SOURCE_DIR}/include/txeo/detail/pch.h>" 57 | ) 58 | target_compile_definitions(txeo_shared PUBLIC TXEO_SHARED) 59 | target_include_directories(txeo_shared PUBLIC 60 | $ 61 | $ 62 | ) 63 | target_link_libraries(txeo_shared PUBLIC TensorFlow::TensorFlow) 64 | set_target_properties(txeo_shared PROPERTIES OUTPUT_NAME "txeo") 65 | 66 | -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/logger-console.md: -------------------------------------------------------------------------------- 1 | # LoggerConsole 2 | 3 | Thread-safe singleton logger for console output with colored messages and timestamp formatting. 4 | 5 | --- 6 | 7 | ## Overview 8 | 9 | The `LoggerConsole` class is a concrete implementation of the `txeo::Logger` interface that writes log messages to the terminal. It formats messages with timestamps, log levels, and optional color codes, and ensures thread safety using an internal mutex. 10 | 11 | This logger is implemented as a singleton, meaning only one instance exists throughout the program. It is ideal for simple real-time diagnostics, debugging, or CLI tools. 12 | 13 | --- 14 | 15 | ## Features 16 | 17 | * ✅ Thread-safe via `std::mutex` 18 | * ✅ Singleton access pattern (`LoggerConsole::instance()`) 19 | * ✅ Colored log levels (if enabled in your implementation) 20 | * ✅ Timestamped output 21 | * ✅ Level-based filtering (via `set_output_level()`) 22 | 23 | --- 24 | 25 | ## Header 26 | 27 | ```cpp 28 | #include "txeo/LoggerConsole.h" 29 | ``` 30 | 31 | --- 32 | 33 | ## Usage Example 34 | 35 | ```cpp 36 | #include "txeo/LoggerConsole.h" 37 | 38 | int main() { 39 | auto &logger = txeo::LoggerConsole::instance(); 40 | 41 | logger.set_output_level(txeo::LogLevel::INFO); 42 | 43 | logger.debug("Debug message"); // Will not be shown if level is INFO 44 | logger.info("Info message"); // ✅ Visible 45 | logger.warning("Warning!"); // ✅ Visible 46 | logger.error("Fatal error!"); // ✅ Visible 47 | } 48 | ``` 49 | 50 | --- 51 | 52 | ## Member Functions 53 | 54 | ### `static LoggerConsole &instance()` 55 | 56 | Returns the singleton instance of the `LoggerConsole`. 57 | 58 | #### Example 59 | 60 | ```cpp 61 | LoggerConsole::instance().info("Logger ready!"); 62 | ``` 63 | 64 | --- 65 | 66 | ### `void write(LogLevel level, const std::string &message)` 67 | 68 | Overrides the base class `Logger::write()` to print a formatted log message to the console, thread-safely. 69 | 70 | > ⚠️ This method is **not meant to be called directly**. Use `log()`, `info()`, `warning()` etc. from the base class. 71 | 72 | --- 73 | 74 | ## Thread Safety 75 | 76 | All output is protected with a `std::mutex` to ensure that concurrent log writes do not interleave. 77 | 78 | --- 79 | 80 | For detailed API references, see individual method documentation at [txeo::LoggerConsole](https://txeo-doc.netlify.app/classtxeo_1_1_logger_console.html). 81 | -------------------------------------------------------------------------------- /include/txeo/detail/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef TXEO_UTILS_H 2 | #define TXEO_UTILS_H 3 | #pragma once 4 | 5 | #include // for int64_t 6 | #include // for size_t, abs 7 | #include // for numeric_limits 8 | #include // for string 9 | #include 10 | #include 11 | #include // for DataTypeToEnum, Enum... 12 | #include // for DataType 13 | #include // for is_floating_point_v 14 | #include // for vector 15 | 16 | #include "txeo/TensorShape.h" // for TensorShape 17 | 18 | namespace tensorflow { 19 | class TensorShape; 20 | class TensorShapeProto; 21 | } // namespace tensorflow 22 | 23 | namespace tf = tensorflow; 24 | 25 | namespace txeo::detail { 26 | 27 | /** 28 | * @brief Gets the correspondent TensorFlow type from the cpp type 29 | * 30 | * @tparam T cpp type 31 | * @return tf::DataType TensorFlow type 32 | */ 33 | template 34 | constexpr tf::DataType get_tf_dtype() { 35 | static_assert(tf::DataTypeToEnum::value != tf::DT_INVALID, 36 | "Unsupported C++ type for TensorFlow mapping"); 37 | return tf::DataTypeToEnum::value; 38 | } 39 | 40 | /** 41 | * @brief Specifies the cpp type from the TensorFlow type 42 | * 43 | * @tparam T TensorFlow type 44 | */ 45 | template 46 | using cpp_type = typename tf::EnumToDataType::Type; 47 | 48 | int64_t to_int64(const size_t &val); 49 | 50 | size_t to_size_t(const int64_t &val); 51 | 52 | std::vector to_size_t(const std::vector &vec); 53 | 54 | std::vector to_int64(const std::vector &vec); 55 | 56 | int to_int(const size_t &val); 57 | 58 | int to_int(const int64_t &val); 59 | 60 | std::string format(const double &a, int precision); 61 | 62 | txeo::TensorShape to_txeo_tensor_shape(const tf::TensorShape &shape); 63 | 64 | txeo::TensorShape proto_to_txeo_tensor_shape(const tf::TensorShapeProto &shape); 65 | 66 | std::vector calc_stride(const tf::TensorShape &shape); 67 | 68 | template 69 | bool is_zero(T value) { 70 | if constexpr (std::is_floating_point_v) 71 | return std::abs(value) < std::numeric_limits::epsilon(); 72 | 73 | return value == 0; 74 | } 75 | 76 | bool is_numeric(const std::string &word); 77 | 78 | std::string current_time(); 79 | 80 | } // namespace txeo::detail 81 | 82 | #endif -------------------------------------------------------------------------------- /include/txeo/TensorIO.h: -------------------------------------------------------------------------------- 1 | #ifndef TENSORIO_H 2 | #define TENSORIO_H 3 | #pragma once 4 | 5 | #include "txeo/Tensor.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace txeo { 14 | 15 | /** 16 | * @brief This class is deprecated. Please use class txeo::MatrixIO 17 | * 18 | */ 19 | 20 | class TensorIO { 21 | public: 22 | explicit TensorIO(const std::filesystem::path &path, char separator = ',') 23 | : _path(std::move(path)), _separator(separator) {}; 24 | 25 | template 26 | [[deprecated("Use class txeo::MatrixIO.")]] 27 | txeo::Tensor read_text_file(bool has_header = false) const; 28 | 29 | template 30 | [[deprecated("Use class txeo::MatrixIO.")]] 31 | void write_text_file(const txeo::Tensor &tensor) const; 32 | 33 | template 34 | requires(std::is_floating_point_v) 35 | [[deprecated("Use class txeo::MatrixIO.")]] 36 | void write_text_file(const txeo::Tensor &tensor, size_t precision) const; 37 | 38 | template 39 | [[deprecated("Use class txeo::MatrixIO.")]] 40 | static txeo::Tensor read_textfile(const std::filesystem::path &path, char separator = ',', 41 | bool has_header = false) { 42 | txeo::TensorIO io{path, separator}; 43 | Tensor resp{io.read_text_file(has_header)}; 44 | return resp; 45 | }; 46 | 47 | template 48 | [[deprecated("Use class txeo::MatrixIO.")]] 49 | static void write_textfile(const txeo::Tensor &tensor, const std::filesystem::path &path, 50 | char separator = ',') { 51 | txeo::TensorIO io{path, separator}; 52 | io.write_text_file(tensor); 53 | } 54 | 55 | template 56 | requires(std::is_floating_point_v) 57 | [[deprecated("Use class txeo::MatrixIO.")]] 58 | static void write_textfile(const txeo::Tensor &tensor, size_t precision, 59 | const std::filesystem::path &path, char separator = ',') { 60 | txeo::TensorIO io{path, separator}; 61 | io.write_text_file(tensor, precision); 62 | }; 63 | 64 | private: 65 | std::filesystem::path _path; 66 | char _separator; 67 | }; 68 | 69 | /** 70 | * @brief Exceptions concerning @ref txeo::TensorIO 71 | * 72 | */ 73 | class TensorIOError : public std::runtime_error { 74 | public: 75 | using std::runtime_error::runtime_error; 76 | }; 77 | 78 | } // namespace txeo 79 | 80 | #endif -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/logger-file.md: -------------------------------------------------------------------------------- 1 | # LoggerFile 2 | 3 | Singleton logger for writing formatted log messages to a file. 4 | 5 | --- 6 | 7 | ## Overview 8 | 9 | The `LoggerFile` class is a thread-safe singleton that implements the `txeo::Logger` interface for persistent file-based logging. It supports log-level filtering, timestamped messages, and mutex-protected writes. The log file must be explicitly opened before use. 10 | 11 | This class is ideal for server logs, diagnostics, or long-running processes where console logging is insufficient. 12 | 13 | --- 14 | 15 | ## Features 16 | 17 | * ✅ Thread-safe using internal `std::mutex` 18 | * ✅ Singleton access (`LoggerFile::instance()`) 19 | * ✅ Timestamped log messages 20 | * ✅ RAII for automatic file cleanup 21 | * ✅ Custom error handling with `LoggerFileError` 22 | 23 | --- 24 | 25 | ## Header 26 | 27 | ```cpp 28 | #include "txeo/LoggerFile.h" 29 | ``` 30 | 31 | --- 32 | 33 | ## Usage Example 34 | 35 | ```cpp 36 | #include "txeo/LoggerFile.h" 37 | 38 | int main() { 39 | try { 40 | auto &logger = txeo::LoggerFile::instance(); 41 | logger.open_file("log.txt"); 42 | 43 | logger.info("Application started"); 44 | logger.warning("Disk space low"); 45 | 46 | logger.close_file(); 47 | } catch (const txeo::LoggerFileError& e) { 48 | std::cerr << "Logging error: " << e.what() << std::endl; 49 | } 50 | } 51 | ``` 52 | 53 | --- 54 | 55 | ## Member Functions 56 | 57 | ### `static LoggerFile &instance()` 58 | 59 | Returns the singleton instance of the logger. 60 | 61 | ```cpp 62 | auto& logger = LoggerFile::instance(); 63 | ``` 64 | 65 | ### `bool open_file(const std::filesystem::path &file_path)` 66 | 67 | Opens a file for logging output. Throws `LoggerFileError` if it fails. 68 | 69 | ### `void close_file()` 70 | 71 | Closes the current log file. Automatically called in destructor if still open. 72 | 73 | ### `void write(LogLevel level, const std::string &message)` 74 | 75 | Writes a message to the open file with timestamp and log level formatting. 76 | 77 | > ⚠️ This function is not intended to be called directly; use `log()`, `info()`, `warning()`, etc. 78 | 79 | --- 80 | 81 | ## Exception: `LoggerFileError` 82 | 83 | Thrown when a file cannot be opened or logging fails. 84 | 85 | ```cpp 86 | try { 87 | logger.open_file("invalid/path/log.txt"); 88 | } catch (const txeo::LoggerFileError& err) { 89 | std::cerr << err.what(); 90 | } 91 | ``` 92 | 93 | --- 94 | 95 | For detailed API references, see individual method documentation at [txeo::LoggerFile](https://txeo-doc.netlify.app/classtxeo_1_1_logger_file.html). 96 | -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/logger.md: -------------------------------------------------------------------------------- 1 | # Logger 2 | 3 | Abstract base class for all logging implementations in the **txeo** project. 4 | 5 | --- 6 | 7 | ## Overview 8 | 9 | The `Logger` class defines the standard interface and behavior for logging in **txeo**. It supports log-level filtering, message formatting, and enabling/disabling logging globally. This base class should be inherited by specific logger implementations such as `LoggerConsole` or `LoggerFile`. 10 | 11 | --- 12 | 13 | ## Features 14 | 15 | * ✅ Log-level filtering (`DEBUG`, `INFO`, `WARNING`, `ERROR`) 16 | * ✅ Toggle logging globally (enable/disable) 17 | * ✅ Convenience methods: `info()`, `error()`, `debug()`, `warning()` 18 | * ✅ Virtual `write()` method for subclass customization 19 | 20 | --- 21 | 22 | ## Header 23 | 24 | ```cpp 25 | #include "txeo/Logger.h" 26 | ``` 27 | 28 | --- 29 | 30 | ## Usage Example 31 | 32 | ```cpp 33 | class MyConsoleLogger : public txeo::Logger { 34 | protected: 35 | void write(txeo::LogLevel level, const std::string &message) override { 36 | std::cout << "[" << log_level_str(level) << "] " << message << std::endl; 37 | } 38 | }; 39 | 40 | MyConsoleLogger logger; 41 | logger.set_output_level(txeo::LogLevel::INFO); 42 | logger.info("System initialized"); 43 | logger.debug("Debug skipped"); // Will be filtered 44 | ``` 45 | 46 | --- 47 | 48 | ## Member Functions 49 | 50 | ### `void log(LogLevel level, const std::string &message)` 51 | 52 | Writes a message if logging is enabled and the level is above threshold. 53 | 54 | ### `void turn_on()` / `void turn_off()` 55 | 56 | Globally enables or disables all logging. 57 | 58 | ### `LogLevel output_level() const` / `void set_output_level(LogLevel)` 59 | 60 | Controls the minimum level required for messages to be shown. 61 | 62 | ### Level-Specific Helpers 63 | 64 | * `void debug(const std::string&)` 65 | * `void info(const std::string&)` 66 | * `void warning(const std::string&)` 67 | * `void error(const std::string&)` 68 | 69 | Shortcut methods to log with the corresponding severity level. 70 | 71 | ### `virtual void write(LogLevel level, const std::string &message)` 72 | 73 | Pure virtual method that must be implemented by subclasses. 74 | 75 | ### `static std::string log_level_str(LogLevel)` 76 | 77 | Converts a `LogLevel` to a human-readable string. 78 | 79 | --- 80 | 81 | ## Enum: `LogLevel` 82 | 83 | The `LogLevel` enum controls severity classification. 84 | 85 | ```cpp 86 | enum class LogLevel { 87 | DEBUG, // Developer diagnostics 88 | INFO, // General status messages 89 | WARNING, // Warnings about possible problems 90 | ERROR // Errors requiring immediate attention 91 | }; 92 | ``` 93 | 94 | --- 95 | 96 | For detailed API references, see individual method documentation at [txeo::Logger](https://txeo-doc.netlify.app/classtxeo_1_1_logger.html). 97 | 98 | -------------------------------------------------------------------------------- /mkdocs/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: txeo 2 | site_description: "A Modern C++ wrapper for TensorFlow" 3 | site_url: https://rdabra.github.io/txeo/ 4 | repo_url: "https://github.com/rdabra/txeo" 5 | repo_name: "rdabra/txeo" 6 | theme: 7 | name: material 8 | language: en 9 | logo: assets/logo.png 10 | favicon: img/favicon.ico 11 | palette: 12 | - media: "(prefers-color-scheme: dark)" 13 | scheme: slate 14 | primary: blue grey 15 | toggle: 16 | icon: material/weather-sunny 17 | name: Switch to light mode 18 | 19 | - media: "(prefers-color-scheme: light)" 20 | scheme: default 21 | primary: blue grey 22 | toggle: 23 | icon: material/weather-night 24 | name: Switch to dark mode 25 | features: 26 | - navigation.tabs 27 | - navigation.sections 28 | - navigation.expand 29 | - search.highlight 30 | - search.share 31 | nav: 32 | - Home: index.md 33 | - Getting Started: getting-started.md 34 | - Usage: 35 | - Basic Usage: usage.md 36 | # - Advanced Topics: 37 | # - Tensors: advanced/tensor.md 38 | # - Matrix & Vector: advanced/matrix-vector.md 39 | # - Predictor: advanced/predictor.md 40 | - API Reference: 41 | - TensorShape: api-reference/tensor-shape.md 42 | - Tensor: api-reference/tensor.md 43 | - Matrix: api-reference/matrix.md 44 | - MatrixIO: api-reference/matrix-io.md 45 | - Vector: api-reference/vector.md 46 | - TensorOp: api-reference/tensor-op.md 47 | - TensorAgg: api-reference/tensor-agg.md 48 | - TensorFunc: api-reference/tensor-func.md 49 | - TensorPart: api-reference/tensor-part.md 50 | - Predictor: api-reference/predictor.md 51 | - Loss: api-reference/loss.md 52 | - DataTable: api-reference/data-table.md 53 | - DataTableNorm: api-reference/data-table-norm.md 54 | - Trainer: api-reference/trainer.md 55 | - OlsTrainer: api-reference/ols_gd_trainer.md 56 | - Logger: api-reference/logger.md 57 | - LoggerConsole: api-reference/logger-console.md 58 | - LoggerFile: api-reference/logger-file.md 59 | # - Tutorials: 60 | # - Intro to Tensors: tutorials/intro-to-tensors.md 61 | # - Matrix Math: tutorials/matrix-math.md 62 | # - Model Inference Guide: tutorials/inference-guide.md 63 | - Changelog: changelog.md 64 | # - FAQ: faq.md 65 | # - Contributing: contributing.md 66 | 67 | markdown_extensions: 68 | - toc: 69 | permalink: true 70 | - admonition 71 | - pymdownx.superfences 72 | - pymdownx.inlinehilite 73 | - pymdownx.highlight 74 | - pymdownx.tasklist: 75 | custom_checkbox: true 76 | - pymdownx.arithmatex: 77 | generic: true 78 | 79 | extra_javascript: 80 | - https://polyfill.io/v3/polyfill.min.js?features=es6 81 | - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js 82 | -------------------------------------------------------------------------------- /tests/tLoggerConsole.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/LoggerConsole.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace txeo { 8 | 9 | TEST(LoggerConsoleTest, DefaultOutputLevelIsAll) { 10 | auto &logger = LoggerConsole::instance(); 11 | ASSERT_EQ(logger.output_level(), LogLevel::DEBUG); 12 | } 13 | 14 | TEST(LoggerConsoleTest, SetOutputLevel) { 15 | auto &logger = LoggerConsole::instance(); 16 | logger.set_output_level(LogLevel::INFO); 17 | ASSERT_EQ(logger.output_level(), LogLevel::INFO); 18 | logger.set_output_level(LogLevel::DEBUG); 19 | } 20 | 21 | TEST(LoggerConsoleTest, WhenTurnedOff_NoMessagesLogged) { 22 | auto &logger = LoggerConsole::instance(); 23 | logger.turn_off(); 24 | 25 | std::stringstream buffer; 26 | auto old_buf = std::cout.rdbuf(buffer.rdbuf()); 27 | logger.info("Should not appear"); 28 | std::cout.rdbuf(old_buf); 29 | 30 | EXPECT_TRUE(buffer.str().empty()); 31 | logger.turn_on(); 32 | } 33 | 34 | TEST(LoggerConsoleTest, LogLevelLowerThanOutputLevelNotLogged) { 35 | auto &logger = LoggerConsole::instance(); 36 | logger.set_output_level(LogLevel::WARNING); 37 | 38 | std::stringstream buffer{}; 39 | auto old_buf = std::cout.rdbuf(buffer.rdbuf()); 40 | logger.info("Info message"); 41 | std::cout.rdbuf(old_buf); 42 | 43 | EXPECT_TRUE(buffer.str().empty()); 44 | logger.set_output_level(LogLevel::DEBUG); 45 | } 46 | 47 | TEST(LoggerConsoleTest, LogLevelEqualToOrHigherThanOutputLevelIsLogged) { 48 | auto &logger = LoggerConsole::instance(); 49 | logger.set_output_level(LogLevel::INFO); 50 | 51 | std::stringstream buffer; 52 | auto old_buf = std::cout.rdbuf(buffer.rdbuf()); 53 | logger.info("Info message"); 54 | logger.warning("Warning message"); 55 | std::cout.rdbuf(old_buf); 56 | 57 | EXPECT_NE(buffer.str().find("Info message"), std::string::npos); 58 | EXPECT_NE(buffer.str().find("Warning message"), std::string::npos); 59 | logger.set_output_level(LogLevel::DEBUG); 60 | } 61 | 62 | TEST(LoggerConsoleTest, LogMessagesContainCorrectLevelStrings) { 63 | auto &logger = LoggerConsole::instance(); 64 | 65 | std::stringstream buffer; 66 | auto old_buf = std::cout.rdbuf(buffer.rdbuf()); 67 | logger.debug("Debug"); 68 | logger.info("Info"); 69 | logger.warning("Warning"); 70 | logger.error("Error"); 71 | std::cout.rdbuf(old_buf); 72 | 73 | const std::string output = buffer.str(); 74 | std::cout << output << std::endl; 75 | EXPECT_NE(output.find("DEBUG"), std::string::npos); 76 | EXPECT_NE(output.find("INFO"), std::string::npos); 77 | EXPECT_NE(output.find("WARNING"), std::string::npos); 78 | EXPECT_NE(output.find("ERROR"), std::string::npos); 79 | } 80 | 81 | TEST(LoggerConsoleTest, SingletonInstanceIsSameAcrossCalls) { 82 | auto &logger1 = LoggerConsole::instance(); 83 | auto &logger2 = LoggerConsole::instance(); 84 | ASSERT_EQ(&logger1, &logger2); 85 | } 86 | 87 | } // namespace txeo -------------------------------------------------------------------------------- /tests/tDataTable.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/DataTable.h" 2 | #include "txeo/Matrix.h" 3 | #include 4 | 5 | TEST(DataTableTest, ConstructWithSpecifiedFeatureAndLabelColumns) { 6 | txeo::Matrix data({{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); 7 | txeo::DataTable dt(data, {0, 1}, std::vector({2})); 8 | 9 | EXPECT_EQ(dt.x_train().row_size(), 3); 10 | EXPECT_EQ(dt.x_train().col_size(), 2); 11 | EXPECT_EQ(dt.y_train().col_size(), 1); 12 | } 13 | 14 | TEST(DataTableTest, ConstructWithLabelColumnsOnly) { 15 | txeo::Matrix data({{1.1f, 2.2f, 3.3f, 4.4f}, {5.5f, 6.6f, 7.7f, 8.8f}}); 16 | txeo::DataTable dt(data, {3}); 17 | 18 | EXPECT_EQ(dt.x_dim(), 3); 19 | EXPECT_EQ(dt.y_dim(), 1); 20 | } 21 | 22 | TEST(DataTableTest, ConstructWithEvalSplit) { 23 | txeo::Matrix data(100, 5); 24 | txeo::DataTable dt(data, {0, 1, 2}, {3, 4}, 30); 25 | 26 | EXPECT_EQ(dt.x_train().row_size(), 70); 27 | EXPECT_EQ(dt.x_eval()->row_size(), 30); 28 | } 29 | 30 | TEST(DataTableTest, ConstructWithEvalSplitLabelOnly) { 31 | txeo::Matrix data({{1, 2, 3, 4}, {5, 6, 7, 8}}); 32 | txeo::DataTable dt(data, {3}, 50); 33 | 34 | EXPECT_EQ(dt.row_size(), 1); 35 | EXPECT_EQ(dt.x_eval()->row_size(), 1); 36 | } 37 | 38 | TEST(DataTableTest, ConstructWithEvalAndTestSplit) { 39 | txeo::Matrix data(1000, 10); 40 | txeo::DataTable dt(data, {0, 1, 2, 3}, {4, 5}, 20, 10); 41 | 42 | EXPECT_EQ(dt.x_train().row_size(), 700); 43 | EXPECT_EQ(dt.x_eval()->row_size(), 200); 44 | EXPECT_EQ(dt.x_test()->row_size(), 100); 45 | } 46 | 47 | TEST(DataTableTest, ConstructExplicitTrainingEvalTestSplits) { 48 | txeo::Matrix X_train({{1.0, 2.0}, {3.0, 4.0}}); 49 | txeo::Matrix y_train({{0.5}, {1.2}}); 50 | txeo::Matrix X_eval({{5.0, 6.0}}); 51 | txeo::Matrix y_eval({{2.1}}); 52 | txeo::Matrix X_test({{7.0, 8.0}}); 53 | txeo::Matrix y_test({{3.0}}); 54 | 55 | txeo::DataTable dt_full(X_train, y_train, X_eval, y_eval, X_test, y_test); 56 | 57 | EXPECT_EQ(dt_full.x_train().row_size(), 2); 58 | EXPECT_EQ(dt_full.x_eval()->row_size(), 1); 59 | EXPECT_EQ(dt_full.x_test()->row_size(), 1); 60 | } 61 | 62 | TEST(DataTableTest, ConstructExplicitTrainingAndEvalSplits) { 63 | txeo::Matrix X_train({{1.0, 2.0}, {3.0, 4.0}}); 64 | txeo::Matrix y_train({{0.5}, {1.2}}); 65 | txeo::Matrix X_eval({{5.0, 6.0}}); 66 | txeo::Matrix y_eval({{2.1}}); 67 | 68 | txeo::DataTable dt_eval(X_train, y_train, X_eval, y_eval); 69 | 70 | EXPECT_EQ(dt_eval.x_train().row_size(), 2); 71 | EXPECT_EQ(dt_eval.x_eval()->row_size(), 1); 72 | } 73 | 74 | TEST(DataTableTest, ConstructTrainingDataOnly) { 75 | txeo::Matrix X_train({{1.0, 2.0}, {3.0, 4.0}}); 76 | txeo::Matrix y_train({{0.5}, {1.2}}); 77 | 78 | txeo::DataTable dt_simple(X_train, y_train); 79 | 80 | EXPECT_EQ(dt_simple.x_train().row_size(), 2); 81 | } -------------------------------------------------------------------------------- /include/txeo/TensorIterator.h: -------------------------------------------------------------------------------- 1 | #ifndef TENSOR_ITERATOR_H 2 | #define TENSOR_ITERATOR_H 3 | #pragma once 4 | 5 | #include 6 | 7 | namespace txeo { 8 | 9 | template 10 | class TensorIterator { 11 | public: 12 | using value_type = T; 13 | using pointer = T *; 14 | using reference = T &; 15 | using difference_type = std::ptrdiff_t; 16 | using iterator_category = std::random_access_iterator_tag; 17 | 18 | TensorIterator() : _elements(nullptr), _step(1) {} // required by some std functions 19 | TensorIterator(T *elements, std::ptrdiff_t step = 1) : _elements(elements), _step(step) {} 20 | 21 | inline reference operator*() const { return *_elements; } 22 | inline pointer operator->() const { return _elements; } 23 | 24 | inline TensorIterator &operator++() { 25 | _elements += _step; 26 | return *this; 27 | } 28 | 29 | inline TensorIterator operator++(int) { 30 | auto aux = *this; 31 | ++(*this); 32 | return aux; 33 | } 34 | 35 | inline TensorIterator &operator--() { 36 | _elements -= _step; 37 | return *this; 38 | } 39 | 40 | inline TensorIterator operator--(int) { 41 | auto aux = *this; 42 | --(*this); 43 | return aux; 44 | } 45 | 46 | inline TensorIterator &operator+=(const difference_type &val) { 47 | _elements += val * _step; 48 | return *this; 49 | } 50 | 51 | inline TensorIterator &operator-=(const difference_type &val) { 52 | _elements -= val * _step; 53 | return *this; 54 | } 55 | 56 | friend TensorIterator operator+(TensorIterator iterator, const difference_type &val) { 57 | iterator += val; 58 | return iterator; 59 | } 60 | 61 | friend TensorIterator operator+(const difference_type &val, TensorIterator iterator) { 62 | iterator += val; 63 | return iterator; 64 | } 65 | 66 | friend TensorIterator operator-(TensorIterator iterator, const difference_type &val) { 67 | iterator -= val; 68 | return iterator; 69 | } 70 | 71 | inline difference_type operator-(const TensorIterator &other) const { 72 | return (_elements - other._elements) / _step; 73 | } 74 | 75 | inline bool operator==(const TensorIterator &other) const { 76 | return _elements == other._elements; 77 | } 78 | inline bool operator!=(const TensorIterator &other) const { 79 | return _elements != other._elements; 80 | } 81 | inline bool operator<(const TensorIterator &other) const { return _elements < other._elements; } 82 | inline bool operator>(const TensorIterator &other) const { return _elements > other._elements; } 83 | inline bool operator<=(const TensorIterator &other) const { 84 | return _elements <= other._elements; 85 | } 86 | inline bool operator>=(const TensorIterator &other) const { 87 | return _elements >= other._elements; 88 | } 89 | 90 | private: 91 | T *_elements; 92 | std::ptrdiff_t _step; 93 | }; 94 | 95 | } // namespace txeo 96 | 97 | #endif -------------------------------------------------------------------------------- /cmake/FindTensorFlow.cmake: -------------------------------------------------------------------------------- 1 | # cmake/FindTensorFlow.cmake 2 | include(FindPackageHandleStandardArgs) 3 | 4 | # Find TensorFlow 5 | find_path(TensorFlow_INCLUDE_DIR 6 | NAMES tensorflow/core/public/session.h 7 | HINTS 8 | ${TensorFlow_ROOT_DIR}/include 9 | ${TensorFlow_HOME}/include 10 | $ENV{TensorFlow_ROOT_DIR}/include 11 | $ENV{TensorFlow_HOME}/include 12 | ) 13 | 14 | message(STATUS "Found TensorFlow Includes at: ${TensorFlow_INCLUDE_DIR}") 15 | 16 | find_library(TensorFlow_CC_LIBRARY 17 | NAMES tensorflow_cc 18 | HINTS 19 | ${TensorFlow_ROOT_DIR}/lib 20 | ${TensorFlow_HOME}/lib 21 | $ENV{TensorFlow_ROOT_DIR}/lib 22 | $ENV{TensorFlow_HOME}/lib 23 | ) 24 | 25 | message(STATUS "Found TensorFlow C Library at: ${TensorFlow_CC_LIBRARY}") 26 | 27 | 28 | find_library(TensorFlow_FRAMEWORK_LIBRARY 29 | NAMES tensorflow_framework 30 | HINTS 31 | ${TensorFlow_ROOT_DIR}/lib 32 | ${TensorFlow_HOME}/lib 33 | $ENV{TensorFlow_ROOT_DIR}/lib 34 | $ENV{TensorFlow_HOME}/lib 35 | ) 36 | 37 | message(STATUS "Found TensorFlow Framework Library at: ${TensorFlow_FRAMEWORK_LIBRARY}") 38 | 39 | 40 | # Find Protobuf 41 | find_path(Protobuf_INCLUDE_DIR 42 | NAMES google/protobuf/message.h 43 | HINTS 44 | ${Protobuf_ROOT_DIR}/include 45 | ${Protobuf_HOME}/include 46 | $ENV{Protobuf_ROOT_DIR}/include 47 | $ENV{Protobuf_HOME}/include 48 | ) 49 | 50 | message(STATUS "Found Protobuf Includes at: ${Protobuf_INCLUDE_DIR}") 51 | 52 | 53 | find_library(Protobuf_LIBRARY 54 | NAMES protobuf 55 | HINTS 56 | ${Protobuf_ROOT_DIR}/lib 57 | ${Protobuf_HOME}/lib 58 | $ENV{Protobuf_ROOT_DIR}/lib 59 | $ENV{Protobuf_HOME}/lib 60 | ) 61 | 62 | message(STATUS "Found Protobuf Library at: ${Protobuf_LIBRARY}") 63 | 64 | # Combine Results 65 | set(TensorFlow_INCLUDE_DIRS 66 | ${TensorFlow_INCLUDE_DIR} 67 | ${Protobuf_INCLUDE_DIR} # Add Protobuf headers 68 | ) 69 | 70 | set(TensorFlow_LIBRARIES 71 | ${TensorFlow_CC_LIBRARY} 72 | ${TensorFlow_FRAMEWORK_LIBRARY} 73 | ${Protobuf_LIBRARY} # Link Protobuf 74 | ) 75 | 76 | # Validate Found Dependencies 77 | find_package_handle_standard_args(TensorFlow 78 | REQUIRED_VARS 79 | TensorFlow_INCLUDE_DIR 80 | TensorFlow_CC_LIBRARY 81 | TensorFlow_FRAMEWORK_LIBRARY 82 | Protobuf_INCLUDE_DIR 83 | Protobuf_LIBRARY 84 | ) 85 | 86 | # Create Imported Targets 87 | if(TensorFlow_FOUND AND NOT TARGET TensorFlow::TensorFlow) 88 | # TensorFlow target 89 | add_library(TensorFlow::TensorFlow SHARED IMPORTED) 90 | set_target_properties(TensorFlow::TensorFlow PROPERTIES 91 | INTERFACE_INCLUDE_DIRECTORIES "${TensorFlow_INCLUDE_DIRS}" 92 | IMPORTED_LOCATION "${TensorFlow_CC_LIBRARY}" 93 | INTERFACE_LINK_LIBRARIES 94 | "${TensorFlow_FRAMEWORK_LIBRARY};${Protobuf_LIBRARY}" 95 | ) 96 | endif() 97 | 98 | # Clean up internal variables 99 | mark_as_advanced( 100 | TensorFlow_INCLUDE_DIR 101 | TensorFlow_CC_LIBRARY 102 | TensorFlow_FRAMEWORK_LIBRARY 103 | Protobuf_INCLUDE_DIR 104 | Protobuf_LIBRARY 105 | ) -------------------------------------------------------------------------------- /include/txeo/LoggerFile.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGERFILE_H 2 | #define LOGGERFILE_H 3 | #pragma once 4 | 5 | #include "txeo/Logger.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace txeo { 11 | 12 | /** 13 | * @class LoggerFile 14 | * @brief Singleton logger implementation for file output 15 | * 16 | * Inherits from txeo::Logger and provides thread-safe file logging capabilities. 17 | * Uses RAII for resource management and follows the singleton pattern. 18 | * 19 | * @note The logger must be explicitly opened with open_file() before use 20 | * @note All logging operations are thread-safe through internal mutex 21 | * 22 | * **Example Usage:** 23 | * @code 24 | * try { 25 | * auto& logger = LoggerFile::instance(); 26 | * logger.open_file("app.log"); 27 | * logger.info("System initialized"); 28 | * logger.warning("Low memory detected"); 29 | * logger.close_file(); 30 | * } catch(const LoggerFileError& e) { 31 | * std::cerr << "Logging failed: " << e.what() << std::endl; 32 | * } 33 | * @endcode 34 | */ 35 | class LoggerFile : public txeo::Logger { 36 | public: 37 | LoggerFile(const LoggerFile &) = delete; 38 | LoggerFile(LoggerFile &&) = delete; 39 | LoggerFile &operator=(const LoggerFile &) = delete; 40 | LoggerFile &operator=(LoggerFile &&) = delete; 41 | ~LoggerFile(); 42 | 43 | /** 44 | * @brief Open log file for writing 45 | * @param file_path Path to log file (will be created if not exists) 46 | * @return true if file was successfully opened 47 | * @exception LoggerFileError Thrown if file opening fails 48 | * @note Appends to existing file by default 49 | * 50 | * **Example Usage:** 51 | * @code 52 | * if(!logger.open_file("debug.log")) { 53 | * // Handle open failure 54 | * } 55 | * @endcode 56 | */ 57 | bool open_file(const std::filesystem::path &file_path); 58 | 59 | /** 60 | * @brief Close the current log file 61 | * 62 | * **Example Usage:** 63 | * @code 64 | * logger.close_file(); // Explicit close 65 | * @endcode 66 | */ 67 | void close_file(); 68 | 69 | /** 70 | * @brief Get singleton instance 71 | * @return Reference to the singleton LoggerFile instance 72 | * 73 | * **Example Usage:** 74 | * @code 75 | * auto& logger = LoggerFile::instance(); 76 | * @endcode 77 | */ 78 | static LoggerFile &instance(); 79 | 80 | private: 81 | LoggerFile() = default; 82 | std::ofstream _wf; 83 | void write(txeo::LogLevel level, const std::string &message) override; 84 | std::mutex _mutex; 85 | }; 86 | 87 | /** 88 | * @class LoggerFileError 89 | * @brief Exception class for file logging errors 90 | * 91 | * Thrown during file operations or write failures. Inherits from std::runtime_error. 92 | * 93 | * **Example Usage:** 94 | * @code 95 | * try { 96 | * logger.debug("Sensor reading"); 97 | * } catch(const LoggerFileError& e) { 98 | * handle_error(e.what()); 99 | * } 100 | * @endcode 101 | */ 102 | class LoggerFileError : public std::runtime_error { 103 | public: 104 | using std::runtime_error::runtime_error; 105 | }; 106 | 107 | } // namespace txeo 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.25) 2 | 3 | 4 | project(txeo LANGUAGES CXX VERSION 0.1 DESCRIPTION "TXEO - A DEVELOPER-FRIENDLY TENSORFLOW C++ WRAPPER") 5 | 6 | set(CMAKE_CXX_STANDARD 20) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | set(CMAKE_CXX_EXTENSIONS OFF) #Turns off compiler non-standard features 9 | 10 | 11 | 12 | #################################################### Source Directories #################################################### 13 | 14 | 15 | 16 | include_directories(include) 17 | add_subdirectory(src) 18 | add_subdirectory(examples) 19 | 20 | 21 | #################################################### Testing #################################################### 22 | 23 | enable_testing() 24 | if(BUILD_TESTING) 25 | add_subdirectory(tests) 26 | endif() 27 | 28 | 29 | #################################################### Txeo Installation #################################################### 30 | 31 | # After defining your library targets (add_library) but before install() 32 | 33 | set(CMAKE_INSTALL_PREFIX "/opt/txeo" CACHE PATH "Install path prefix" FORCE) 34 | 35 | # Define installation directories 36 | include(GNUInstallDirs) 37 | 38 | # Install libraries 39 | install(TARGETS txeo_static txeo_shared 40 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} # Static libraries (.a) 41 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} # Shared libraries (.so) 42 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # Executables (if any) 43 | ) 44 | 45 | # Install headers 46 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 47 | 48 | 49 | #################################################### Automating Doxygen #################################################### 50 | 51 | find_package(Doxygen QUIET COMPONENTS dot) 52 | 53 | if (NOT CMAKE_BUILD_TYPE STREQUAL "Release") 54 | if(DOXYGEN_FOUND) 55 | set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile) 56 | 57 | add_custom_target(doxygen ALL 58 | COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_IN} 59 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 60 | COMMENT "Generating Doxygen documentation..." 61 | VERBATIM 62 | ) 63 | install(DIRECTORY ${DOXYGEN_OUT} DESTINATION share/docs) 64 | else() 65 | message(WARNING "Doxygen not found. Documentation target will not be available.") 66 | endif() 67 | endif() 68 | 69 | #################################################### Automating gcovr #################################################### 70 | 71 | option(TXEO_ENABLE_COVERAGE "Enable code coverage reporting" OFF) 72 | 73 | if(TXEO_ENABLE_COVERAGE) 74 | find_program(GCOVR_PATH gcovr PATHS ENV PATH) 75 | if(NOT GCOVR_PATH) 76 | message(FATAL_ERROR "gcovr not found.") 77 | endif() 78 | 79 | add_custom_target(coverage 80 | COMMAND ${GCOVR_PATH} 81 | --gcov-executable "llvm-cov gcov" 82 | --root ${CMAKE_SOURCE_DIR} 83 | --exclude-unreachable-branches 84 | --exclude-throw-branches 85 | --print-summary 86 | --html-details ${CMAKE_BINARY_DIR}/coverage_report.html 87 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 88 | COMMENT "Generating coverage report..." 89 | VERBATIM 90 | ) 91 | 92 | add_custom_target(coverage-clean 93 | COMMAND find ${CMAKE_BINARY_DIR} -name "*.gcda" -type f -delete 94 | COMMENT "Cleaning coverage data..." 95 | ) 96 | 97 | add_dependencies(coverage txeo_tests) 98 | endif() 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/ols_gd_trainer.md: -------------------------------------------------------------------------------- 1 | # OlsGDTrainer 2 | 3 | ## Overview 4 | 5 | `txeo::OlsGDTrainer` is a concrete implementation of the `txeo::Trainer` abstract class. It performs **Ordinary Least Squares (OLS)** linear regression using **Gradient Descent**. 6 | 7 | ## Features 8 | 9 | - Implements gradient descent for linear regression 10 | - Supports **learning rate tuning**, **convergence tolerance**, and **early stopping** 11 | - Optionally uses the **Barzilai-Borwein method** for adaptive learning rate 12 | - Access to learned **weight/bias matrix** 13 | 14 | ## Template Parameter 15 | 16 | - `T`: Floating-point type (e.g., `float`, `double`) 17 | 18 | ## Example Usage 19 | 20 | ```cpp 21 | // Create training data (y = 2x + 1) 22 | txeo::Matrix X({{1.0}, {2.0}, {3.0}}); 23 | txeo::Matrix y({{3.0}, {5.0}, {7.0}}); 24 | 25 | OlsGDTrainer trainer(txeo::DataTable(X, y)); 26 | trainer.set_tolerance(1e-5); 27 | trainer.fit(1000, LossFunc::MSE, 10); 28 | 29 | if (trainer.is_converged()) { 30 | auto weights = trainer.weight_bias(); 31 | std::cout << "Model: y = " << weights(0,0) << "x + " << weights(1,0) << std::endl; 32 | 33 | txeo::Matrix test_input(1,1,{4.0}); 34 | auto prediction = trainer.predict(test_input); 35 | std::cout << "Prediction for x=4: " << prediction(0,0) << std::endl; 36 | } 37 | ``` 38 | 39 | --- 40 | 41 | ## Constructors 42 | 43 | ### `Trainer(const txeo::DataTable &data)` 44 | 45 | Creates a trainer using a data table object. 46 | 47 | ```cpp 48 | txeo::Trainer(const txeo::DataTable &data); 49 | ``` 50 | 51 | --- 52 | 53 | ## Public Methods 54 | 55 | ### `predict(input)` 56 | 57 | Performs prediction on new input data. 58 | 59 | ```cpp 60 | txeo::Tensor predict(const txeo::Tensor& input); 61 | ``` 62 | 63 | ### `learning_rate()` 64 | 65 | Returns the current learning rate. 66 | 67 | ```cpp 68 | T learning_rate() const; 69 | ``` 70 | 71 | ### `set_learning_rate(value)` 72 | 73 | Sets the learning rate used in training. 74 | 75 | ```cpp 76 | void set_learning_rate(T value); 77 | ``` 78 | 79 | ### `enable_variable_lr()` / `disable_variable_lr()` 80 | 81 | Toggles the use of the Barzilai-Borwein adaptive learning rate. 82 | 83 | ```cpp 84 | void enable_variable_lr(); 85 | void disable_variable_lr(); 86 | ``` 87 | 88 | ### `weight_bias()` 89 | 90 | Returns the model weight-bias matrix. 91 | 92 | ```cpp 93 | const txeo::Matrix& weight_bias() const; 94 | ``` 95 | 96 | ### `tolerance()` / `set_tolerance(value)` 97 | 98 | Gets or sets the convergence tolerance. 99 | 100 | ```cpp 101 | T tolerance() const; 102 | void set_tolerance(const T& value); 103 | ``` 104 | 105 | ### `is_converged()` 106 | 107 | Checks if convergence was reached during training. 108 | 109 | ```cpp 110 | bool is_converged() const; 111 | ``` 112 | 113 | ### `min_loss()` 114 | 115 | Returns the minimum loss encountered during training. 116 | 117 | ```cpp 118 | T min_loss() const; 119 | ``` 120 | 121 | --- 122 | 123 | ## Exceptions 124 | 125 | ### `OlsGDTrainerError` 126 | 127 | Exception type used for runtime errors within the trainer. 128 | 129 | ```cpp 130 | class OlsGDTrainerError : public std::runtime_error; 131 | ``` 132 | 133 | --- 134 | 135 | ## Inheritance 136 | 137 | - Inherits from: `txeo::Trainer` 138 | - Implements: 139 | - `predict()` 140 | - `train()` 141 | 142 | For detailed API references, see individual method documentation at [txeo::OlsGDTrainer](https://txeo-doc.netlify.app/classtxeo_1_1_ols_g_d_trainer.html). -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/tensor-func.md: -------------------------------------------------------------------------------- 1 | # Tensor Functions 2 | 3 | The class `TensorFunc` of **txeo** provides common mathematical functions that can be applied element-wise to tensors. 4 | 5 | ## Overview 6 | 7 | `TensorFunc` offers element-wise mathematical functions such as potentiation, square, square root, absolute value, permutation of tensor axes, and matrix transposition. 8 | 9 | ## API Reference 10 | 11 | | Method | Description | 12 | |-----------------------------|--------------------------------------------------------------| 13 | | `abs_by` | Computes element-wise absolute value in-place | 14 | | `abs` | Computes element-wise absolute value | 15 | | `permute_by` | Permutes axes of a tensor in-place | 16 | | `permute` | Permutes axes of a tensor | 17 | | `power_elem_by` | Computes element-wise power in-place | 18 | | `power_elem` | Computes element-wise power of tensor elements | 19 | | `sqrt_by` | Computes element-wise square root in-place | 20 | | `sqrt` | Computes element-wise square root | 21 | | `square_by` | Computes element-wise square in-place | 22 | | `square` | Computes element-wise square | 23 | | `transpose_by` | Transposes a matrix in-place | 24 | | `transpose` | Transposes a matrix | 25 | 26 | --- 27 | 28 | ## Examples 29 | 30 | ### Element-wise Power 31 | 32 | ```cpp 33 | txeo::Tensor a({3}, {2.0f, 3.0f, 4.0f}); 34 | auto b = TensorFunc::power_elem(a, 2.0f); // [4.0, 9.0, 16.0] 35 | ``` 36 | 37 | ### In-place Element-wise Square 38 | 39 | ```cpp 40 | txeo::Tensor tensor({3}, {1, 2, 3}); 41 | TensorFunc::square_by(tensor); // tensor becomes [1, 4, 9] 42 | ``` 43 | 44 | ### Square Root 45 | 46 | ```cpp 47 | txeo::Tensor tensor({3}, {1.0, 4.0, 9.0}); 48 | auto result = TensorFunc::sqrt(tensor); // [1.0, 2.0, 3.0] 49 | ``` 50 | 51 | ### Absolute Value 52 | 53 | ```cpp 54 | txeo::Tensor tensor({3}, {-1, 2, -3}); 55 | auto result = TensorFunc::abs(tensor); // [1, 2, 3] 56 | ``` 57 | 58 | ### Permute Axes 59 | 60 | ```cpp 61 | txeo::Tensor tensor({2, 3, 4}, {1, 2, ..., 24}); 62 | auto result = TensorFunc::permute(tensor, {1, 2, 0}); // shape: (3, 4, 2) 63 | ``` 64 | 65 | ### Normalization 66 | 67 | ```cpp 68 | enum class NormalizationType { MIN_MAX, Z_SCORE }; 69 | ``` 70 | 71 | ```cpp 72 | txeo::Tensor tensor({3, 3}, {1., 2., 3., 4., 5., 6., 7., 8., 9.}); 73 | txeo::TensorFunc::normalize_by(tensor, txeo::NormalizationType::MIN_MAX); 74 | std::cout << tens << std::endl; // [0 0.125 0.25][0.375 0.5 0.625][0.75 0.875 1] 75 | ``` 76 | 77 | ### Matrix Transpose 78 | 79 | ```cpp 80 | txeo::Matrix matrix(2, 3, {1, 2, 3, 4, 5, 6}); 81 | auto result = TensorFunc::transpose(matrix); // shape: (3, 2) 82 | ``` 83 | 84 | ## Exceptions 85 | 86 | `TensorFuncError` is thrown if operations encounter invalid arguments, such as mismatched tensor shapes or invalid axis permutations. 87 | 88 | --- 89 | 90 | For detailed API references, see individual method documentation at [txeo::TensorFunc](https://txeo-doc.netlify.app/classtxeo_1_1_tensor_func.html). 91 | -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/trainer.md: -------------------------------------------------------------------------------- 1 | # Trainer 2 | 3 | ## Overview 4 | 5 | The `txeo::Trainer` class is an **abstract base class** that provides the interface for training machine learning models in **txeo**. It handles training/evaluation data, common training parameters, and the training lifecycle. 6 | 7 | Derived classes must implement the `predict()` and `train()` methods. 8 | 9 | --- 10 | 11 | ## Features 12 | 13 | - Abstract base class with pure virtual methods. 14 | - Manages training and evaluation datasets. 15 | - Supports early stopping. 16 | - Tracks whether the model has been trained. 17 | 18 | --- 19 | 20 | ## Template Parameter 21 | 22 | - `T`: The numeric type used in tensors (e.g., `float`, `double`). 23 | 24 | --- 25 | 26 | ## Constructors 27 | 28 | ### **Trainer(x_train, y_train, x_eval, y_eval)** 29 | 30 | Initializes the trainer with a data table object. 31 | 32 | ```cpp 33 | Trainer(const txeo::DataTable &data); 34 | ``` 35 | 36 | --- 37 | 38 | ## Public Methods 39 | 40 | ### **fit(epochs, metric)** 41 | 42 | Trains the model for a fixed number of epochs. 43 | 44 | ```cpp 45 | void fit(size_t epochs, txeo::LossFunc metric); 46 | ``` 47 | 48 | ### **fit(epochs, metric, patience)** 49 | 50 | Trains the model with early stopping. 51 | 52 | ```cpp 53 | void fit(size_t epochs, txeo::LossFunc metric, size_t patience); 54 | ``` 55 | 56 | ### **fit(epochs, metric, patience, type)** 57 | 58 | Trains the model with early stopping and feature normalization. 59 | 60 | ```cpp 61 | void fit(size_t epochs, txeo::LossFunc metric, size_t patience, txeo::NormalizationType type); 62 | ``` 63 | 64 | ### **predict(input)** 65 | 66 | Pure virtual method to generate predictions from a trained model. 67 | Must be implemented in derived classes. 68 | 69 | ```cpp 70 | txeo::Tensor predict(const txeo::Tensor& input) = 0; 71 | ``` 72 | 73 | ### **compute_test_loss(txeo::LossFunc metric) const** 74 | 75 | Computes the loss of the trained model for test data. 76 | 77 | ```cpp 78 | virtual T compute_test_loss(txeo::LossFunc metric) const; 79 | ``` 80 | 81 | ### **is_trained()** 82 | 83 | Returns `true` if the model has been trained. 84 | 85 | ```cpp 86 | bool is_trained() const; 87 | ``` 88 | 89 | ### **data_table()** 90 | 91 | Returns `std::DataTable` object owned by the trainer. 92 | 93 | ```cpp 94 | const txeo::DataTable &data_table() const; 95 | ``` 96 | 97 | ### **enable_feature_norm()** 98 | 99 | Enables normalization of feature data (input). 100 | 101 | ```cpp 102 | void enable_feature_norm(txeo::NormalizationType type); 103 | ``` 104 | 105 | ### **disable_feature_norm()** 106 | 107 | Disable normalization of feature data (input). 108 | 109 | ```cpp 110 | void disable_feature_norm(); 111 | ``` 112 | 113 | --- 114 | 115 | ## Exceptions 116 | 117 | ### **TrainerError** 118 | 119 | Exception type thrown by `Trainer` operations. 120 | 121 | ```cpp 122 | class TrainerError : public std::runtime_error; 123 | ``` 124 | 125 | ## Example Usage 126 | 127 | ```cpp 128 | class MyTrainer : public txeo::Trainer { 129 | public: 130 | using txeo::Trainer::Trainer; 131 | 132 | txeo::Tensor predict(const txeo::Tensor& input) override { 133 | // your prediction logic 134 | } 135 | 136 | protected: 137 | void train(size_t epochs, txeo::LossFunc loss_func) override { 138 | // your training logic 139 | } 140 | }; 141 | ``` 142 | 143 | For detailed API references, see individual method documentation at [txeo::Predictor](https://txeo-doc.netlify.app/classtxeo_1_1_trainer.html). 144 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 6, 3 | "configurePresets": [ 4 | { 5 | "name": "debugClang", 6 | "displayName": "debug-clang", 7 | "description": "Using compilers: clang, clang++", 8 | "generator": "Ninja", 9 | "binaryDir": "${sourceDir}/.out/build/${presetName}", 10 | "cacheVariables": { 11 | "CMAKE_INSTALL_PREFIX": "${sourceDir}/.out/install/${presetName}", 12 | "CMAKE_C_COMPILER": "$env{Clang_HOME}/bin/clang", 13 | "CMAKE_CXX_COMPILER": "$env{Clang_HOME}/bin/clang++", 14 | "CMAKE_CXX_FLAGS": "-stdlib=libstdc++ -g -O0", 15 | "CMAKE_BUILD_TYPE": "Debug", 16 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", 17 | "BUILD_TESTING": true 18 | }, 19 | "environment": { 20 | "TensorFlow_HOME": "/opt/tensorflow", 21 | "Protobuf_HOME": "/opt/protobuf", 22 | "CC": "clang", 23 | "CXX": "clang++" 24 | } 25 | }, 26 | { 27 | "name": "gcovrClang", 28 | "displayName": "gcovr-clang", 29 | "inherits": "debugClang", 30 | "cacheVariables": { 31 | "CMAKE_CXX_FLAGS": "-stdlib=libstdc++ -O0 -coverage", 32 | "BUILD_TESTING": true, 33 | "TXEO_ENABLE_COVERAGE": true 34 | }, 35 | "environment": { 36 | "TensorFlow_HOME": "/opt/tensorflow", 37 | "Protobuf_HOME": "/opt/protobuf", 38 | "CC": "clang", 39 | "CXX": "clang++" 40 | } 41 | }, 42 | { 43 | "name": "releaseClang", 44 | "displayName": "release-clang", 45 | "description": "Using compilers: clang, clang++", 46 | "generator": "Ninja", 47 | "binaryDir": "${sourceDir}/.out/build/${presetName}", 48 | "cacheVariables": { 49 | "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", 50 | "CMAKE_C_COMPILER": "$env{CLANG_HOME}/bin/clang", 51 | "CMAKE_CXX_COMPILER": "$env{CLANG_HOME}/bin/clang++", 52 | "CMAKE_CXX_FLAGS": "-stdlib=libstdc++ -O3", 53 | "CMAKE_BUILD_TYPE": "Release" 54 | }, 55 | "environment": { 56 | "TensorFlow_HOME": "/opt/tensorflow", 57 | "Protobuf_HOME": "/opt/protobuf", 58 | "CC": "clang", 59 | "CXX": "clang++" 60 | } 61 | }, 62 | { 63 | "name": "releaseGcc", 64 | "displayName": "release-gcc", 65 | "description": "Using compilers: g++, gcc", 66 | "generator": "Ninja", 67 | "binaryDir": "${sourceDir}/.out/build/${presetName}", 68 | "cacheVariables": { 69 | "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", 70 | "CMAKE_C_COMPILER": "gcc", 71 | "CMAKE_CXX_COMPILER": "g++", 72 | "CMAKE_CXX_FLAGS": "-stdlib=libstdc++ -O3", 73 | "CMAKE_BUILD_TYPE": "Release" 74 | }, 75 | "environment": { 76 | "TensorFlow_HOME": "/opt/tensorflow", 77 | "Protobuf_HOME": "/opt/protobuf", 78 | "CC": "gcc", 79 | "CXX": "g++" 80 | } 81 | }, 82 | { 83 | "name": "releaseIntel", 84 | "displayName": "Intel Release", 85 | "description": "Intel C++ Compiler (optimized for Intel architectures)", 86 | "generator": "Ninja", 87 | "binaryDir": "${sourceDir}/.out/build/${presetName}", 88 | "cacheVariables": { 89 | "CMAKE_C_COMPILER": "icx", 90 | "CMAKE_CXX_COMPILER": "icpx", 91 | "CMAKE_CXX_FLAGS": "-stdlib=libstdc++ -O3", 92 | "CMAKE_BUILD_TYPE": "Release" 93 | }, 94 | "environment": { 95 | "TensorFlow_HOME": "/opt/tensorflow", 96 | "Protobuf_HOME": "/opt/protobuf", 97 | "CC": "icx", 98 | "CXX": "icpx" 99 | } 100 | } 101 | ] 102 | } -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/tensor-part.md: -------------------------------------------------------------------------------- 1 | # TensorPart 2 | 3 | ## Overview 4 | 5 | `txeo::TensorPart` is a utility class that provides static methods to **partition and manipulate tensors and matrices**. It is especially useful for preprocessing operations like slicing, unstacking, or extracting submatrices. 6 | 7 | 8 | ## Template Parameter 9 | 10 | - `T`: Data type of tensor or matrix elements (e.g., `int`, `float`, `double`) 11 | 12 | ## Methods 13 | 14 | ### `unstack(tensor, axis)` 15 | 16 | Unstacks a tensor along the specified axis. 17 | 18 | ```cpp 19 | #include "txeo/TensorPart.h" 20 | #include "txeo/Tensor.h" 21 | #include 22 | 23 | int main() { 24 | txeo::Tensor tensor({{{1, 2, 3}, {4, 5, 6}}, {{7, 8, 9}, {10, 11, 12}}}); 25 | 26 | auto unstacked_tensors = txeo::TensorPart::unstack(tensor, 0); 27 | 28 | for (size_t i = 0; i < unstacked_tensors.size(); ++i) { 29 | std::cout << "Unstacked Tensor " << i << ":\n" << unstacked_tensors[i] << std::endl; 30 | } 31 | 32 | return 0; 33 | } 34 | ``` 35 | 36 | --- 37 | 38 | ### `slice(tensor, first_axis_begin, first_axis_end)` 39 | 40 | Returns a slice of the tensor along its first axis (no copying). 41 | 42 | ```cpp 43 | #include 44 | #include "txeo/Tensor.h" 45 | #include "txeo/TensorPart.h" 46 | 47 | int main() { 48 | txeo::Tensor tensor{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 49 | auto sliced_tensor = txeo::TensorPart::slice(tensor, 0, 2); 50 | 51 | std::cout << "Sliced Tensor: " << sliced_tensor << std::endl; 52 | return 0; 53 | } 54 | ``` 55 | 56 | --- 57 | 58 | ### `increase_dimension(tensor, axis, value)` 59 | 60 | Returns a new tensor with an inserted dimension filled with a specific value. 61 | 62 | ```cpp 63 | txeo::Tensor increase_dimension(const txeo::Tensor& tensor, size_t axis, T value); 64 | ``` 65 | 66 | --- 67 | 68 | ### `increase_dimension_by(tensor, axis, value)` 69 | 70 | Modifies the tensor **in-place**, inserting a new dimension. 71 | 72 | ```cpp 73 | txeo::Tensor& increase_dimension_by(txeo::Tensor& tensor, size_t axis, T value); 74 | ``` 75 | 76 | --- 77 | 78 | ### `sub_matrix_cols(matrix, cols)` 79 | 80 | Returns a submatrix with only the selected columns. 81 | 82 | ```cpp 83 | txeo::Matrix sub_matrix_cols(const txeo::Matrix& matrix, const std::vector& cols); 84 | ``` 85 | 86 | --- 87 | 88 | ### `sub_matrix_cols_exclude(matrix, cols)` 89 | 90 | Returns a submatrix **excluding** specified columns. 91 | 92 | ```cpp 93 | txeo::Matrix sub_matrix_cols_exclude(const txeo::Matrix& matrix, const std::vector& cols); 94 | ``` 95 | 96 | --- 97 | 98 | ### `sub_matrix_rows(matrix, rows)` 99 | 100 | Returns a submatrix with the specified rows. 101 | 102 | ```cpp 103 | txeo::Matrix sub_matrix_rows(const txeo::Matrix& matrix, const std::vector& rows); 104 | ``` 105 | 106 | --- 107 | 108 | ## Exceptions 109 | 110 | ### `TensorPartError` 111 | 112 | Thrown when a tensor or matrix operation fails. 113 | 114 | ```cpp 115 | class TensorPartError : public std::runtime_error; 116 | ``` 117 | 118 | --- 119 | 120 | ## Example: Unstacking 121 | 122 | ```cpp 123 | txeo::Tensor t({{{1,2,3}, {4,5,6}}, {{7,8,9}, {10,11,12}}}); 124 | auto slices = txeo::TensorPart::unstack(t, 0); 125 | ``` 126 | 127 | ## Example: Column Submatrix 128 | 129 | ```cpp 130 | txeo::Matrix m(2, 3, {1.1, 2.2, 3.3, 4.4, 5.5, 6.6}); 131 | auto sub = txeo::TensorPart::sub_matrix_cols(m, {0, 2}); 132 | ``` 133 | 134 | For detailed API references, see individual method documentation at [txeo::TensorPart](https://txeo-doc.netlify.app/classtxeo_1_1_tensor_part.html). 135 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/detail/utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace tf = tensorflow; 11 | 12 | namespace txeo::detail { 13 | 14 | int64_t to_int64(const size_t &val) { 15 | if (val > static_cast(std::numeric_limits::max())) 16 | throw std::overflow_error("size_t value exceeds int64_t maximum"); 17 | 18 | return static_cast(val); 19 | } 20 | 21 | size_t to_size_t(const int64_t &val) { 22 | if (val < 0) 23 | throw std::overflow_error("int64_t has a negative value"); 24 | 25 | return static_cast(val); 26 | } 27 | 28 | std::vector to_size_t(const std::vector &vec) { 29 | std::vector aux; 30 | for (auto &item : vec) 31 | aux.emplace_back(txeo::detail::to_size_t(item)); 32 | return aux; 33 | } 34 | 35 | std::vector to_int64(const std::vector &vec) { 36 | std::vector aux; 37 | for (auto &item : vec) 38 | aux.emplace_back(txeo::detail::to_int64(item)); 39 | return aux; 40 | } 41 | 42 | int to_int(const size_t &val) { 43 | if (val > static_cast(std::numeric_limits::max())) 44 | throw std::overflow_error("size_t value exceeds int maximum"); 45 | 46 | return static_cast(val); 47 | } 48 | 49 | int to_int(const int64_t &val) { 50 | if (val > static_cast(std::numeric_limits::max())) 51 | throw std::overflow_error("int64_t value exceeds int maximum"); 52 | 53 | return static_cast(val); 54 | } 55 | 56 | std::string format(const double &a, int precision) { 57 | std::stringstream stream; 58 | stream.setf(std::ios::fixed); 59 | stream.precision(precision + 1); 60 | stream << a; 61 | 62 | return stream.str(); 63 | } 64 | 65 | txeo::TensorShape to_txeo_tensor_shape(const tf::TensorShape &shape) { 66 | std::vector aux; 67 | auto dim_sizes = shape.dim_sizes(); 68 | std::ranges::copy(dim_sizes, std::back_inserter(aux)); 69 | 70 | txeo::TensorShape res(aux); 71 | 72 | return res; 73 | } 74 | 75 | txeo::TensorShape proto_to_txeo_tensor_shape(const tf::TensorShapeProto &shape) { 76 | std::vector aux; 77 | for (const auto &item : shape.dim()) { 78 | if (item.size() < 0) 79 | aux.emplace_back(0); 80 | else 81 | aux.emplace_back(static_cast(item.size())); 82 | } 83 | 84 | txeo::TensorShape res(aux); 85 | 86 | return res; 87 | } 88 | 89 | std::vector calc_stride(const tf::TensorShape &shape) { 90 | if (shape.dims() <= 1) 91 | return std::vector{}; 92 | std::vector resp(shape.dims() - 1); 93 | size_t accum_sizes{1}; 94 | for (size_t i = shape.dims() - 1; i > 0; --i) { 95 | accum_sizes *= shape.dim_size(txeo::detail::to_int(i)); 96 | resp[i - 1] = accum_sizes; 97 | } 98 | return resp; 99 | } 100 | 101 | bool is_numeric(const std::string &word) { 102 | std::istringstream word_stream{word}; 103 | double val{}; 104 | char c{}; 105 | 106 | return (word_stream >> val) && !(word_stream >> c); 107 | } 108 | 109 | std::string current_time() { 110 | auto now = std::chrono::system_clock::now(); 111 | auto local_now = std::chrono::current_zone()->to_local(now); 112 | auto local_midnight = std::chrono::floor(local_now); 113 | auto current_time = local_now - local_midnight; 114 | 115 | const std::chrono::hh_mm_ss hms{duration_cast(current_time)}; 116 | 117 | return std::format("{:%T}", hms); 118 | } 119 | 120 | } // namespace txeo::detail 121 | -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/predictor.md: -------------------------------------------------------------------------------- 1 | # Predictor 2 | 3 | **txeo**'s `Predictor` class handles inference tasks using TensorFlow SavedModels. It loads models, performs predictions, and provides metadata about model inputs, outputs, and devices. 4 | 5 | ## Constructors 6 | 7 | ### Initialization with path to model 8 | 9 | ```cpp 10 | explicit Predictor(std::filesystem::path model_path); 11 | ``` 12 | 13 | Constructs a `Predictor` object from a TensorFlow SavedModel directory containing a `.pb` file. 14 | 15 | **Example (Python Model Freezing):** 16 | 17 | ```python 18 | import tensorflow as tf 19 | 20 | model = tf.saved_model.load("path/to/trained_model") 21 | concrete_func = model.signatures["serving_default"] 22 | frozen_func = tf.python.framework.convert_to_constants.convert_variables_to_constants_v2(concrete_func) 23 | tf.io.write_graph( 24 | frozen_func.graph.as_graph_def(), 25 | "path/to/frozen_model", 26 | "frozen.pb", 27 | as_text=False 28 | ) 29 | ``` 30 | 31 | --- 32 | 33 | ## Methods 34 | 35 | ### `get_input_metadata` 36 | 37 | Returns input tensor metadata (names and shapes). 38 | 39 | ```cpp 40 | const TensorInfo &get_input_metadata() const noexcept; 41 | ``` 42 | 43 | ### `get_output_metadata` 44 | 45 | Returns output tensor metadata (names and shapes). 46 | 47 | ```cpp 48 | const TensorInfo &get_output_metadata() const noexcept; 49 | ``` 50 | 51 | ### `get_input_metadata_shape` 52 | 53 | Returns shape for a specified input tensor by name. 54 | 55 | ```cpp 56 | std::optional get_input_metadata_shape(const std::string &name) const; 57 | ``` 58 | 59 | ### `get_output_metadata_shape` 60 | 61 | Returns shape for a specified output tensor by name. 62 | 63 | ```cpp 64 | std::optional get_output_metadata_shape(const std::string &name) const; 65 | ``` 66 | 67 | ### `get_devices` 68 | 69 | Returns available compute devices. 70 | 71 | ```cpp 72 | std::vector get_devices() const; 73 | ``` 74 | 75 | ### `predict` 76 | 77 | Performs single input/output inference. 78 | 79 | ```cpp 80 | txeo::Tensor predict(const txeo::Tensor &input) const; 81 | ``` 82 | 83 | **Example:** 84 | 85 | ```cpp 86 | Tensor input({2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); 87 | auto output = predictor.predict(input); 88 | ``` 89 | 90 | ### `predict_batch` 91 | 92 | Performs batch inference with multiple named inputs. 93 | 94 | ```cpp 95 | std::vector> predict_batch(const TensorIdent &inputs) const; 96 | ``` 97 | 98 | **Example:** 99 | 100 | ```cpp 101 | std::vector>> inputs { 102 | {"image", image_tensor}, 103 | {"metadata", meta_tensor} 104 | }; 105 | auto results = predictor.predict_batch(inputs); 106 | ``` 107 | 108 | ### `enable_xla` 109 | 110 | Enables or disables XLA (Accelerated Linear Algebra) compilation. 111 | 112 | ```cpp 113 | void enable_xla(bool enable); 114 | ``` 115 | 116 | **Note:** Prefer enabling XLA before the first inference call. 117 | 118 | --- 119 | 120 | ## Structures 121 | 122 | ### DeviceInfo 123 | 124 | | Member | Description | 125 | |-----------------|------------------------| 126 | | `name` | Device name | 127 | | `device_type` | Type of device (CPU/GPU)| 128 | | `memory_limit` | Memory limit in bytes | 129 | 130 | --- 131 | 132 | ## Exceptions 133 | 134 | ### PredictorError 135 | 136 | Exception thrown when predictor operations fail. 137 | 138 | ```cpp 139 | class PredictorError : public std::runtime_error; 140 | ``` 141 | 142 | --- 143 | 144 | For detailed API references, see individual method documentation at [txeo::Predictor](https://txeo-doc.netlify.app/classtxeo_1_1_predictor.html). 145 | -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/data-table.md: -------------------------------------------------------------------------------- 1 | # DataTable 2 | 3 | A C++ template class in the **txeo** namespace designed to handle and organize datasets for machine learning workflows. It supports splitting data into training, evaluation, and test sets. 4 | 5 | ## Overview 6 | 7 | `DataTable` is a data container for supervised learning scenarios. It offers flexibility for defining feature and label columns and supports optional evaluation and test splits. 8 | 9 | --- 10 | 11 | ## Template Parameters 12 | 13 | - `T`: Numeric type (e.g., `float`, `double`) used in the underlying `Matrix`. 14 | 15 | --- 16 | 17 | ## Constructors 18 | 19 | ### DataTable with X/Y columns 20 | 21 | ```cpp 22 | DataTable(const Matrix& data, std::vector x_cols, std::vector y_cols); 23 | ``` 24 | 25 | Split based on specified feature and label columns. 26 | 27 | ### DataTable with only Y columns (auto-infer X columns) 28 | 29 | ```cpp 30 | DataTable(const Matrix& data, std::vector y_cols); 31 | ``` 32 | 33 | All columns not in `y_cols` are considered feature columns. 34 | 35 | ### DataTable with evaluation split 36 | 37 | ```cpp 38 | DataTable(const Matrix& data, std::vector x_cols, std::vector y_cols, 39 | size_t eval_percent); 40 | 41 | DataTable(const Matrix& data, std::vector y_cols, size_t eval_percent); 42 | ``` 43 | 44 | Reserves a percentage of the data for evaluation. 45 | 46 | ### DataTable with evaluation and test splits 47 | 48 | ```cpp 49 | DataTable(const Matrix& data, std::vector x_cols, std::vector y_cols, 50 | size_t eval_percent, size_t eval_test); 51 | 52 | DataTable(const Matrix& data, std::vector y_cols, size_t eval_percent, 53 | size_t eval_test); 54 | ``` 55 | 56 | Splits dataset into training, evaluation, and test. 57 | 58 | ### DataTable with explicit splits 59 | 60 | ```cpp 61 | DataTable(const Matrix& x_train, const Matrix& y_train, 62 | const Matrix& x_eval, const Matrix& y_eval, 63 | const Matrix& x_test, const Matrix& y_test); 64 | 65 | DataTable(const Matrix& x_train, const Matrix& y_train, 66 | const Matrix& x_eval, const Matrix& y_eval); 67 | 68 | DataTable(const Matrix& x_train, const Matrix& y_train); 69 | ``` 70 | 71 | Use pre-split matrices directly. If rvalues are passed, copy is avoided. 72 | 73 | --- 74 | 75 | ## Accessors 76 | 77 | ### Training Data 78 | 79 | ```cpp 80 | const Matrix& x_train() const; 81 | const Matrix& y_train() const; 82 | ``` 83 | 84 | ### Evaluation Data 85 | 86 | ```cpp 87 | const Matrix* x_eval() const; 88 | const Matrix* y_eval() const; 89 | ``` 90 | 91 | Returns nullptr if evaluation was not set. 92 | 93 | ### Test Data 94 | 95 | ```cpp 96 | const Matrix* x_test() const; 97 | const Matrix* y_test() const; 98 | ``` 99 | 100 | Returns nullptr if test was not set. 101 | 102 | --- 103 | 104 | ## Metadata 105 | 106 | ### Input/Output Dimensions 107 | 108 | ```cpp 109 | size_t x_dim() const; 110 | size_t y_dim() const; 111 | ``` 112 | 113 | ### Row Count 114 | 115 | ```cpp 116 | size_t row_size() const; 117 | ``` 118 | 119 | Number of rows in the training set. 120 | 121 | --- 122 | 123 | ## Exceptions 124 | 125 | ### `txeo::DataTableError` 126 | 127 | Thrown when invalid inputs or split percentages are provided. 128 | 129 | --- 130 | 131 | ## Example Usage 132 | 133 | ```cpp 134 | txeo::Matrix data = {{1, 2, 3, 4}, {5, 6, 7, 8}}; 135 | DataTable dt(data, {3}, 50); // 50% eval split 136 | 137 | assert(dt.x_train().rows() == 1); 138 | assert(dt.x_eval()->rows() == 1); 139 | ``` 140 | 141 | For detailed API references, see individual method documentation at [txeo::DataTable](https://txeo-doc.netlify.app/classtxeo_1_1_data_table.html). -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/loss.md: -------------------------------------------------------------------------------- 1 | # Loss 2 | 3 | ## Overview 4 | 5 | The `txeo::Loss` class computes error metrics between predicted and ground truth tensors. It supports multiple standard loss functions that are selectable at runtime. 6 | 7 | > ✅ Compatible with any numeric tensor type (float/double recommended) 8 | 9 | ## Supported Loss Functions 10 | 11 | - **MSE**: Mean Squared Error 12 | - **MAE**: Mean Absolute Error 13 | - **MSLE**: Mean Squared Logarithmic Error 14 | - **LCHE**: Log-Cosh Error 15 | 16 | --- 17 | 18 | ## Template Parameter 19 | 20 | - `T`: Numeric type of tensor elements (`float`, `double`, etc.) 21 | 22 | --- 23 | 24 | ## Constructor 25 | 26 | ### `Loss(const Tensor& valid, LossFunc func = LossFunc::MSE)` 27 | 28 | Creates a new loss evaluator object. 29 | 30 | ```cpp 31 | txeo::Loss loss(y_true, txeo::LossFunc::MAE); 32 | ``` 33 | 34 | --- 35 | 36 | ## Public Methods 37 | 38 | ### `T get_loss(const Tensor& pred) const` 39 | 40 | Computes loss using the current selected function. 41 | 42 | ```cpp 43 | auto error = loss.get_loss(pred); 44 | ``` 45 | 46 | ### `void set_loss(LossFunc func)` 47 | 48 | Sets the active loss function. 49 | 50 | ```cpp 51 | loss.set_loss(txeo::LossFunc::LCHE); 52 | ``` 53 | 54 | --- 55 | 56 | ## Specific Loss Functions 57 | 58 | All functions require prediction tensors with the same shape as the validation tensor. 59 | 60 | ### `mean_squared_error(pred)` / `mse(pred)` 61 | 62 | Computes: 63 | $$ 64 | MSE = \frac{1}{N} \sum_{i=1}^{N}(y_i - \hat{y}_i)^2 65 | $$ 66 | 67 | ### `mean_absolute_error(pred)` / `mae(pred)` 68 | 69 | Computes: 70 | $$ 71 | MAE = \frac{1}{N} \sum_{i=1}^{N}|y_i - \hat{y}_i| 72 | $$ 73 | 74 | ### `mean_squared_logarithmic_error(pred)` / `msle(pred)` 75 | 76 | Computes: 77 | $$ 78 | MSLE = \frac{1}{N} \sum_{i=1}^{N}(\log(1+y_i) - \log(1+\hat{y}_i))^2 79 | $$ 80 | > ⚠ Requires all values to be non-negative. 81 | 82 | ### `log_cosh_error(pred)` / `lche(pred)` 83 | 84 | Computes: 85 | $$ 86 | LCHE = \frac{1}{N} \sum_{i=1}^{N}\log(\cosh(y_i - \hat{y}_i)) 87 | $$ 88 | 89 | --- 90 | 91 | ## Shorthand Aliases 92 | 93 | | Alias | Full Function | 94 | |-------|----------------| 95 | | `lche(pred)` | `log_cosh_error(pred)` | 96 | | `mae(pred)` | `mean_absolute_error(pred)` | 97 | | `mse(pred)` | `mean_squared_error(pred)` | 98 | | `msle(pred)` | `mean_squared_logarithmic_error(pred)` | 99 | 100 | --- 101 | 102 | ## Exceptions 103 | 104 | ### `LossError` 105 | 106 | Thrown on shape mismatch or invalid inputs: 107 | 108 | ```cpp 109 | class LossError : public std::runtime_error; 110 | ``` 111 | 112 | --- 113 | 114 | ## Example 115 | 116 | ```cpp 117 | #include "txeo/Loss.h" 118 | 119 | int main() { 120 | // Create validation data 121 | txeo::Tensor valid({4}, {1.5f, 2.0f, 3.2f, 4.8f}); 122 | 123 | // Initialize loss calculator with default (MSE) 124 | txeo::Loss loss(valid); 125 | 126 | // Generate predictions 127 | txeo::Tensor pred({4}, {1.6f, 1.9f, 3.0f, 5.0f}); 128 | 129 | // Calculate and compare different losses 130 | std::cout << "MSE: " << loss.get_loss(pred) << std::endl; 131 | std::cout << "Direct MAE: " << loss.mae(pred) << std::endl; 132 | 133 | // Switch to MSLE and calculate 134 | loss.set_loss(txeo::LossFunc::MSLE); 135 | std::cout << "MSLE: " << loss.get_loss(pred) << std::endl; 136 | 137 | return 0; 138 | } 139 | ``` 140 | 141 | --- 142 | 143 | ## Notes 144 | 145 | - Tensors must have the same shape. 146 | - First dimension is assumed to be the sample axis. 147 | - Negative values in MSLE will throw `LossError`. 148 | - Loss functions are interchangeable at runtime. 149 | 150 | For detailed API references, see individual method documentation at [txeo::Loss](https://txeo-doc.netlify.app/classtxeo_1_1_loss.html). 151 | -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/data-table-norm.md: -------------------------------------------------------------------------------- 1 | 2 | # DataTableNorm 3 | 4 | A normalizer for `DataTable` objects that handles feature scaling, supporting both **Min-Max** and **Z-Score** normalization. 5 | 6 | ## Overview 7 | 8 | The `DataTableNorm` class provides feature normalization capabilities for machine learning datasets stored in `DataTable` format. It supports two normalization techniques: 9 | 10 | - **Min-Max Scaling**: Transforms features to [0, 1] range 11 | - **Z-Score Standardization**: Transforms features to mean=0, std=1 12 | 13 | **Key Features**: 14 | 15 | - Computes parameters from training data 16 | - Handles both in-place and copied normalization 17 | - Supports efficient rvalue operations 18 | - Works with evaluation/test splits 19 | 20 | --- 21 | 22 | ## Constructor 23 | 24 | ### `DataTableNorm(const DataTable &data, NormalizationType type = MIN_MAX)` 25 | 26 | Initializes the normalizer from a data table. 27 | 28 | **Example:** 29 | 30 | ```cpp 31 | txeo::DataTable data = load_my_dataset(); 32 | txeo::DataTableNorm normalizer(data, txeo::NormalizationType::Z_SCORE); 33 | ``` 34 | 35 | --- 36 | 37 | ## Member Functions 38 | 39 | ### `const DataTable& data_table() const` 40 | 41 | Returns the internal reference to the associated `DataTable`. 42 | 43 | **Example:** 44 | 45 | ```cpp 46 | const auto& dt = normalizer.data_table(); 47 | std::cout << dt.x_train().rows() << std::endl; 48 | ``` 49 | 50 | ### `void set_data_table(const DataTable& data)` 51 | 52 | Sets a new data table for normalization. 53 | 54 | **Example:** 55 | 56 | ```cpp 57 | txeo::DataTable new_data = load_updated_dataset(); 58 | normalizer.set_data_table(new_data); 59 | ``` 60 | 61 | ### `NormalizationType type() const` 62 | 63 | Returns the type of normalization currently used. 64 | 65 | **Example:** 66 | 67 | ```cpp 68 | if (normalizer.type() == txeo::NormalizationType::MIN_MAX) 69 | std::cout << "Using Min-Max normalization" << std::endl; 70 | ``` 71 | 72 | ### `Matrix normalize(Matrix&& x) const` 73 | 74 | Normalizes a matrix **in-place** using rvalue semantics. 75 | 76 | **Example:** 77 | 78 | ```cpp 79 | txeo::Matrix large_matrix = generate_large_data(); 80 | auto normalized = normalizer.normalize(std::move(large_matrix)); 81 | ``` 82 | 83 | ### `Matrix normalize(const Matrix& x) const` 84 | 85 | Normalizes a matrix **by copy**. 86 | 87 | **Example:** 88 | 89 | ```cpp 90 | txeo::Matrix original = {{1.0}, {2.0}, {3.0}}; 91 | auto normalized = normalizer.normalize(original); 92 | ``` 93 | 94 | ### `Matrix x_train_normalized()` 95 | 96 | Returns normalized training data. 97 | 98 | **Example:** 99 | 100 | ```cpp 101 | auto x_train_norm = normalizer.x_train_normalized(); 102 | model.train(x_train_norm, normalizer.data_table().y_train()); 103 | ``` 104 | 105 | ### `Matrix x_eval_normalized()` 106 | 107 | Returns normalized evaluation data. 108 | 109 | **Example:** 110 | 111 | ```cpp 112 | auto x_eval_norm = normalizer.x_eval_normalized(); 113 | model.evaluate(x_eval_norm, normalizer.data_table().y_eval()); 114 | ``` 115 | 116 | ### `Matrix x_test_normalized()` 117 | 118 | Returns normalized test data. 119 | 120 | **Example:** 121 | 122 | ```cpp 123 | auto x_test_norm = normalizer.x_test_normalized(); 124 | model.test(x_test_norm, normalizer.data_table().y_test()); 125 | ``` 126 | 127 | ## Exceptions 128 | 129 | - `DataTableNormError`: Thrown if normalization parameters are invalid or data table is inconsistent. 130 | 131 | --- 132 | 133 | ## Notes 134 | 135 | - Normalization parameters are computed from training data only. 136 | - Be sure to properly configure your `DataTable` before using `DataTableNorm`. 137 | 138 | 139 | For detailed API references, see individual method documentation at [txeo::DataTableNorm](https://txeo-doc.netlify.app/classtxeo_1_1_data_table_norm.html). -------------------------------------------------------------------------------- /tests/tUtils.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "txeo/TensorShape.h" 11 | #include "txeo/detail/utils.h" 12 | #include "gtest/gtest.h" 13 | 14 | namespace tf = tensorflow; 15 | 16 | TEST(UtilsTest, TestTypes) { 17 | EXPECT_EQ(txeo::detail::get_tf_dtype(), tf::DT_INT16); 18 | EXPECT_EQ(txeo::detail::get_tf_dtype(), tf::DT_INT32); 19 | EXPECT_TRUE(txeo::detail::get_tf_dtype() == tf::DT_INT32 || 20 | txeo::detail::get_tf_dtype() == tf::DT_INT64); 21 | EXPECT_TRUE(txeo::detail::get_tf_dtype() == tf::DT_INT64); 22 | EXPECT_EQ(txeo::detail::get_tf_dtype(), tf::DT_FLOAT); 23 | EXPECT_EQ(txeo::detail::get_tf_dtype(), tf::DT_DOUBLE); 24 | EXPECT_EQ(txeo::detail::get_tf_dtype(), tf::DT_BOOL); 25 | EXPECT_EQ(txeo::detail::get_tf_dtype(), tf::DT_UINT64); 26 | 27 | EXPECT_EQ(txeo::detail::get_tf_dtype>(), tf::DT_INT16); 28 | EXPECT_EQ(txeo::detail::get_tf_dtype>(), tf::DT_INT32); 29 | EXPECT_TRUE(txeo::detail::get_tf_dtype>() == tf::DT_INT64); 30 | EXPECT_EQ(txeo::detail::get_tf_dtype>(), tf::DT_FLOAT); 31 | EXPECT_EQ(txeo::detail::get_tf_dtype>(), tf::DT_DOUBLE); 32 | EXPECT_EQ(txeo::detail::get_tf_dtype>(), tf::DT_BOOL); 33 | EXPECT_EQ(txeo::detail::get_tf_dtype>(), tf::DT_UINT64); 34 | } 35 | 36 | TEST(UtilsTest, ToInt64Valid) { 37 | size_t val = 42; 38 | EXPECT_EQ(txeo::detail::to_int64(val), 42); 39 | } 40 | 41 | TEST(UtilsTest, ToInt64Overflow) { 42 | size_t val = static_cast(std::numeric_limits::max()) + 1; 43 | EXPECT_THROW(txeo::detail::to_int64(val), std::overflow_error); 44 | } 45 | 46 | TEST(UtilsTest, ToSizeTValid) { 47 | int64_t val = 42; 48 | EXPECT_EQ(txeo::detail::to_size_t(val), 42); 49 | } 50 | 51 | TEST(UtilsTest, ToSizeTNegative) { 52 | int64_t val = -1; 53 | EXPECT_THROW(txeo::detail::to_size_t(val), std::overflow_error); 54 | } 55 | 56 | TEST(UtilsTest, ToSizeTVector) { 57 | std::vector input = {1, 2, 3}; 58 | std::vector expected = {1, 2, 3}; 59 | EXPECT_EQ(txeo::detail::to_size_t(input), expected); 60 | } 61 | 62 | TEST(UtilsTest, ToInt64Vector) { 63 | std::vector input = {1, 2, 3}; 64 | std::vector expected = {1, 2, 3}; 65 | EXPECT_EQ(txeo::detail::to_int64(input), expected); 66 | } 67 | 68 | TEST(UtilsTest, ToIntValid) { 69 | size_t val = 42; 70 | EXPECT_EQ(txeo::detail::to_int(val), 42); 71 | } 72 | 73 | TEST(UtilsTest, ToIntOverflow) { 74 | size_t val = static_cast(std::numeric_limits::max()) + 1; 75 | EXPECT_THROW(txeo::detail::to_int(val), std::overflow_error); 76 | } 77 | 78 | TEST(UtilsTest, ToInt64ToIntValid) { 79 | int64_t val = 42; 80 | EXPECT_EQ(txeo::detail::to_int(val), 42); 81 | } 82 | 83 | TEST(UtilsTest, ToInt64ToIntOverflow) { 84 | int64_t val = static_cast(std::numeric_limits::max()) + 1; 85 | EXPECT_THROW(txeo::detail::to_int(val), std::overflow_error); 86 | } 87 | 88 | TEST(UtilsTest, ToTxeoTensorShape) { 89 | tf::TensorShape tf_shape({2, 3, 4}); 90 | txeo::TensorShape txeo_shape = txeo::detail::to_txeo_tensor_shape(tf_shape); 91 | EXPECT_EQ(txeo::detail::to_size_t(txeo_shape.axes_dims()), std::vector({2, 3, 4})); 92 | } 93 | 94 | TEST(UtilsTest, CalcStride) { 95 | tf::TensorShape shape({3, 4, 5}); 96 | std::vector expected = {20, 5}; 97 | EXPECT_EQ(txeo::detail::calc_stride(shape), expected); 98 | } 99 | 100 | TEST(UtilsTest, CalcStrideSingleDim) { 101 | tf::TensorShape shape({5}); 102 | EXPECT_TRUE(txeo::detail::calc_stride(shape).empty()); 103 | } 104 | -------------------------------------------------------------------------------- /src/Loss.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/Loss.h" 2 | #include "txeo/Tensor.h" 3 | #include "txeo/TensorShape.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace txeo { 9 | 10 | template 11 | void Loss::set_loss(LossFunc func) { 12 | switch (func) { 13 | case LossFunc::MSE: 14 | _loss_func = [this](const Tensor &pred) -> T { return this->mse(pred); }; 15 | break; 16 | case LossFunc::MAE: 17 | _loss_func = [this](const Tensor &pred) -> T { return this->mae(pred); }; 18 | break; 19 | case LossFunc::MSLE: 20 | _loss_func = [this](const Tensor &pred) -> T { return this->msle(pred); }; 21 | break; 22 | case LossFunc::LCHE: 23 | _loss_func = [this](const Tensor &pred) -> T { return this->lche(pred); }; 24 | break; 25 | } 26 | } 27 | 28 | template 29 | Loss::Loss(Tensor &&valid, LossFunc func) : _label{std::move(valid)} { 30 | if (_label.dim() == 0) 31 | throw LossError("Tensor has dimension zero."); 32 | 33 | this->set_loss(func); 34 | } 35 | 36 | template 37 | void Loss::verify_parameter(const Tensor &pred) const { 38 | if (pred.dim() == 0) 39 | throw LossError("Tensor has dimension zero."); 40 | if (pred.shape() != _label.shape()) 41 | throw LossError("Incompatible shape."); 42 | } 43 | 44 | template 45 | T Loss::mean_squared_error(const Tensor &pred) const { 46 | this->verify_parameter(pred); 47 | 48 | T resp = 0; 49 | auto pred_flat = pred.data(); 50 | auto valid_flat = _label.data(); 51 | 52 | for (size_t i{0}; i < pred.dim(); ++i) { 53 | auto aux = pred_flat[i] - valid_flat[i]; 54 | resp += aux * aux; 55 | } 56 | 57 | return resp / pred.dim(); 58 | } 59 | 60 | template 61 | T Loss::mean_absolute_error(const Tensor &pred) const { 62 | this->verify_parameter(pred); 63 | 64 | T resp = 0; 65 | auto pred_flat = pred.data(); 66 | auto valid_flat = _label.data(); 67 | 68 | for (size_t i{0}; i < pred.dim(); ++i) 69 | resp += std::abs(pred_flat[i] - valid_flat[i]); 70 | 71 | return resp / pred.dim(); 72 | } 73 | 74 | template <> 75 | size_t Loss::mean_absolute_error(const Tensor &pred) const { 76 | this->verify_parameter(pred); 77 | 78 | size_t resp = 0; 79 | auto pred_flat = pred.data(); 80 | auto valid_flat = _label.data(); 81 | 82 | for (size_t i{0}; i < pred.dim(); ++i) { 83 | resp += 84 | pred_flat[i] > valid_flat[i] ? pred_flat[i] - valid_flat[i] : valid_flat[i] - pred_flat[i]; 85 | } 86 | 87 | return resp / pred.shape().axis_dim(0); 88 | } 89 | 90 | template 91 | T Loss::mean_squared_logarithmic_error(const Tensor &pred) const { 92 | this->verify_parameter(pred); 93 | 94 | T resp = 0; 95 | auto pred_flat = pred.data(); 96 | auto valid_flat = _label.data(); 97 | 98 | for (size_t i{0}; i < pred.dim(); ++i) { 99 | if (pred_flat[i] < 0 || valid_flat[i] < 0) 100 | throw LossError("A tensor element is negative."); 101 | 102 | auto aux = std::log1p(pred_flat[i]) - std::log1p(valid_flat[i]); 103 | resp += aux * aux; 104 | } 105 | 106 | return resp / pred.shape().axis_dim(0); 107 | } 108 | 109 | template 110 | T Loss::log_cosh_error(const Tensor &pred) const { 111 | 112 | this->verify_parameter(pred); 113 | 114 | T resp = 0; 115 | auto pred_flat = pred.data(); 116 | auto valid_flat = _label.data(); 117 | 118 | for (size_t i{0}; i < pred.dim(); ++i) 119 | resp += std::log(std::cosh(pred_flat[i] - valid_flat[i])); 120 | 121 | return resp / pred.shape().axis_dim(0); 122 | } 123 | 124 | template 125 | T Loss::get_loss(const Tensor &pred) const { 126 | return _loss_func(pred); 127 | } 128 | 129 | template class Loss; 130 | template class Loss; 131 | template class Loss; 132 | template class Loss; 133 | template class Loss; 134 | template class Loss; 135 | template class Loss; 136 | template class Loss; 137 | 138 | } // namespace txeo 139 | -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/tensor-op.md: -------------------------------------------------------------------------------- 1 | # TensorOp 2 | 3 | The `TensorOp` class provides utility methods for performing common mathematical operations on tensors, vectors, and matrices in the **txeo** library. 4 | 5 | --- 6 | 7 | ## Overview 8 | 9 | `TensorOp` offers a collection of static functions, including arithmetic operations, scalar operations, and higher-level linear algebra functions, specifically tailored to simplify tensor computations. 10 | 11 | --- 12 | 13 | ## API Reference 14 | 15 | | Method | Description | 16 | |----------------------------------|-----------------------------------------------------------| 17 | | `divide(tensor, scalar)` | Scalar division | 18 | | `dot(matrix1, matrix2)` | Matrix multiplication | 19 | | `hadamard_prod(tensor1, tensor2)`| Element-wise multiplication | 20 | | `inner(vector1, vector2)` | Computes the inner product of two vectors | 21 | | `multiply(tensor, scalar)` | Scalar multiplication | 22 | | `subtract(tensor1, tensor2)` | Element-wise subtraction | 23 | | `sum(tensor, scalar)` | Adds scalar to each tensor element | 24 | | `sum(tensor1, tensor2)` | Element-wise sum | 25 | 26 | --- 27 | 28 | ## Arithmetic Operations 29 | 30 | ### Sum 31 | 32 | Sum two tensors element-wise: 33 | 34 | ```cpp 35 | #include "txeo/Tensor.h" 36 | #include "txeo/TensorOp.h" 37 | 38 | int main() { 39 | txeo::Tensor a({2,2}, {1,2,3,4}); 40 | txeo::Tensor b({2,2}, {5,6,7,8}); 41 | 42 | auto result = txeo::TensorOp::sum(a, b); 43 | // result: [6, 8, 10, 12] 44 | } 45 | ``` 46 | 47 | ### Subtraction Operations 48 | 49 | Element-wise subtraction: 50 | 51 | ```cpp 52 | txeo::Tensor result = txeo::TensorOp::subtract(a, b); 53 | ``` 54 | 55 | ### Scalar Operations 56 | 57 | - **Addition:** `TensorOp::sum(tensor, scalar)` 58 | - **Subtraction:** `TensorOp::subtract(tensor, scalar)` 59 | - **Multiplication:** `TensorOp::multiply(tensor, scalar)` 60 | - **Division:** `TensorOp::divide(tensor, scalar)` 61 | 62 | Example: 63 | 64 | ```cpp 65 | txeo::Tensor tensor({3}, {1.0f, 2.0f, 3.0f}); 66 | auto result = txeo::TensorOp::multiply(tensor, 2.0f); // [2.0, 4.0, 6.0] 67 | ``` 68 | 69 | ### Hadamard Product (Element-wise multiplication) 70 | 71 | ```cpp 72 | txeo::Tensor result = txeo::TensorOp::hadamard_prod(tensor1, tensor2); 73 | ``` 74 | 75 | --- 76 | 77 | ## Matrix Operations 78 | 79 | ### Matrix Multiplication 80 | 81 | ```cpp 82 | txeo::Matrix mat1(2, 3, {1, 2, 3, 4, 5, 6}); 83 | txeo::Matrix mat2(3, 2, {7, 8, 9, 10, 11, 12}); 84 | 85 | auto result = txeo::TensorOp::dot(mat1, mat2); // [[58, 64], [139, 154]] 86 | ``` 87 | 88 | ### Vector Dot Product 89 | 90 | ```cpp 91 | txeo::Vector vec1({1, 2, 3}); 92 | txeo::Vector vec2({4, 5, 6}); 93 | 94 | int dot_product = txeo::TensorOp::inner(vec1, vec2); // 32 95 | ``` 96 | 97 | --- 98 | 99 | ## Exception Handling 100 | 101 | Operations that violate tensor shape constraints throw `TensorOpError`: 102 | 103 | ```cpp 104 | try { 105 | auto result = txeo::TensorOp::sum(tensor1, incompatible_tensor); 106 | } catch (const txeo::TensorOpError &e) { 107 | std::cerr << e.what() << std::endl; 108 | } 109 | ``` 110 | 111 | --- 112 | 113 | ## Examples 114 | 115 | ### Tensor Arithmetic 116 | 117 | ```cpp 118 | #include "txeo/Tensor.h" 119 | #include "txeo/TensorOp.h" 120 | 121 | int main() { 122 | txeo::Tensor t1({2}, {1.5, 2.5}); 123 | auto result = txeo::TensorOp::sum(t1, 4.5); 124 | std::cout << result << std::endl; 125 | } 126 | ``` 127 | 128 | --- 129 | 130 | For detailed API references, see individual method documentation at [txeo::TensorOp](https://txeo-doc.netlify.app/classtxeo_1_1_tensor_op.html). 131 | -------------------------------------------------------------------------------- /include/txeo/Logger.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGER_H 2 | #define LOGGER_H 3 | #pragma once 4 | 5 | #include 6 | 7 | namespace txeo { 8 | 9 | /** 10 | * @enum LogLevel 11 | * @brief Defines severity levels for log messages 12 | * 13 | * Ordered from most verbose to most critical: 14 | * @li DEBUG - Diagnostic information for developers 15 | * @li INFO - General operational messages 16 | * @li WARNING - Indicates potential issues 17 | * @li ERROR - Critical problems requiring attention 18 | */ 19 | enum class LogLevel { DEBUG, INFO, WARNING, ERROR }; 20 | 21 | /** 22 | * @class Logger 23 | * @brief Abstract base class for logging subsystems 24 | * 25 | * Provides common interface and functionality for concrete loggers. 26 | * Supports severity filtering and global enable/disable. 27 | * 28 | * @note Inherit from this class to create specific logger implementations 29 | * 30 | * **Example Usage:** 31 | * @code 32 | * class ConsoleLogger : public Logger { 33 | * protected: 34 | * void write(LogLevel level, const std::string& message) override { 35 | * std::cout << "[" << log_level_str(level) << "] " << message << "\n"; 36 | * } 37 | * }; 38 | * 39 | * ConsoleLogger logger; 40 | * logger.set_output_level(LogLevel::INFO); 41 | * logger.info("Application started"); 42 | * logger.debug("This won't be shown"); // Filtered by output level 43 | * @endcode 44 | */ 45 | class Logger { 46 | public: 47 | Logger(const Logger &) = delete; 48 | Logger(Logger &&) = delete; 49 | Logger &operator=(const Logger &) = delete; 50 | Logger &operator=(Logger &&) = delete; 51 | virtual ~Logger() = default; 52 | 53 | /** 54 | * @brief Main logging method 55 | * @param level Severity level of the message 56 | * @param message Content to log 57 | * 58 | * @note Respects both output level and enabled state 59 | */ 60 | void log(txeo::LogLevel level, const std::string &message); 61 | 62 | /** 63 | * @brief Enable logging operations 64 | */ 65 | void turn_on() { _is_turned_on = true; }; 66 | 67 | /** 68 | * @brief Disable all logging output 69 | */ 70 | void turn_off() { _is_turned_on = false; }; 71 | 72 | /** 73 | * @brief Get current output level threshold 74 | * @return Active LogLevel filter 75 | */ 76 | [[nodiscard]] txeo::LogLevel output_level() const { return _output_level; } 77 | 78 | /** 79 | * @brief Set minimum logging level to output 80 | * @param output_level Messages below this level will be filtered 81 | * 82 | * **Example Usage:** 83 | * @code 84 | * logger.set_output_level(LogLevel::WARNING); // Only show WARNING+ 85 | * @endcode 86 | */ 87 | void set_output_level(txeo::LogLevel output_level) { _output_level = output_level; } 88 | 89 | /** 90 | * @brief Log DEBUG level message 91 | * @param message Diagnostic information 92 | */ 93 | void debug(const std::string &message); 94 | 95 | /** 96 | * @brief Log INFO level message 97 | * @param message Operational status update 98 | */ 99 | void info(const std::string &message); 100 | 101 | /** 102 | * @brief Log WARNING level message 103 | * @param message Potential issue notification 104 | */ 105 | void warning(const std::string &message); 106 | 107 | /** 108 | * @brief Log ERROR level message 109 | * @param message Critical error report 110 | */ 111 | void error(const std::string &message); 112 | 113 | protected: 114 | Logger() = default; 115 | bool _is_turned_on{true}; 116 | txeo::LogLevel _output_level{txeo::LogLevel::DEBUG}; 117 | 118 | static std::string log_level_str(txeo::LogLevel level); 119 | 120 | /** 121 | * @brief Abstract write operation 122 | * @param level Message severity level 123 | * @param message Formatted log content 124 | * 125 | * @note Must be implemented in derived classes 126 | */ 127 | virtual void write(txeo::LogLevel level, const std::string &message) = 0; 128 | }; 129 | 130 | } // namespace txeo 131 | #endif -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/vector.md: -------------------------------------------------------------------------------- 1 | # Vector 2 | 3 | The `Vector` class in **txeo** is a specialized subclass of `txeo::Tensor`, specifically designed for first-order tensors, providing a straightforward interface for vector operations. 4 | 5 | --- 6 | 7 | ## Overview 8 | 9 | The `Vector` class simplifies handling 1st-order tensor operations, offering intuitive constructors, easy initialization methods, and seamless conversion between vectors and general tensors. 10 | 11 | --- 12 | 13 | ## API Reference 14 | 15 | | Method | Description | 16 | |---------------------------------|-------------------------------------------------------| 17 | | `normalize(type)` | Normalize this vector according to a normalization type | 18 | | `reshape(shape)` | Changes the shape of the vector | 19 | | `to_tensor(vector)` | Converts a vector to tensor (copy/move) | 20 | | `to_vector(tensor)` | Converts a first-order tensor to vector (copy/move) | 21 | 22 | --- 23 | 24 | ## Creating Vectors 25 | 26 | ### Basic Construction 27 | 28 | Create an uninitialized vector by specifying its dimension: 29 | 30 | ```cpp 31 | #include 32 | #include "txeo/Vector.h" 33 | 34 | int main() { 35 | txeo::Vector vector(3); // Creates a vector of size 3 36 | std::cout << vector << std::endl; 37 | } 38 | ``` 39 | 40 | ### Initialization with Specific Values 41 | 42 | ```cpp 43 | txeo::Vector vector(3, 5); // Creates a vector of size 3 filled with 5 44 | ``` 45 | 46 | ### Initialization from Vector 47 | 48 | ```cpp 49 | txeo::Vector vector(3, {1.0, 2.0, 3.0}); 50 | ``` 51 | 52 | ### Initialization Using Initializer Lists 53 | 54 | ```cpp 55 | txeo::Vector vector({1, 2, 3}); // Vector of size 3 56 | ``` 57 | 58 | --- 59 | 60 | ## Conversion between Vector and Tensor 61 | 62 | ### Tensor to Vector 63 | 64 | ```cpp 65 | txeo::Tensor tensor({4}, {1, 2, 3, 4}); 66 | auto vector = txeo::Vector::to_vector(std::move(tensor)); 67 | ``` 68 | 69 | ### Vector to Tensor 70 | 71 | ```cpp 72 | txeo::Vector vector({1, 2, 3, 4}); 73 | // Copy semantics 74 | txeo::Tensor tensor = txeo::Vector::to_tensor(vector); 75 | ``` 76 | 77 | ```cpp 78 | // Using move semantics 79 | txeo::Tensor tensor = txeo::Vector::to_tensor(std::move(vector)); 80 | ``` 81 | 82 | ### Vector to Tensor (Move Constructor) 83 | 84 | ```cpp 85 | txeo::Tensor tensor({1, 2, 3, 4}); 86 | txeo::Vector vector(std::move(tensor)); 87 | ``` 88 | 89 | --- 90 | 91 | ## Normalization 92 | 93 | ### Min-Max 94 | 95 | ```cpp 96 | Vector vec({2.0, 4.0, 6.0}); 97 | vec.normalize(txeo::NormalizationType::MIN_MAX); 98 | // vec becomes [0.0, 0.5, 1.0] (original min=2, max=6) 99 | ``` 100 | 101 | ### Z-Score 102 | 103 | ```cpp 104 | Vector v({2.0f, 4.0f, 6.0f}); 105 | v.normalize(txeo::NormalizationType::Z_SCORE); 106 | // v becomes approximately [-1.2247, 0.0, 1.2247] 107 | // (μ=4.0, σ≈1.63299) 108 | ``` 109 | 110 | ## Exception Handling 111 | 112 | Invalid vector operations throw `VectorError` exceptions: 113 | 114 | ```cpp 115 | try { 116 | txeo::Tensor tensor({2, 2}, {1, 2, 3, 4}); 117 | // Throws VectorError 118 | auto vector = txeo::Vector::to_vector(std::move(tensor)); 119 | } catch (const txeo::VectorError &e) { 120 | std::cerr << e.what() << std::endl; 121 | } 122 | ``` 123 | 124 | --- 125 | 126 | ## Examples 127 | 128 | ### Vector Arithmetic Operations 129 | 130 | ```cpp 131 | #include 132 | #include "txeo/Vector.h" 133 | 134 | int main() { 135 | txeo::Vector vec1({1, 2, 3}); 136 | auto vec2 = vec1 * 2; // Scalar multiplication 137 | 138 | std::cout << "Resulting vector: " << vec2 << std::endl; 139 | } 140 | ``` 141 | 142 | ### Accessing and Modifying Vector Elements 143 | 144 | ```cpp 145 | vec1(0) = 10; // Sets the first element to 10 146 | ``` 147 | 148 | --- 149 | 150 | For detailed API references, see individual method documentation at [txeo::Vector](https://txeo-doc.netlify.app/classtxeo_1_1_vector.html). 151 | -------------------------------------------------------------------------------- /examples/txeo_shapes.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/TensorShape.h" 2 | #include 3 | 4 | int main() { 5 | try { 6 | // -------------------------- 7 | // 1. Construction Examples 8 | // -------------------------- 9 | std::cout << "=== Construction Examples ===\n"; 10 | 11 | // Empty shape (scalar) 12 | txeo::TensorShape scalar_shape({}); 13 | std::cout << "Scalar shape: " << scalar_shape << "\n"; 14 | 15 | // Uniform dimensions 16 | txeo::TensorShape uniform_shape(3, 5); // 3 axes, each dim 5 17 | std::cout << "Uniform shape: " << uniform_shape << "\n"; 18 | 19 | // From vector 20 | std::vector vec_dims{2, 3, 4}; 21 | txeo::TensorShape vector_shape(vec_dims); 22 | std::cout << "Vector constructed shape: " << vector_shape << "\n"; 23 | 24 | // From initializer list 25 | txeo::TensorShape init_list_shape({4, 5, 6}); 26 | std::cout << "Initializer list shape: " << init_list_shape << "\n"; 27 | 28 | // -------------------------- 29 | // 2. Shape Manipulation 30 | // -------------------------- 31 | std::cout << "\n=== Shape Manipulation ===\n"; 32 | 33 | txeo::TensorShape dynamic_shape({2, 3}); 34 | std::cout << "Original shape: " << dynamic_shape << "\n"; 35 | 36 | // Add axis at end 37 | dynamic_shape.push_axis_back(4); 38 | std::cout << "After push_back(4): " << dynamic_shape << "\n"; 39 | 40 | // Insert axis at position 1 41 | dynamic_shape.insert_axis(1, 5); 42 | std::cout << "After insert(1, 5): " << dynamic_shape << "\n"; 43 | 44 | // Remove axis at position 2 45 | dynamic_shape.remove_axis(2); 46 | std::cout << "After remove(2): " << dynamic_shape << "\n"; 47 | 48 | // Modify existing dimension 49 | dynamic_shape.set_dim(1, 7); 50 | std::cout << "After set_dim(1,7): " << dynamic_shape << "\n"; 51 | 52 | // -------------------------- 53 | // 3. Shape Inspection 54 | // -------------------------- 55 | std::cout << "\n=== Shape Inspection ===\n"; 56 | 57 | const txeo::TensorShape shape({2, 3, 4}); 58 | std::cout << "Inspecting shape: " << shape << "\n"; 59 | 60 | // Access individual dimensions 61 | std::cout << "Axis 0 dim: " << shape.axis_dim(0) << "\n"; 62 | std::cout << "Axis 1 dim: " << shape.axis_dim(1) << "\n"; 63 | std::cout << "Axis 2 dim: " << shape.axis_dim(2) << "\n"; 64 | 65 | // Get all dimensions 66 | auto dims = shape.axes_dims(); 67 | std::cout << "All dimensions: "; 68 | for (auto d : dims) 69 | std::cout << d << " "; 70 | std::cout << "\n"; 71 | 72 | // Memory stride calculation 73 | auto strides = shape.stride(); 74 | std::cout << "Memory strides: "; 75 | for (auto s : strides) 76 | std::cout << s << " "; 77 | std::cout << "\n"; 78 | 79 | // -------------------------- 80 | // 4. Advanced Operations 81 | // -------------------------- 82 | std::cout << "\n=== Advanced Operations ===\n"; 83 | 84 | // Capacity calculation 85 | std::cout << "Total elements: " << shape.calculate_capacity() << "\n"; 86 | 87 | // Cloning 88 | auto cloned_shape = shape.clone(); 89 | cloned_shape.set_dim(0, 5); 90 | std::cout << "Original: " << shape << "\n"; 91 | std::cout << "Modified clone: " << cloned_shape << "\n"; 92 | 93 | // Validity checks 94 | std::cout << "Is fully defined? " << std::boolalpha << shape.is_fully_defined() << "\n"; 95 | 96 | // -------------------------- 97 | // 5. Error Handling 98 | // -------------------------- 99 | std::cout << "\n=== Error Handling ===\n"; 100 | 101 | try { 102 | txeo::TensorShape invalid_shape(0, 5); // 0 axes 103 | } catch (const txeo::TensorShapeError &e) { 104 | std::cout << "Caught error: " << e.what() << "\n"; 105 | } 106 | 107 | try { 108 | auto aux = dynamic_shape.axis_dim(10); // Invalid axis 109 | std::cout << aux << std::endl; 110 | } catch (const txeo::TensorShapeError &e) { 111 | std::cout << "Caught error: " << e.what() << "\n"; 112 | } 113 | 114 | } catch (const std::exception &e) { 115 | std::cerr << "Error: " << e.what() << "\n"; 116 | return 1; 117 | } 118 | 119 | return 0; 120 | } -------------------------------------------------------------------------------- /tests/tTensorShape.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "txeo/TensorShape.h" 10 | 11 | namespace txeo { 12 | 13 | TEST(TensorShapeTest, ConstructorNumberOfAxesDim) { 14 | TensorShape shape(3, 4); 15 | EXPECT_EQ(shape.number_of_axes(), 3); 16 | EXPECT_EQ(shape.axis_dim(0), 4); 17 | EXPECT_EQ(shape.axis_dim(1), 4); 18 | EXPECT_EQ(shape.axis_dim(2), 4); 19 | } 20 | 21 | TEST(TensorShapeTest, ConstructorVector) { 22 | TensorShape shape({1, 3, 5}); 23 | EXPECT_EQ(shape.number_of_axes(), 3); 24 | EXPECT_EQ(shape.axis_dim(0), 1); 25 | EXPECT_EQ(shape.axis_dim(1), 3); 26 | EXPECT_EQ(shape.axis_dim(2), 5); 27 | EXPECT_EQ(shape.stride(), std::vector({15, 5})); 28 | } 29 | 30 | TEST(TensorShapeTest, CopySemantics) { 31 | TensorShape original({2, 3, 5}); 32 | TensorShape copy(original); 33 | EXPECT_EQ(copy, original); 34 | 35 | TensorShape copy_assigned = original; 36 | EXPECT_EQ(copy_assigned, original); 37 | 38 | TensorShape original2({22, 33, 55}); 39 | copy = original2; 40 | EXPECT_EQ(copy, original2); 41 | } 42 | 43 | TEST(TensorShapeTest, MoveSemantics) { 44 | TensorShape original({2, 4, 6}); 45 | TensorShape moved(std::move(original)); 46 | EXPECT_EQ(moved.number_of_axes(), 3); 47 | EXPECT_EQ(moved.axis_dim(1), 4); 48 | 49 | TensorShape move_assigned = std::move(moved); 50 | EXPECT_EQ(move_assigned.number_of_axes(), 3); 51 | } 52 | 53 | TEST(TensorShapeTest, AxisAccess) { 54 | TensorShape shape({2, 3, 5}); 55 | EXPECT_EQ(shape.axis_dim(1), 3); 56 | EXPECT_THROW( 57 | { 58 | auto result = shape.axis_dim(3); 59 | (void)result; 60 | }, 61 | TensorShapeError); 62 | EXPECT_THROW( 63 | { 64 | auto result = shape.axis_dim(-1); 65 | (void)result; 66 | }, 67 | TensorShapeError); 68 | } 69 | 70 | TEST(TensorShapeTest, AxesDims) { 71 | TensorShape shape({2, 3, 5}); 72 | auto dims = shape.axes_dims(); 73 | ASSERT_EQ(dims.size(), 3); 74 | EXPECT_EQ(dims[0], 2); 75 | EXPECT_EQ(dims[1], 3); 76 | EXPECT_EQ(dims[2], 5); 77 | } 78 | 79 | TEST(TensorShapeTest, ShapeModifications) { 80 | TensorShape shape({1, 2}); 81 | 82 | shape.push_axis_back(3); 83 | EXPECT_EQ(shape.number_of_axes(), 3); 84 | EXPECT_EQ(shape.axis_dim(2), 3); 85 | 86 | shape.insert_axis(1, 4); 87 | EXPECT_EQ(shape.axes_dims(), std::vector({1, 4, 2, 3})); 88 | 89 | shape.remove_axis(2); 90 | EXPECT_EQ(shape.axes_dims(), std::vector({1, 4, 3})); 91 | 92 | shape.set_dim(1, 5); 93 | EXPECT_EQ(shape.axis_dim(1), 5); 94 | 95 | TensorShape empty_shape(0, 0); 96 | EXPECT_EQ(empty_shape.stride(), std::vector({})); 97 | EXPECT_THROW(shape.insert_axis(5, 2), TensorShapeError); 98 | EXPECT_THROW(shape.remove_axis(5), TensorShapeError); 99 | EXPECT_THROW(shape.set_dim(5, 2), TensorShapeError); 100 | 101 | shape.remove_all_axes(); 102 | EXPECT_TRUE(shape.axes_dims().empty()); 103 | } 104 | 105 | TEST(TensorShapeTest, ComparisonOperators) { 106 | TensorShape shape1(3, 4); 107 | TensorShape shape2({4, 4, 4}); 108 | TensorShape shape3({2, 3, 5}); 109 | 110 | EXPECT_TRUE(shape1 == shape2); 111 | EXPECT_FALSE(shape1 != shape2); 112 | EXPECT_TRUE(shape1 != shape3); 113 | EXPECT_FALSE(shape1 == shape3); 114 | } 115 | 116 | TEST(TensorShapeTest, FullyDefinedCheck) { 117 | TensorShape defined_shape({2, 3, 5}); 118 | 119 | EXPECT_TRUE(defined_shape.is_fully_defined()); 120 | } 121 | 122 | TEST(TensorShapeTest, StreamOperator) { 123 | TensorShape shape({2, 3, 5}); 124 | std::stringstream ss; 125 | ss << shape; 126 | EXPECT_EQ(ss.str(), "[2,3,5]"); 127 | } 128 | 129 | TEST(TensorShapeTest, NumberOfElements) { 130 | TensorShape shape({2, 3, 5, 6}); 131 | 132 | EXPECT_EQ(shape.stride(), std::vector({90, 30, 6})); 133 | EXPECT_EQ(shape.calculate_capacity(), 2 * 3 * 5 * 6); 134 | } 135 | 136 | TEST(TensorShapeTest, EmptyShape) { 137 | TensorShape empty_shape(0, 0); 138 | EXPECT_EQ(empty_shape.number_of_axes(), 0); 139 | EXPECT_EQ(empty_shape.calculate_capacity(), 1); 140 | EXPECT_TRUE(empty_shape.is_fully_defined()); 141 | } 142 | 143 | } // namespace txeo -------------------------------------------------------------------------------- /mkdocs/docs/usage.md: -------------------------------------------------------------------------------- 1 | # Basic Usage 2 | 3 | This section provides **two simple C++ examples** to help you get started with **txeo**. 4 | 5 | > **📌 Prerequisite:** Before compiling, ensure that TensorFlow and **txeo** are properly installed in `/opt/`. 6 | > If necessary, add the library paths: 7 | > 8 | > ```sh 9 | > export LD_LIBRARY_PATH=/opt/tensorflow/lib:/opt/txeo/lib:$LD_LIBRARY_PATH 10 | > ``` 11 | 12 | ## A Simple CMakeLists.txt 13 | 14 | To compile a project using **txeo**, use the following **CMakeLists.txt** file. 15 | 16 | ```cmake 17 | # CMakeLists.txt 18 | cmake_minimum_required(VERSION 3.25) 19 | project(HelloTxeo LANGUAGES CXX) 20 | 21 | # Set C++ standard 22 | set(CMAKE_CXX_STANDARD 20) 23 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 24 | 25 | # Manually specify Txeo installation paths 26 | set(TXEO_INCLUDE_DIR "/opt/txeo/include") 27 | set(TXEO_LIBRARY "/opt/txeo/lib/libtxeo.so") 28 | 29 | # Manually specify TensorFlow paths 30 | set(TENSORFLOW_INCLUDE_DIR "/opt/tensorflow/include") 31 | set(TENSORFLOW_CC_LIBRARY "/opt/tensorflow/lib/libtensorflow_cc.so") 32 | set(TENSORFLOW_FRAMEWORK "/opt/tensorflow/lib/libtensorflow_framework.so") 33 | 34 | # Create an executable 35 | add_executable(hello_txeo main.cpp) 36 | 37 | # Include directories for Txeo and TensorFlow 38 | target_include_directories(hello_txeo PRIVATE ${TXEO_INCLUDE_DIR} ${TENSORFLOW_INCLUDE_DIR}) 39 | 40 | # Link Txeo and TensorFlow manually 41 | target_link_libraries(hello_txeo PRIVATE ${TXEO_LIBRARY} ${TENSORFLOW_CC_LIBRARY} ${TENSORFLOW_FRAMEWORK}) 42 | 43 | # Optionally set rpath for runtime library search 44 | set_target_properties(hello_txeo PROPERTIES INSTALL_RPATH "/opt/txeo/lib;/opt/tensorflow/lib") 45 | ``` 46 | 47 | 💡 Note: If TensorFlow is installed in a different location, update TENSORFLOW_INCLUDE_DIR and TENSORFLOW_LIBRARY paths accordingly. 48 | 49 | ## Example 1: Tensor Basics 50 | 51 | Here is a code sample where a 3x3 `txeo::Matrix` is defined, written to a file and then another instance is created from the saved file. 52 | 53 | ```cpp 54 | //main.cpp 55 | #include "txeo/Tensor.h" 56 | #include "txeo/MatrixIO.h" 57 | #include 58 | 59 | using namespace txeo; 60 | using namespace std; 61 | 62 | int main() { 63 | 64 | // 3×3 matrix created from a list of double values in row-major order 65 | Matrix matrix({3, 3}, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f}); 66 | 67 | // Save matrix to file 68 | MatrixIO::write_textfile(matrix, "matrix.txt"); 69 | 70 | // Load matrix from file 71 | auto loaded_matrix = MatrixIO::read_textfile("matrix.txt"); 72 | 73 | // Convert matrix to second-order tensor 74 | auto loaded_tensor = Matrix::to_tensor(loaded_matrix); 75 | 76 | // Reshape second-order tensor to first-order 77 | loaded_tensor.reshape({9}); 78 | 79 | // Display loaded tensor 80 | cout << loaded_tensor << endl; 81 | 82 | return 0; 83 | } 84 | ``` 85 | 86 | ## Example 2: Running Inference with a Saved Model 87 | 88 | This example loads a saved TensorFlow model, performs inference on an input tensor, and saves the output: 89 | 90 | ```cpp 91 | //main.cpp 92 | #include "txeo/Predictor.h" 93 | #include "txeo/Tensor.h" 94 | #include "txeo/MatrixIO.h" 95 | 96 | using namespace txeo; 97 | using namespace std; 98 | 99 | int main() { 100 | 101 | // Define paths to model and input/output tensors 102 | string model_path{"path/to/saved_model"}; 103 | string input_path{"path/to/input_tensor.txt"}; 104 | string output_path{"path/to/output_tensor.txt"}; 105 | 106 | // Load the model 107 | Predictor predictor{model_path}; 108 | 109 | // Read input tensor from file 110 | auto input = MatrixIO::read_textfile(input_path); 111 | 112 | // Run inference 113 | auto output = predictor.predict(input); 114 | 115 | // Save output tensor to file 116 | MatrixIO::write_textfile(output, output_path); 117 | 118 | return 0; 119 | } 120 | ``` 121 | 122 | 💡 Note: Ensure that "path/to/saved_model" contains a valid TensorFlow model before running this example. 123 | 124 | 📁 For more samples, please visit the [examples folder](https://github.com/rdabra/txeo/tree/main/examples). 125 | 126 | 👓 Doxygen Documentation with extensive usage examples is hosted at [Netlify](https://txeo-doc.netlify.app/). 127 | -------------------------------------------------------------------------------- /mkdocs/docs/index.md: -------------------------------------------------------------------------------- 1 |

2 | txeo logo 3 |

4 | 5 | # Welcome to txeo Library Documentation 6 | 7 | **txeo** is a lightweight and intuitive **C++ wrapper for TensorFlow**, designed to **simplify TensorFlow C++ development** while preserving **high performance and flexibility**. Built entirely with **Modern C++**, **txeo** allows developers to use TensorFlow with the ease of a high-level API, eliminating the complexity of its low-level C++ interface. 8 | 9 | **txeo** is an open-source library hosted at [**Github**](https://github.com/rdabra/txeo). 10 | 11 | --- 12 | 13 | ## Main Features 14 | 15 | - 📦 **Intuitive API** – A clean and modern C++ interface, simplifying TensorFlow C++ usage. 16 | - 🔧 **High-Level Tensor Abstraction** – Easily create, manipulate, and operate on tensors. 17 | - 💾 **Flexible Tensor IO** – Seamless reading and writing of tensors to text files. 18 | - 🏗 **Simplified Model Loading** – Load and run saved TensorFlow models with minimal setup. 19 | - ⚡ **XLA Acceleration** – Effortlessly enable or disable TensorFlow’s XLA optimizations. 20 | - 🚀 **Near-Native Performance** – Achieves **99.35% to 99.79% of native TensorFlow speed** with negligible overhead. 21 | - 🛡 **Encapsulated TensorFlow API** – Fully abstracts TensorFlow internals for a cleaner, more maintainable experience. 22 | 23 | --- 24 | 25 | ## Performance Comparison 26 | 27 | **txeo** was benchmarked against the native **TensorFlow C++ API** using inference from a saved **multiclassification convolution model**. 28 | 29 | - **Model and other info:** 30 | - **279,610 parameters** 31 | - **1 Softmax Output Layer** with 10 classes 32 | - **3 Fully-Connected ReLU Convolutional Layers** with 200 nodes each 33 | - **Input**: 210,000 grayscale images (28×28). 34 | - **CPU**: AMD Ryzen 7 5700X CPU 35 | - **TensorFlow**: Compiled with CPU optimization 36 | 37 | ### **Results Overview** 38 | 39 | | Compiler | txeo (μs) | TensorFlow C++ (μs) | Difference (%) | 40 | |----------|-----------|-----------------|----------------| 41 | | GCC | 233,994 | 232,494 | +0.65% | 42 | | Intel | 234,489 | 232,683 | +0.78% | 43 | | Clang | 236,858 | 234,016 | +1.21% | 44 | 45 | - The performance overhead is **negligible**, ranging from **0.65% to 1.21%**. 46 | - **txeo’s abstraction layer** provides **ease of use** with almost no cost to performance. 47 | 48 | --- 49 | 50 | ## Roadmap 51 | 52 | **txeo** is actively evolving! Here are some of the upcoming features: 53 | 54 | ### 🏋️ Training Capabilities 55 | 56 | - **Model Training** - Enable training models using TensorFlow C++. 57 | - **Backpropagation Support** - Implement automatic differentiation. 58 | - **Gradient Descent & Optimizers** - Integrate optimizers like SGD and Adam. 59 | 60 | ### 🔢 Advanced Tensor Operations 61 | 62 | - **Linear Algebra Functions (SVD, QR decomposition)** - Matrix Computations on tensors. 63 | 64 | ### 📊 Model Saving & Loading Enhancements 65 | 66 | - **Checkpointing** - Save model weights at different training stages. 67 | - **Frozen Graph Support** - Load & optimize frozen models for inference. 68 | 69 | ## 📬 Contact 70 | 71 | For any inquiries or contributions: 72 | 73 | - **GitHub Discussions:** [Start a discussion](https://github.com/rdabra/txeo/discussions) 74 | - **Issue Reporting:** [Open an issue](https://github.com/rdabra/txeo/issues) 75 | - **Email:** [robertodias70@outlook.com](mailto:robertodias70@outlook.com) *(for serious inquiries only)* 76 | 77 | --- 78 | 79 | ## License 80 | 81 | **txeo** is licensed under the **Apache License 2.0**, meaning it is **open-source, free to use, modify, and distribute**, while requiring proper attribution. 82 | 83 | ### 📄 Third-Party Licenses 84 | 85 | **txeo** depends on third-party libraries that have their own licenses: 86 | 87 | - **TensorFlow C++** - Licensed under **Apache License 2.0** 88 | - 📜 [TensorFlow License](third_party/tensorflow/LICENSE) 89 | - 🔗 [TensorFlow GitHub](https://github.com/tensorflow/tensorflow) 90 | - **Protobuf** - Licensed under **BSD 3-Clause** 91 | - 📜 [Protobuf License](https://github.com/protocolbuffers/protobuf/blob/main/LICENSE) 92 | 93 | > **📌 Note:** The precompiled binaries of TensorFlow and Protobuf provided in the releases section **are unmodified versions** of the official source code. 94 | -------------------------------------------------------------------------------- /examples/txeo_tensorio.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/MatrixIO.h" 2 | #include 3 | #include 4 | 5 | int main() { 6 | // ====================================================================================== 7 | // 1. Basic File Reading (Static Method) 8 | // ====================================================================================== 9 | { 10 | std::cout << "\n=== 1. Reading CSV with Header ===\n"; 11 | try { 12 | auto data = txeo::MatrixIO::read_textfile("data.csv", // Assume this file exists 13 | ',', 14 | true // Skip header row 15 | ); 16 | std::cout << "CSV Tensor shape: " << data.shape() << "\n" 17 | << "First 3 elements: " << data(0, 0) << ", " << data(0, 1) << ", " << data(0, 2) 18 | << "\n"; 19 | } catch (const txeo::MatrixIOError &e) { 20 | std::cerr << "Read error: " << e.what() << "\n"; 21 | } 22 | } 23 | 24 | // ====================================================================================== 25 | // 2. Reading TSV Without Header (Instance Method) 26 | // ====================================================================================== 27 | { 28 | std::cout << "\n=== 2. Reading TSV Without Header ===\n"; 29 | txeo::MatrixIO reader("data.tsv", '\t'); // Tab-separated 30 | 31 | try { 32 | auto tensor = reader.read_text_file(); 33 | std::cout << "TSV Tensor:\n" << tensor << "\n"; 34 | } catch (const txeo::MatrixIOError &e) { 35 | std::cerr << "Read error: " << e.what() << "\n"; 36 | } 37 | } 38 | 39 | // ====================================================================================== 40 | // 3. Basic File Writing (Static Method) 41 | // ====================================================================================== 42 | { 43 | std::cout << "\n=== 3. Writing CSV ===\n"; 44 | txeo::Matrix matrix{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 45 | 46 | txeo::MatrixIO::write_textfile(matrix, "output_matrix.csv", 47 | ',' // CSV format 48 | ); 49 | std::cout << "Wrote 3x3 matrix to output_matrix.csv\n"; 50 | } 51 | 52 | // ====================================================================================== 53 | // 4. Precision Writing for Floating Points 54 | // ====================================================================================== 55 | { 56 | std::cout << "\n=== 4. Precision Writing ===\n"; 57 | txeo::Matrix measurements{{std::numbers::pi, std::numbers::e}, 58 | {std::numbers::phi, std::numbers::egamma}}; 59 | 60 | txeo::MatrixIO::write_textfile(measurements, 61 | 4, // 4 decimal places 62 | "precision_data.csv"); 63 | std::cout << "Wrote double tensor with 4-digit precision\n"; 64 | } 65 | 66 | // ====================================================================================== 67 | // 5. Instance-Based Writing with Custom Format 68 | // ====================================================================================== 69 | { 70 | std::cout << "\n=== 5. Custom Format Writing ===\n"; 71 | txeo::Matrix sensor_data{{25.4f, 18.9f, 30.1f}, {22.5f, 19.8f, 28.7f}}; 72 | 73 | txeo::MatrixIO writer("sensor_data.psv", '|'); 74 | try { 75 | writer.write_text_file(sensor_data, 1); // 1 decimal place 76 | std::cout << "Created pipe-separated file with 1 decimal precision\n"; 77 | } catch (const txeo::MatrixIOError &e) { 78 | std::cerr << "Write error: " << e.what() << "\n"; 79 | } 80 | } 81 | 82 | // ====================================================================================== 83 | // 6. Error Handling Demonstration 84 | // ====================================================================================== 85 | { 86 | std::cout << "\n=== 6. Error Handling ===\n"; 87 | try { 88 | auto invalid = txeo::MatrixIO::read_textfile("non_existent_file.dat", 89 | '$', // Invalid separator 90 | true); 91 | } catch (const txeo::MatrixIOError &e) { 92 | std::cerr << "Caught expected error: " << e.what() << "\n"; 93 | } 94 | } 95 | 96 | return 0; 97 | } -------------------------------------------------------------------------------- /tests/tDataTableNorm.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/DataTable.h" 2 | #include "txeo/DataTableNorm.h" 3 | #include 4 | 5 | using namespace txeo; 6 | 7 | // Helper function to create test data 8 | template 9 | DataTable create_sample_datatable() { 10 | Matrix data({{1.0, 2.0, 0.0}, {3.0, 4.0, 1.0}, {5.0, 6.0, 2.0}}); 11 | return DataTable(std::move(data), {2}); 12 | } 13 | 14 | TEST(DataTableNormTest, ConstructorInitialization) { 15 | auto dt = create_sample_datatable(); 16 | DataTableNorm normalizer(dt, NormalizationType::MIN_MAX); 17 | 18 | EXPECT_EQ(&normalizer.data_table(), &dt); 19 | EXPECT_EQ(normalizer.type(), NormalizationType::MIN_MAX); 20 | } 21 | 22 | TEST(DataTableNormTest, NormalizeMinMax) { 23 | auto dt = create_sample_datatable(); 24 | DataTableNorm normalizer(dt, NormalizationType::MIN_MAX); 25 | 26 | Matrix input({{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}); 27 | auto result = normalizer.normalize(input); 28 | 29 | // Expected min-max normalized values for columns 0 and 1 30 | EXPECT_DOUBLE_EQ(result(0, 0), 0.0); // (1-1)/(5-1) 31 | EXPECT_DOUBLE_EQ(result(1, 0), 0.5); // (3-1)/(5-1) 32 | EXPECT_DOUBLE_EQ(result(0, 1), 0.0); // (2-2)/(6-2) 33 | EXPECT_DOUBLE_EQ(result(1, 1), 0.5); // (4-2)/(6-2) 34 | } 35 | 36 | TEST(DataTableNormTest, NormalizeZScore) { 37 | auto dt = create_sample_datatable(); 38 | DataTableNorm normalizer(dt, NormalizationType::Z_SCORE); 39 | 40 | Matrix input({{3.0, 0.0}, {3.0, 1.0}, {3.0, 2.0}}); // Column 0 values 41 | auto result = normalizer.normalize(input); 42 | 43 | // μ=3.0, σ=1.63299 for column 0 44 | const double eps = 1e-5; 45 | EXPECT_NEAR(result(0, 0), (3.0 - 3.0) / 1.63299, eps); 46 | EXPECT_NEAR(result(1, 0), (3.0 - 3.0) / 1.63299, eps); 47 | } 48 | 49 | TEST(DataTableNormTest, NormalizeThrowsWhenUninitialized) { 50 | DataTableNorm normalizer; 51 | Matrix input({{1.0}}); 52 | 53 | EXPECT_THROW(normalizer.normalize(input), DataTableNormError); 54 | } 55 | 56 | TEST(DataTableNormTest, SetDataTableUpdatesParameters) { 57 | auto dt1 = create_sample_datatable(); 58 | DataTableNorm normalizer(dt1, NormalizationType::MIN_MAX); 59 | 60 | Matrix new_data({{10.0, 20.0}}); 61 | DataTable dt2(std::move(new_data), {1}); 62 | normalizer.set_data_table(dt2); 63 | 64 | Matrix input({{10.0}, {20.0}}); 65 | auto result = normalizer.normalize(input); 66 | EXPECT_DOUBLE_EQ(result(0, 0), 0.0); // New min=10 67 | EXPECT_DOUBLE_EQ(result(0, 0), 0.0); // New max=20 68 | } 69 | 70 | TEST(DataTableNormTest, ConstantFeatureHandling) { 71 | Matrix data({{5.0, 0.0}, {5.0, 1.0}, {5.0, 2.0}}); 72 | DataTable dt(std::move(data), {1}); 73 | DataTableNorm normalizer(dt, NormalizationType::MIN_MAX); 74 | 75 | Matrix input({{5.0}, {5.0}}); 76 | auto result = normalizer.normalize(input); 77 | 78 | // Constant feature should be zeroed 79 | EXPECT_DOUBLE_EQ(result(0, 0), 0.0); 80 | EXPECT_DOUBLE_EQ(result(1, 0), 0.0); 81 | } 82 | 83 | TEST(DataTableNormTest, XTrainNormalized) { 84 | auto dt = create_sample_datatable(); 85 | DataTableNorm normalizer(dt, NormalizationType::MIN_MAX); 86 | 87 | auto normalized_train = normalizer.x_train_normalized(); 88 | const auto &original_train = dt.x_train(); 89 | 90 | EXPECT_TRUE(original_train.shape() == txeo::TensorShape({3, 2})); 91 | 92 | // Verify first column normalization 93 | EXPECT_DOUBLE_EQ(normalized_train(0, 0), 0.0); // min=1 94 | EXPECT_DOUBLE_EQ(normalized_train(2, 0), 1.0); // max=5 95 | } 96 | 97 | TEST(DataTableNormTest, NormalizeRvalueSemantics) { 98 | auto dt = create_sample_datatable(); 99 | DataTableNorm normalizer(dt); 100 | 101 | Matrix input(1000, 2); // Large matrix 102 | auto original_ptr = input.data(); 103 | auto result = normalizer.normalize(std::move(input)); 104 | 105 | // Verify move semantics preserved storage 106 | EXPECT_EQ(result.data(), original_ptr); 107 | } 108 | 109 | TEST(DataTableNormTest, TypeGetterReturnsCorrectType) { 110 | auto dt = create_sample_datatable(); 111 | DataTableNorm minmax_norm(dt, NormalizationType::MIN_MAX); 112 | DataTableNorm zscore_norm(dt, NormalizationType::Z_SCORE); 113 | 114 | EXPECT_EQ(minmax_norm.type(), NormalizationType::MIN_MAX); 115 | EXPECT_EQ(zscore_norm.type(), NormalizationType::Z_SCORE); 116 | } -------------------------------------------------------------------------------- /tests/tMatrixIO.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "txeo/Matrix.h" 9 | #include "txeo/MatrixIO.h" 10 | #include "txeo/Tensor.h" 11 | #include "txeo/TensorShape.h" 12 | 13 | namespace txeo { 14 | namespace { 15 | 16 | namespace fs = std::filesystem; 17 | 18 | void create_test_file(const std::string &path, const std::string &content) { 19 | std::ofstream file{path}; 20 | file << content; 21 | } 22 | 23 | class MatrixIOTest : public ::testing::Test { 24 | protected: 25 | void SetUp() override { fs::create_directory(test_dir); } 26 | 27 | void TearDown() override { fs::remove_all(test_dir); } 28 | 29 | const std::string test_dir = "test_data"; 30 | }; 31 | 32 | TEST_F(MatrixIOTest, InstanceReadWrite2DInt) { 33 | const std::string path = test_dir + "/test_int.csv"; 34 | const Matrix original(2, 3, {1, 2, 3, 4, 5, 6}); 35 | 36 | MatrixIO io(path); 37 | io.write_text_file(original); 38 | 39 | auto loaded = io.read_text_file(); 40 | EXPECT_EQ(original.shape(), loaded.shape()); 41 | for (size_t i = 0; i < original.dim(); ++i) { 42 | EXPECT_EQ(original.data()[i], loaded.data()[i]); 43 | } 44 | } 45 | 46 | TEST_F(MatrixIOTest, StaticReadWrite2DFloat) { 47 | const std::string path = test_dir + "/test_float.csv"; 48 | const Matrix original(3, 2, {1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f}); 49 | 50 | MatrixIO::write_textfile(original, path); 51 | 52 | auto loaded = MatrixIO::read_textfile(path); 53 | EXPECT_EQ(original.shape(), loaded.shape()); 54 | for (size_t i = 0; i < original.dim(); ++i) { 55 | EXPECT_FLOAT_EQ(original.data()[i], loaded.data()[i]); 56 | } 57 | } 58 | 59 | TEST_F(MatrixIOTest, ReadWithHeader) { 60 | const std::string path = test_dir + "/header_test.csv"; 61 | create_test_file(path, "col1,col2,col3\n1,2,3\n4,5,6"); 62 | 63 | auto tensor = MatrixIO::read_textfile(path, ',', true); 64 | 65 | EXPECT_EQ(tensor.shape(), TensorShape({2, 3})); 66 | EXPECT_EQ(tensor(1, 2), 6); 67 | } 68 | 69 | TEST_F(MatrixIOTest, WritePrecision) { 70 | const std::string path = test_dir + "/precision_test.csv"; 71 | const Matrix original(1, 3, {1.23456789, 2.34567891, 3.45678912}); 72 | 73 | MatrixIO::write_textfile(original, 3, path); 74 | 75 | std::ifstream file(path); 76 | std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); 77 | EXPECT_EQ(content, "1.235,2.346,3.457"); 78 | } 79 | 80 | TEST_F(MatrixIOTest, FileNotFoundRead) { 81 | EXPECT_THROW(MatrixIO::read_textfile("nonexistent.csv"), MatrixIOError); 82 | } 83 | 84 | TEST_F(MatrixIOTest, InvalidDataFormat) { 85 | const std::string path = test_dir + "/invalid_data.csv"; 86 | create_test_file(path, "1,2.5,three\n4,5,6"); 87 | 88 | EXPECT_THROW(MatrixIO::read_textfile(path), MatrixIOError); 89 | } 90 | 91 | TEST_F(MatrixIOTest, EmptyFile) { 92 | const std::string path = test_dir + "/empty.csv"; 93 | create_test_file(path, ""); 94 | 95 | EXPECT_THROW(MatrixIO::read_textfile(path), MatrixIOError); 96 | } 97 | 98 | TEST_F(MatrixIOTest, InconsistentRowLength) { 99 | const std::string path = test_dir + "/inconsistent.csv"; 100 | create_test_file(path, "1,2,3\n4,5"); 101 | 102 | EXPECT_THROW(MatrixIO::read_textfile(path), MatrixIOError); 103 | } 104 | 105 | TEST_F(MatrixIOTest, FloatingPointRequires) { 106 | const Matrix float_tensor(2, 2); 107 | 108 | EXPECT_TRUE((requires { MatrixIO::write_textfile(float_tensor, 2, "test.csv"); })); 109 | } 110 | 111 | TEST_F(MatrixIOTest, OneHotEncode) { 112 | std::filesystem::path input_path{"../../../../tests/test_data/files/insurance.csv"}; 113 | std::filesystem::path output_path{test_dir + "/test_insurance_one_hot.csv"}; 114 | auto io = MatrixIO::one_hot_encode_text_file(input_path, ',', true, output_path); 115 | auto matrix = io.read_text_file(true); 116 | 117 | EXPECT_EQ(matrix.dim(), 55); 118 | EXPECT_EQ(matrix(3, 1), 1.0f); 119 | EXPECT_EQ(matrix(4, 9), 0.0f); 120 | EXPECT_THROW(MatrixIO::one_hot_encode_text_file("nofile.txt", ',', true, output_path), 121 | MatrixIOError); 122 | 123 | const std::string path = test_dir + "/inconsistent.csv"; 124 | create_test_file(path, "1,2,3\n4,5"); 125 | 126 | EXPECT_THROW(MatrixIO::one_hot_encode_text_file(path, ',', false, output_path), MatrixIOError); 127 | } 128 | 129 | } // namespace 130 | } // namespace txeo -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/tensor-shape.md: -------------------------------------------------------------------------------- 1 | # TensorShape 2 | 3 | The `TensorShape` class defines the dimensional structure of tensors in the **txeo** library. It describes the dimensions and axes of tensors, serving as the foundation for tensor creation, manipulation, and indexing. 4 | 5 | ## Overview 6 | 7 | A `TensorShape` represents the dimensions of a tensor: 8 | 9 | - **Axes**: Positions labeled from zero, each associated with a tensor dimension. 10 | - **Dimensions**: Size along each axis. 11 | 12 | Examples: 13 | 14 | - Scalar (no axes): `TensorShape()` 15 | - Vector: `{3}` 16 | - Matrix: `{3, 4}` 17 | - 3-dimensional tensor: `{2, 3, 4}` 18 | 19 | --- 20 | 21 | ## API Reference 22 | 23 | | Method | Description | 24 | |-----------------------------|-------------------------------------------------| 25 | | `axes_dims()` | Returns dimensions of each axis | 26 | | `clone()` | Returns a deep copy of shape | 27 | | `insert_axis(axis, dim)` | Inserts axis at specified position | 28 | | `number_of_axes()` | Synonym for `size()` | 29 | | `push_axis_back(dim)` | Adds an axis at the end | 30 | | `remove_all_axes()` | Removes all axes | 31 | | `remove_axis(axis)` | Removes specified axis | 32 | | `set_dim(axis, dim)` | Changes size of specified axis | 33 | | `size()` | Returns number of axes | 34 | | `stride()` | Returns strides for efficient indexing | 35 | 36 | --- 37 | 38 | ## Creating Tensor Shapes 39 | 40 | ### Constructing from dimensions 41 | 42 | ```cpp 43 | txeo::TensorShape shape({2, 3, 4}); // Creates a shape with dimensions 2x3x4 44 | ``` 45 | 46 | ### Creating uniform dimensions 47 | 48 | ```cpp 49 | txeo::TensorShape shape(3, 5); // Shape with three axes, each of dimension 5 50 | ``` 51 | 52 | ## Common Operations 53 | 54 | ### Accessing Dimensions 55 | 56 | You can access the shape dimensions: 57 | 58 | ```cpp 59 | std::vector dims = shape.axes_dims(); 60 | ``` 61 | 62 | ### Comparing shapes 63 | 64 | ```cpp 65 | if (shape1 == shape2) { 66 | std::cout << "Shapes are equal."; 67 | } 68 | ``` 69 | 70 | ## Manipulating Axes 71 | 72 | ### Inserting an Axis 73 | 74 | ```cpp 75 | shape.insert_axis(1, 5); // Inserts a new axis at position 1 with dimension 5 76 | ``` 77 | 78 | ### Removing an Axis 79 | 80 | ```cpp 81 | shape.remove_axis(2); // Removes the axis at position 2 82 | ``` 83 | 84 | ### Changing a Dimension 85 | 86 | ```cpp 87 | shape.set_dim(0, 10); // Sets the first axis dimension size to 10 88 | ``` 89 | 90 | ### Removing All Axes 91 | 92 | ```cpp 93 | shape.remove_axis(0); // Removes axis at position 0 94 | shape.remove_axis(1); // Removes axis at new position 1 95 | ``` 96 | 97 | or simply: 98 | 99 | ```cpp 100 | shape.remove_all_axes(); 101 | ``` 102 | 103 | ## Stride 104 | 105 | Tensor strides represent the memory step size for each dimension: 106 | 107 | ```cpp 108 | auto strides = shape.stride(); 109 | 110 | for (size_t s : strides) 111 | std::cout << s << ' '; 112 | ``` 113 | 114 | --- 115 | 116 | ## Examples 117 | 118 | ### Checking Shape Equality 119 | 120 | ```cpp 121 | #include 122 | #include "txeo/TensorShape.h" 123 | 124 | int main() { 125 | txeo::TensorShape shape1({3, 4}); 126 | txeo::TensorShape shape2({3, 4}); 127 | 128 | if (shape == shape2) { 129 | std::cout << "Shapes match!" << std::endl; 130 | } 131 | } 132 | ``` 133 | 134 | ### Modifying a TensorShape 135 | 136 | ```cpp 137 | #include 138 | #include "txeo/TensorShape.h" 139 | 140 | int main() { 141 | txeo::TensorShape shape({2, 3}); 142 | 143 | shape.push_axis_back(4); // shape now (2,3,4) 144 | shape.set_dim(1, 5); // Update dimension of axis 1 from 3 to 5 145 | 146 | std::cout << "Updated Shape: " << shape << std::endl; 147 | } 148 | ``` 149 | 150 | --- 151 | 152 | ## Exception Handling 153 | 154 | All invalid operations throw a `TensorShapeError`: 155 | 156 | ```cpp 157 | try { 158 | shape.insert_axis(10, 2); // invalid operation 159 | } catch (const txeo::TensorShapeError &e) { 160 | std::cerr << "Error: " << e.what(); 161 | } 162 | ``` 163 | 164 | --- 165 | 166 | For detailed API references, see individual method documentation at [txeo::TensorShape](https://txeo-doc.netlify.app/classtxeo_1_1_tensor_shape.html). 167 | -------------------------------------------------------------------------------- /tests/tLoggerFile.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/LoggerFile.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace txeo { 8 | namespace fs = std::filesystem; 9 | 10 | const fs::path TEST_LOG = "test_logfile.log"; 11 | 12 | std::string read_last_line(const fs::path &path) { 13 | std::ifstream file(path); 14 | std::string line, last_line; 15 | while (std::getline(file, line)) { 16 | if (!line.empty()) 17 | last_line = line; 18 | } 19 | return last_line; 20 | } 21 | 22 | TEST(LoggerFileTest, SingletonInstanceConsistency) { 23 | LoggerFile &logger1 = LoggerFile::instance(); 24 | LoggerFile &logger2 = LoggerFile::instance(); 25 | ASSERT_EQ(&logger1, &logger2); 26 | } 27 | 28 | TEST(LoggerFileTest, FileCreationOnFirstOpen) { 29 | if (fs::exists(TEST_LOG)) 30 | fs::remove(TEST_LOG); 31 | 32 | auto &logger = LoggerFile::instance(); 33 | ASSERT_TRUE(logger.open_file(TEST_LOG)); 34 | ASSERT_TRUE(fs::exists(TEST_LOG)); 35 | } 36 | 37 | TEST(LoggerFileTest, WriteToClosedFileThrows) { 38 | auto &logger = LoggerFile::instance(); 39 | logger.turn_on(); 40 | 41 | logger.close_file(); 42 | 43 | EXPECT_THROW({ logger.info("Should throw"); }, LoggerFileError); 44 | } 45 | 46 | TEST(LoggerFileTest, LogLevelStringsInOutput) { 47 | auto &logger = LoggerFile::instance(); 48 | logger.turn_on(); 49 | logger.set_output_level(LogLevel::DEBUG); 50 | 51 | if (!logger.open_file(TEST_LOG)) { 52 | FAIL() << "Failed to open log file"; 53 | } 54 | 55 | const std::string test_msg = "LEVEL_TEST_"; 56 | logger.debug(test_msg + "debug"); 57 | logger.info(test_msg + "info"); 58 | logger.warning(test_msg + "warning"); 59 | logger.error(test_msg + "error"); 60 | 61 | std::ifstream file(TEST_LOG); 62 | std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); 63 | 64 | EXPECT_NE(content.find("DEBUG"), std::string::npos); 65 | EXPECT_NE(content.find("INFO"), std::string::npos); 66 | EXPECT_NE(content.find("WARNING"), std::string::npos); 67 | EXPECT_NE(content.find("ERROR"), std::string::npos); 68 | } 69 | 70 | TEST(LoggerFileTest, LogLevelFiltering) { 71 | auto &logger = LoggerFile::instance(); 72 | if (!logger.open_file(TEST_LOG)) 73 | FAIL() << "Failed to open log file"; 74 | logger.turn_on(); 75 | logger.set_output_level(LogLevel::WARNING); 76 | 77 | const std::string test_msg = "FILTER_TEST_"; 78 | logger.info(test_msg + "should_not_appear"); 79 | logger.warning(test_msg + "should_appear"); 80 | 81 | std::string content = read_last_line(TEST_LOG); 82 | EXPECT_EQ(content.find(test_msg + "should_not_appear"), std::string::npos); 83 | EXPECT_NE(content.find(test_msg + "should_appear"), std::string::npos); 84 | } 85 | 86 | TEST(LoggerFileTest, ToggleLogging) { 87 | auto &logger = LoggerFile::instance(); 88 | if (!logger.open_file(TEST_LOG)) 89 | FAIL() << "Failed to open log file"; 90 | 91 | logger.turn_off(); 92 | 93 | const std::string test_msg = "TOGGLE_TEST"; 94 | logger.error(test_msg); 95 | 96 | std::string content = read_last_line(TEST_LOG); 97 | EXPECT_EQ(content.find(test_msg), std::string::npos); 98 | 99 | logger.turn_on(); 100 | logger.error(test_msg); 101 | content = read_last_line(TEST_LOG); 102 | EXPECT_NE(content.find(test_msg), std::string::npos); 103 | } 104 | 105 | TEST(LoggerFileTest, FinalCleanup) { 106 | if (fs::exists(TEST_LOG)) { 107 | ASSERT_TRUE(fs::remove(TEST_LOG)); 108 | } 109 | } 110 | 111 | // This test only woks if executed alone 112 | // 113 | // TEST(LoggerFileTest, ConcurrentWriteSafety) { 114 | // auto &logger = LoggerFile::instance(); 115 | // if (!logger.open_file("test_logfile_t.log")) 116 | // FAIL() << "Failed to open log file"; 117 | 118 | // logger.turn_on(); 119 | 120 | // constexpr int NUM_THREADS = 10; 121 | // std::vector threads; 122 | // std::vector messages; 123 | 124 | // for (int i = 0; i < NUM_THREADS; ++i) { 125 | // messages.push_back("THREAD_" + std::to_string(i)); 126 | // } 127 | 128 | // for (const auto &msg : messages) { 129 | // threads.emplace_back([&logger, msg]() { logger.info(msg); }); 130 | // } 131 | 132 | // for (auto &t : threads) { 133 | // t.join(); 134 | // } 135 | 136 | // std::ifstream file("test_logfile_t.log"); 137 | // std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); 138 | 139 | // std::cout << content << std::endl; 140 | // for (const auto &msg : messages) { 141 | // EXPECT_NE(content.find(msg), std::string::npos); 142 | // } 143 | // } 144 | 145 | } // namespace txeo -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/matrix.md: -------------------------------------------------------------------------------- 1 | # Matrix 2 | 3 | The `Matrix` class is a specialized 2nd-order tensor provided by the **txeo** library, facilitating intuitive handling of matrix-specific operations. 4 | 5 | ## Overview 6 | 7 | The `Matrix` class in **txeo** is a specialized tensor explicitly tailored for second-order data structures. It provides simplified constructors, clear interfaces, and seamless interoperability with tensors. 8 | 9 | --- 10 | 11 | ## API Reference 12 | 13 | | Method | Description | 14 | |---------------------------|-------------------------------------------------------------| 15 | | `col_size()` | Returns the column size of the matrix. | 16 | | `normalize_columns(type)` | Normalize all the columns of this matrix according to a normalization type | 17 | | `normalize_rows(type)` | Normalize all the rows of this matrix according to a normalization type | 18 | | `row_size()` | Returns the row size of the matrix. | 19 | | `size()` | Returns total number of matrix elements | 20 | | `to_matrix(tensor)` | Converts a second-order tensor to matrix (move semantics) | 21 | | `to_tensor(matrix)` | Converts a matrix to tensor, supports copy and move semantics | 22 | | `transpose()` | Transposes the matrix (swaps rows and columns) in-place. | 23 | 24 | --- 25 | 26 | ## Creating Matrices 27 | 28 | ### Basic Matrix Creation 29 | 30 | ```cpp 31 | #include 32 | #include "txeo/Matrix.h" 33 | 34 | int main() { 35 | txeo::Matrix matrix(3, 3); // Creates a 3x3 matrix 36 | std::cout << matrix << std::endl; 37 | } 38 | ``` 39 | 40 | ### Initialization with Specific Values 41 | 42 | ```cpp 43 | txeo::Matrix matrix(2, 3, 5); // 2x3 matrix filled with value 5 44 | ``` 45 | 46 | ### Initialization from Vector 47 | 48 | ```cpp 49 | txeo::Matrix matrix(2, 3, {1, 2, 3, 4, 5, 6}); 50 | ``` 51 | 52 | ### Nested Initializer Lists 53 | 54 | ```cpp 55 | txeo::Matrix matrix{{1, 2, 3}, {4, 5, 6}}; // 2x3 matrix 56 | ``` 57 | 58 | --- 59 | 60 | ## Normalization 61 | 62 | ```cpp 63 | // Example: Min-max normalize columns 64 | txeo::Matrix mat({{10.0, 20.0}, // Column 1: [10, 30] 65 | {30.0, 40.0}}); // Column 2: [20, 40] 66 | mat.normalize_columns(txeo::NormalizationType::MIN_MAX); 67 | // Column 1 becomes [0.0, 1.0] 68 | // Column 2 becomes [0.0, 1.0] 69 | 70 | // Example: Z-score normalize columns 71 | txeo::Matrix m({{1.0f, 4.0f}, // Column 1: μ=2.0, σ=1.414 72 | {3.0f, 6.0f}}); // Column 2: μ=5.0, σ=1.414 73 | m.normalize_columns(txeo::NormalizationType::Z_SCORE); 74 | // Column 1 becomes [-0.707, 0.707] 75 | // Column 2 becomes [-0.707, 0.707] 76 | ``` 77 | 78 | --- 79 | 80 | ## Conversion between Matrix and Tensor 81 | 82 | ### Matrix to Tensor (Move Constructor) 83 | 84 | ```cpp 85 | txeo::Tensor tensor({2, 3}, {1, 2, 3, 4, 5, 6}); 86 | txeo::Matrix matrix(std::move(tensor)); 87 | ``` 88 | 89 | ### Tensor to Matrix (Move Semantics) 90 | 91 | ```cpp 92 | txeo::Tensor tensor({2, 3}, {1, 2, 3, 4, 5, 6}); 93 | auto matrix = txeo::Matrix::to_matrix(std::move(tensor)); 94 | ``` 95 | 96 | ### Matrix to Tensor (Copy) 97 | 98 | ```cpp 99 | txeo::Matrix matrix(2, 3, {1, 2, 3, 4, 5, 6}); 100 | txeo::Tensor tensor = txeo::Matrix::to_tensor(matrix); 101 | ``` 102 | 103 | ### Matrix to Tensor (Move Semantics) 104 | 105 | ```cpp 106 | txeo::Tensor tensor = txeo::Matrix::to_tensor(std::move(matrix)); 107 | ``` 108 | 109 | --- 110 | 111 | ## Exception Handling 112 | 113 | Matrix-related errors throw `MatrixError` exceptions: 114 | 115 | ```cpp 116 | try { 117 | txeo::Matrix matrix(2, 3, {1,2,3}); // Invalid initialization 118 | } catch (const txeo::MatrixError &e) { 119 | std::cerr << e.what() << std::endl; 120 | } 121 | ``` 122 | 123 | --- 124 | 125 | ## Examples 126 | 127 | ### Basic Matrix Manipulation 128 | 129 | ```cpp 130 | #include 131 | #include "txeo/Tensor.h" 132 | #include "txeo/Matrix.h" 133 | 134 | int main() { 135 | txeo::Matrix mat{{1, 2}, {3, 4}}; 136 | mat(0, 1) = 10; 137 | std::cout << "Matrix:\n" << mat << std::endl; 138 | } 139 | ``` 140 | 141 | ### Matrix and Scalar Operations 142 | 143 | ```cpp 144 | #include 145 | #include "txeo/Matrix.h" 146 | 147 | int main() { 148 | txeo::Matrix mat(2, 2, {1, 2, 3, 4}); 149 | auto mat2 = mat * 3; // Scalar multiplication 150 | 151 | std::cout << "Resulting matrix: " << mat2 << std::endl; 152 | return 0; 153 | } 154 | ``` 155 | 156 | --- 157 | 158 | For detailed API references, see individual method documentation at [txeo::Matrix](https://txeo-doc.netlify.app/classtxeo_1_1_matrix.html). 159 | -------------------------------------------------------------------------------- /mkdocs/docs/getting-started.md: -------------------------------------------------------------------------------- 1 | # Installation Guide 2 | 3 | ## Requirements 4 | 5 | - **Supported OS:** 🐧 **Linux** (Tested on Ubuntu and Manjaro). 6 | - ⚠️ **Windows and macOS are not yet officially supported.** 7 | - **Build Tools:** 🛠 Essential C/C++ development tools. 8 | - **CMake:** 🏗 Built with **v3.25+**. 9 | - **Compilers:** 💻 Requires a C++20-compatible compiler: 10 | - ✅ **Clang** (Tested with **v19.1.2**) 11 | - ✅ **GCC** (Tested with **v13.2.0**) 12 | - ✅ **Intel** (Tested with **v2025.0.4**) 13 | - 🛠 Supports **concepts, ranges, and other C++20 features**. 14 | - **Dependencies:** 15 | - 🔗 **TensorFlow 2.18.0** → [GitHub](https://github.com/tensorflow/tensorflow) 16 | - 📜 **Protobuf 3.21.9** → [GitHub](https://github.com/protocolbuffers/protobuf) 17 | 18 | --- 19 | 20 | ## Option 1: Installation Steps with Precompiled Binaries (Fastest Way) 21 | 22 | This method **installs TensorFlow and Protobuf binaries** into `/opt/`. 23 | 24 | ### **1️⃣ Download and install Protobuf** 25 | 26 | ```sh 27 | wget https://github.com/rdabra/txeo/releases/download/v1.0.0/libprotobuf-3.21.9-linux-x64.tar.gz 28 | sudo tar -xzf libprotobuf-3.21.9-linux-x64.tar.gz -C /opt/ 29 | echo "export Protobuf_ROOT_DIR=/opt/protobuf" >> ~/.bashrc 30 | source ~/.bashrc 31 | ``` 32 | 33 | ### **2️⃣ Download and install TensorFlow** 34 | 35 | Choose the correct version based on your system: 36 | 37 | | Version | Download | 38 | | -------- | ------- | 39 | | 💻 Without CPU optimizations | [libtensorflow-2.18-linux-x64-cpu.tar.gz](https://github.com/rdabra/txeo/releases/download/v1.0.0/libtensorflow-2.18-linux-x64-cpu.tar.gz) | 40 | | 🚀 With CPU optimizations: | [libtensorflow-2.18-linux-x64-cpu-opt.tar.gz](https://github.com/rdabra/txeo/releases/download/v1.0.0/libtensorflow-2.18-linux-x64-cpu-opt.tar.gz) | 41 | | 🎮 With GPU support: | [libtensorflow-2.18-linux-x64-gpu.tar.gz](https://github.com/rdabra/txeo/releases/download/v1.0.0/libtensorflow-2.18-linux-x64-gpu.tar.gz) | 42 | 43 | 💡 **Important Note** : The Protobuf and TensorFlow source codes used for compiling the binaries above **were not modified** in any way. These assets are **only provided to simplify installation** for **txeo** users. 44 | 45 | Installing TensorFlow binaries: 46 | 47 | ```sh 48 | wget https://github.com/rdabra/txeo/releases/download/v1.0.0/libtensorflow-2.18-linux-x64-cpu.tar.gz 49 | sudo tar -xzf libtensorflow-2.18-linux-x64-cpu.tar.gz -C /opt/ 50 | echo "export TensorFlow_ROOT_DIR=/opt/tensorflow" >> ~/.bashrc 51 | source ~/.bashrc 52 | ``` 53 | 54 | ### **3️⃣ Clone and install txeo** 55 | 56 | Installing **txeo** and making libraries visible via library path: 57 | 58 | ```sh 59 | git clone https://github.com/rdabra/txeo.git 60 | cd txeo 61 | mkdir build && cd build 62 | cmake .. -DCMAKE_BUILD_TYPE=Release 63 | make -j$(nproc) 64 | sudo make install 65 | echo "export LD_LIBRARY_PATH=/opt/tensorflow/lib:/opt/txeo/lib:$LD_LIBRARY_PATH" >> ~/.bashrc 66 | ``` 67 | 68 | --- 69 | 70 | ## Option 2: Installation Steps with Protobuf and TensorFlow built from source (may take a long time) 71 | 72 | ### **1️⃣ Clone and install Protobuf** 73 | 74 | ```sh 75 | git clone https://github.com/protocolbuffers/protobuf.git 76 | cd protobuf 77 | git checkout refs/tags/v3.21.9 78 | cmake -S. -Bcmake-out -G Ninja -DCMAKE_INSTALL_PREFIX="/opt/protobuf" -Dprotobuf_ABSL_PROVIDER=package -Dprotobuf_BUILD_TESTS=OFF 79 | cd cmake-out 80 | cmake --build . 81 | sudo cmake --install . 82 | echo "export Protobuf_ROOT_DIR=/opt/protobuf" >> ~/.bashrc 83 | source ~/.bashrc 84 | ``` 85 | 86 | ### **2️⃣ Clone and install Tensorflow** 87 | 88 | ⚠️ Important: 89 | Ensure Bazel is installed before proceeding. You can use Bazelisk to manage Bazel versions: 90 | [Bazelisk GitHub](https://github.com/bazelbuild/bazelisk). For the gcc compiler, key `-std=gnu2x` must be removed. 91 | 92 | ```sh 93 | git clone https://github.com/tensorflow/tensorflow.git 94 | cd tensorflow 95 | git checkout refs/tags/v2.18.0 96 | ./configure 97 | bazel build -c opt --copt=-std=gnu2x --copt=-mavx --copt=-mavx2 --copt=-mfma --copt=-msse4.1 --copt=-msse4.2 //tensorflow:libtensorflow_cc.so //tensorflow:libtensorflow_framework.so //tensorflow:install_headers 98 | ``` 99 | 100 | Copying libraries and includes accordingly: 101 | 102 | ```sh 103 | cd bazel-bin 104 | sudo mkdir /opt/tensorflow 105 | sudo cp -r tensorflow/include /opt/tensorflow 106 | sudo mkdir /opt/tensorflow/lib 107 | sudo cp -r tensorflow/*.so* /opt/tensorflow/lib 108 | echo "export TensorFlow_ROOT_DIR=/opt/tensorflow" >> ~/.bashrc 109 | source ~/.bashrc 110 | ``` 111 | 112 | ### **3️⃣ Installing txeo** 113 | 114 | ```sh 115 | git clone https://github.com/rdabra/txeo.git 116 | cd txeo 117 | mkdir build && cd build 118 | cmake .. -DCMAKE_BUILD_TYPE=Release 119 | make -j$(nproc) 120 | sudo make install 121 | echo "export LD_LIBRARY_PATH=/opt/tensorflow/lib:/opt/txeo/lib:$LD_LIBRARY_PATH" >> ~/.bashrc 122 | ``` -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/matrix-io.md: -------------------------------------------------------------------------------- 1 | # MatrixIO 2 | 3 | `txeo::MatrixIO` is a **txeo** class designed for convenient reading and writing of matrix data from and to text files. It supports flexible formatting options including custom separators and floating-point precision control. 4 | 5 | ## Constructors 6 | 7 | ### Initialization with file path and column separator 8 | 9 | ```cpp 10 | explicit MatrixIO(const std::filesystem::path &path, char separator = ','); 11 | ``` 12 | 13 | Constructs a `MatrixIO` object associated with a specified file path and optional separator. 14 | 15 | **Example:** 16 | 17 | ```cpp 18 | txeo::MatrixIO io("data.csv"); 19 | ``` 20 | 21 | ## Member Functions 22 | 23 | ### read_text_file 24 | 25 | ```cpp 26 | template 27 | txeo::Matrix read_text_file(bool has_header = false) const; 28 | ``` 29 | 30 | Reads matrix data from a file into a `Matrix`. Optionally skips the first line if it is a header. 31 | 32 | **Example:** 33 | 34 | ```cpp 35 | txeo::MatrixIO io("data.csv"); 36 | auto matrix = io.read_text_file(true); 37 | ``` 38 | 39 | ### write_text_file 40 | 41 | ```cpp 42 | template 43 | void write_text_file(const txeo::Matrix &matrix) const; 44 | ``` 45 | 46 | Writes a matrix to a file using the defined separator. 47 | 48 | **Example:** 49 | 50 | ```cpp 51 | txeo::Matrix data(txeo::TensorShape({2, 3}), {1, 2, 3, 4, 5, 6}); 52 | txeo::MatrixIO io("output.csv"); 53 | io.write_text_file(data); 54 | ``` 55 | 56 | ### write_text_file (with precision) 57 | 58 | ```cpp 59 | template 60 | requires(std::is_floating_point_v) 61 | void write_text_file(const txeo::Matrix &matrix, size_t precision) const; 62 | ``` 63 | 64 | Writes a floating-point matrix to a file with a specified number of decimal places. 65 | 66 | **Example:** 67 | 68 | ```cpp 69 | txeo::Matrix values(txeo::TensorShape({1, 3}), {1.2345, 2.3456, 3.4567}); 70 | txeo::MatrixIO io("results.csv"); 71 | io.write_text_file(values, 2); // Output: 1.23,2.35,3.46 72 | ``` 73 | 74 | ## Static Member Functions 75 | 76 | ### read_textfile 77 | 78 | ```cpp 79 | template 80 | static txeo::Matrix read_textfile(const std::filesystem::path &path, char separator = ',', bool has_header = false); 81 | ``` 82 | 83 | Convenience static function for reading matrix data from a file in a single call. 84 | 85 | **Example:** 86 | 87 | ```cpp 88 | auto data = txeo::MatrixIO::read_textfile("input.tsv", '\t', true); 89 | ``` 90 | 91 | ### write_textfile 92 | 93 | ```cpp 94 | template 95 | static void write_textfile(const txeo::Matrix &matrix, const std::filesystem::path &path, char separator = ','); 96 | ``` 97 | 98 | Convenience static function for writing matrix data to a file in a single call. 99 | 100 | **Example:** 101 | 102 | ```cpp 103 | txeo::Matrix matrix(txeo::TensorShape({3, 2}), {1, 2, 3, 4, 5, 6}); 104 | txeo::MatrixIO::write_textfile(matrix, "matrix.csv"); 105 | ``` 106 | 107 | ### write_textfile (with precision) 108 | 109 | ```cpp 110 | template 111 | requires(std::is_floating_point_v) 112 | static void write_textfile(const txeo::Matrix &matrix, size_t precision, const std::filesystem::path &path, char separator = ','); 113 | ``` 114 | 115 | Writes a floating-point matrix to a file with specified precision using a single call. 116 | 117 | **Example:** 118 | 119 | ```cpp 120 | txeo::Matrix results(txeo::TensorShape({2, 2}), {0.000123, 4567.8, 9.1, 234.567}); 121 | txeo::MatrixIO::write_textfile(results, 3, "science.csv"); 122 | // Output: 0.000,4567.800,9.100,234.567 123 | ``` 124 | 125 | ### one_hot_encode_text_file 126 | 127 | ```cpp 128 | static txeo::MatrixIO one_hot_encode_text_file(const std::filesystem::path &source_path, 129 | char separator, bool has_header, 130 | const std::filesystem::path &target_path); 131 | ``` 132 | 133 | Loads a source file, one-hot-encode its non-numeric columns, outputs the result to a target file and returns 134 | its associated `MatrixIO`. 135 | 136 | **Example:** 137 | 138 | ```cpp 139 | std::filesystem::path source_path = "input.csv"; 140 | std::filesystem::path target_path = "output.csv"; 141 | char separator = ','; 142 | bool has_header = true; 143 | 144 | auto io = MatrixIO::one_hot_encode_text_file(source_path, separator, has_header, target_path); 145 | auto matrix = io.read_text_file(true); 146 | 147 | std::cout << matrix << std::endl; 148 | ``` 149 | 150 | ## Exceptions 151 | 152 | All methods may throw: 153 | 154 | ### MatrixIOError 155 | 156 | Exception class thrown on I/O errors. 157 | 158 | ```cpp 159 | class MatrixIOError : public std::runtime_error; 160 | ``` 161 | 162 | --- 163 | 164 | For detailed API references, see individual method documentation at [txeo::MatrixIO](https://txeo-doc.netlify.app/classtxeo_1_1_matrix_i_o.html). 165 | -------------------------------------------------------------------------------- /tests/tLoss.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "txeo/Loss.h" 6 | #include "txeo/Tensor.h" 7 | #include "txeo/TensorShape.h" 8 | #include "txeo/types.h" 9 | 10 | TEST(LossTest, MeanSquaredError) { 11 | txeo::Tensor valid({3}, {1.0f, 2.0f, 3.0f}); 12 | txeo::Loss loss(valid); 13 | 14 | txeo::Tensor pred({3}, {1.5f, 1.8f, 2.9f}); 15 | float expected = ((0.5f * 0.5f) + (0.2f * 0.2f) + (0.1f * 0.1f)) / 3.0f; 16 | 17 | EXPECT_FLOAT_EQ(loss.mean_squared_error(pred), expected); 18 | EXPECT_FLOAT_EQ(loss.mse(pred), expected); 19 | } 20 | 21 | TEST(LossTest, MeanAbsoluteError) { 22 | txeo::Tensor valid({4}, {5.0, 3.0, 2.0, 7.0}); 23 | txeo::Loss loss(valid); 24 | 25 | txeo::Tensor pred({4}, {4.5, 3.2, 2.5, 6.8}); 26 | double expected = (0.5 + 0.2 + 0.5 + 0.2) / 4.0; 27 | 28 | EXPECT_DOUBLE_EQ(loss.mean_absolute_error(pred), expected); 29 | EXPECT_DOUBLE_EQ(loss.mae(pred), expected); 30 | } 31 | 32 | TEST(LossTest, MeanSquaredLogarithmicError) { 33 | txeo::Tensor valid({2}, {1.0f, 10.0f}); 34 | txeo::Loss loss(valid); 35 | 36 | txeo::Tensor pred({2}, {1.2f, 9.5f}); 37 | float log_valid1 = std::log1p(1.0f); 38 | float log_valid2 = std::log1p(10.0f); 39 | float log_pred1 = std::log1p(1.2f); 40 | float log_pred2 = std::log1p(9.5f); 41 | float expected = (pow(log_pred1 - log_valid1, 2) + pow(log_pred2 - log_valid2, 2)) / 2.0f; 42 | 43 | EXPECT_FLOAT_EQ(loss.mean_squared_logarithmic_error(pred), expected); 44 | EXPECT_FLOAT_EQ(loss.msle(pred), expected); 45 | } 46 | 47 | TEST(LossTest, LogCoshError) { 48 | txeo::Tensor valid({3}, {2.0, 3.0, 5.0}); 49 | txeo::Loss loss(valid); 50 | 51 | txeo::Tensor pred({3}, {1.8, 3.2, 4.9}); 52 | double error1 = 1.8 - 2.0; 53 | double error2 = 3.2 - 3.0; 54 | double error3 = 4.9 - 5.0; 55 | double expected = 56 | (std::log(std::cosh(error1)) + std::log(std::cosh(error2)) + std::log(std::cosh(error3))) / 57 | 3.0; 58 | 59 | EXPECT_DOUBLE_EQ(loss.log_cosh_error(pred), expected); 60 | EXPECT_DOUBLE_EQ(loss.lche(pred), expected); 61 | } 62 | 63 | TEST(LossTest, ShapeMismatchError) { 64 | txeo::Tensor valid({2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); 65 | txeo::Loss loss(valid); 66 | 67 | txeo::Tensor invalid_pred({4}); 68 | EXPECT_THROW(loss.mse(invalid_pred), txeo::LossError); 69 | } 70 | 71 | TEST(LossTest, EmptyTensorHandling) { 72 | txeo::Tensor valid(txeo::TensorShape({0})); 73 | 74 | EXPECT_THROW({ txeo::Loss loss(valid); }, txeo::LossError); 75 | } 76 | 77 | TEST(LossTest, InvalidLogarithmicInput) { 78 | txeo::Tensor valid({2}, {1.0f, -2.0f}); 79 | txeo::Loss loss(valid); 80 | 81 | txeo::Tensor pred({2}, {0.5f, -1.5f}); 82 | EXPECT_THROW(loss.msle(pred), txeo::LossError); 83 | } 84 | 85 | TEST(LossTest, ShorthandEquivalence) { 86 | txeo::Tensor valid({3}, {2.0, 3.0, 4.0}); 87 | txeo::Loss loss(valid); 88 | 89 | txeo::Tensor pred({3}, {1.9, 3.1, 4.0}); 90 | EXPECT_EQ(loss.mse(pred), loss.mean_squared_error(pred)); 91 | EXPECT_EQ(loss.mae(pred), loss.mean_absolute_error(pred)); 92 | EXPECT_EQ(loss.msle(pred), loss.mean_squared_logarithmic_error(pred)); 93 | EXPECT_EQ(loss.lche(pred), loss.log_cosh_error(pred)); 94 | } 95 | 96 | TEST(LossTest, DefaultLossFunction) { 97 | txeo::Tensor valid({3}, {1.0f, 2.0f, 3.0f}); 98 | txeo::Loss loss(valid); 99 | 100 | txeo::Tensor pred({3}, {1.1f, 1.9f, 3.05f}); 101 | EXPECT_FLOAT_EQ(loss.get_loss(pred), loss.mse(pred)); 102 | } 103 | 104 | TEST(LossTest, SetAndGetMAE) { 105 | txeo::Tensor valid({4}, {5.0, 3.0, 2.0, 7.0}); 106 | txeo::Loss loss(valid, txeo::LossFunc::MSE); 107 | 108 | loss.set_loss(txeo::LossFunc::MAE); 109 | txeo::Tensor pred({4}, {4.5, 3.2, 2.5, 6.8}); 110 | EXPECT_DOUBLE_EQ(loss.get_loss(pred), loss.mae(pred)); 111 | } 112 | 113 | TEST(LossTest, SetAndGetMSLE) { 114 | txeo::Tensor valid({2}, {1.0f, 10.0f}); 115 | txeo::Loss loss(valid, txeo::LossFunc::MAE); 116 | 117 | loss.set_loss(txeo::LossFunc::MSLE); 118 | txeo::Tensor pred({2}, {1.2f, 9.5f}); 119 | EXPECT_FLOAT_EQ(loss.get_loss(pred), loss.msle(pred)); 120 | } 121 | 122 | TEST(LossTest, SetAndGetLCHE) { 123 | txeo::Tensor valid({3}, {2.0, 3.0, 5.0}); 124 | txeo::Loss loss(valid); 125 | 126 | loss.set_loss(txeo::LossFunc::LCHE); 127 | txeo::Tensor pred({3}, {1.8, 3.2, 4.9}); 128 | EXPECT_DOUBLE_EQ(loss.get_loss(pred), loss.lche(pred)); 129 | } 130 | 131 | TEST(LossTest, MultipleFunctionChanges) { 132 | txeo::Tensor valid({2}, {4.0f, 6.0f}); 133 | txeo::Tensor pred({2}, {3.8f, 6.2f}); 134 | txeo::Loss loss(valid); 135 | 136 | loss.set_loss(txeo::LossFunc::MAE); 137 | EXPECT_FLOAT_EQ(loss.get_loss(pred), loss.mae(pred)); 138 | 139 | loss.set_loss(txeo::LossFunc::MSE); 140 | EXPECT_FLOAT_EQ(loss.get_loss(pred), loss.mse(pred)); 141 | 142 | loss.set_loss(txeo::LossFunc::LCHE); 143 | EXPECT_NEAR(loss.get_loss(pred), loss.lche(pred), 1e-6); 144 | } -------------------------------------------------------------------------------- /include/txeo/Trainer.h: -------------------------------------------------------------------------------- 1 | #ifndef TRAINER_H 2 | #define TRAINER_H 3 | #include "txeo/Logger.h" 4 | #include "txeo/LoggerConsole.h" 5 | #pragma once 6 | 7 | #include "txeo/DataTable.h" 8 | #include "txeo/DataTableNorm.h" 9 | #include "txeo/Tensor.h" 10 | #include "txeo/types.h" 11 | 12 | #include 13 | #include 14 | 15 | namespace txeo { 16 | enum class LossFunc; 17 | 18 | /** 19 | * @class Trainer 20 | * @brief Abstract base class for machine learning trainers 21 | * 22 | * @tparam T Numeric type for tensor elements (e.g., float, double) 23 | * 24 | * This class provides the core interface for training machine learning models with: 25 | * - Training/evaluation data management 26 | * - Common training parameters 27 | * - Basic training lifecycle control 28 | * 29 | * Derived classes must implement the prediction logic and training algorithm. 30 | */ 31 | template 32 | class Trainer { 33 | public: 34 | Trainer(const Trainer &) = delete; 35 | Trainer(Trainer &&) = delete; 36 | Trainer &operator=(const Trainer &) = delete; 37 | Trainer &operator=(Trainer &&) = delete; 38 | virtual ~Trainer() = default; 39 | 40 | /** 41 | * @brief Construct a new Trainer object from a data table. 42 | * 43 | * @param data Training/Evaluation/Test data. 44 | */ 45 | Trainer(txeo::DataTable &&data, txeo::Logger &logger = txeo::LoggerConsole::instance()) 46 | : _data_table{std::make_unique>(std::move(data))}, _logger{&logger} {}; 47 | 48 | Trainer(const txeo::DataTable &data) : Trainer{data.clone()} {}; 49 | 50 | /** 51 | * @brief Trains the model for specified number of epochs 52 | * 53 | * @param epochs Number of training iterations 54 | * @param metric Loss function to optimize 55 | */ 56 | virtual void fit(size_t epochs, txeo::LossFunc metric); 57 | 58 | /** 59 | * @brief Trains with early stopping based on validation performance 60 | * 61 | * @param epochs Maximum number of training iterations 62 | * @param metric Loss function to optimize 63 | * @param patience Number of epochs to wait without improvement before stopping 64 | */ 65 | virtual void fit(size_t epochs, txeo::LossFunc metric, size_t patience); 66 | 67 | /** 68 | * @brief Trains with early stopping based on validation performance and feature normalization 69 | * 70 | * @param epochs Maximum number of training iterations 71 | * @param metric Loss function to optimize 72 | * @param patience Number of epochs to wait without improvement before stopping 73 | *@param type Type of normalization 74 | */ 75 | virtual void fit(size_t epochs, txeo::LossFunc metric, size_t patience, 76 | txeo::NormalizationType type); 77 | 78 | /** 79 | * @brief Evaluates test data based on a specified metric 80 | * 81 | *@ throws txeo::TrainerError 82 | * 83 | * @param metric Loss function type 84 | * @return T Loss value 85 | */ 86 | T compute_test_loss(txeo::LossFunc metric) const; 87 | 88 | /** 89 | * @brief Makes predictions using the trained model (pure virtual) 90 | * 91 | * @param input Input tensor for prediction (shape: [samples, features]) 92 | * @return Prediction tensor (shape: [samples, outputs]) 93 | * 94 | * @throws txeo::TrainerError 95 | * 96 | * @note Must be implemented in derived classes 97 | */ 98 | virtual txeo::Tensor predict(const txeo::Tensor &input) const = 0; 99 | 100 | /** 101 | * @brief Checks if model has been trained 102 | * 103 | * @return true if training has been completed, false otherwise 104 | */ 105 | [[nodiscard]] bool is_trained() const { return _is_trained; } 106 | 107 | /** 108 | * @brief Returns the data table of this trainer 109 | * 110 | * @return const txeo::DataTable& 111 | */ 112 | const txeo::DataTable &data_table() const { return *_data_table; } 113 | 114 | /** 115 | * @brief Enable feature normalization 116 | * 117 | * @param type Type of normalization 118 | */ 119 | void enable_feature_norm(txeo::NormalizationType type); 120 | 121 | /** 122 | * @brief Disable feature normalization 123 | * 124 | * @param type Type of normalization 125 | */ 126 | void disable_feature_norm() { _is_norm_enabled = false; }; 127 | 128 | protected: 129 | Trainer() = default; 130 | 131 | bool _is_trained{false}; 132 | bool _is_early_stop{false}; 133 | size_t _patience{0}; 134 | 135 | std::unique_ptr> _data_table; 136 | txeo::Logger *_logger{nullptr}; 137 | 138 | txeo::DataTableNorm _data_table_norm; 139 | bool _is_norm_enabled{false}; 140 | 141 | virtual void train(size_t epochs, txeo::LossFunc loss_func) = 0; 142 | }; 143 | 144 | /** 145 | * @brief Exceptions concerning @ref txeo::OlsGDTrainer 146 | * 147 | */ 148 | class TrainerError : public std::runtime_error { 149 | public: 150 | using std::runtime_error::runtime_error; 151 | }; 152 | 153 | } // namespace txeo 154 | 155 | #endif -------------------------------------------------------------------------------- /examples/txeo_tensors.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/Tensor.h" 2 | #include 3 | 4 | int main() { 5 | // ============================================================================================ 6 | // 1. Basic Tensor Creation & Initialization 7 | // ============================================================================================ 8 | { 9 | std::cout << "\n=== 1. Basic Tensor Creation ===\n"; 10 | 11 | // Create 3x4 tensor filled with 5 12 | txeo::Tensor filled_tensor({3, 4}, 5); 13 | std::cout << "Filled Tensor:\n" << filled_tensor << "\n"; 14 | 15 | // Create 2x3 tensor from nested initializer list 16 | txeo::Tensor matrix{{1.1f, 2.2f, 3.3f}, {4.4f, 5.5f, 6.6f}}; 17 | std::cout << "\nMatrix Tensor:\n" << matrix << "\n"; 18 | 19 | // 3D tensor from triple nested initializer 20 | txeo::Tensor cube{{{1.1, 2.2}, {3.3, 4.4}}, {{5.5, 6.6}, {7.7, 8.8}}}; 21 | std::cout << "\n3D Tensor:\n" << cube << std::endl; 22 | } 23 | 24 | // ============================================================================================ 25 | // 2. Element Access & Modification 26 | // ============================================================================================ 27 | { 28 | std::cout << "\n\n=== 2. Element Access ===\n"; 29 | txeo::Tensor tensor{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 30 | 31 | // Safe access with bounds checking 32 | std::cout << "Element at (1,2): " << tensor.at(1, 2) << "\n"; 33 | 34 | // Unsafe but faster access 35 | tensor(2, 1) = 42; 36 | std::cout << "\nModified Tensor:\n" << tensor << "\n"; 37 | 38 | try { 39 | std::cout << tensor.at(3, 0); // Throws TensorError 40 | } catch (const txeo::TensorError &e) { 41 | std::cerr << "\nError: " << e.what() << std::endl; 42 | } 43 | } 44 | 45 | // ============================================================================================ 46 | // 3. Tensor Operations & Transformations 47 | // ============================================================================================ 48 | { 49 | std::cout << "\n\n=== 3. Tensor Operations ===\n"; 50 | txeo::Tensor original{{1, 2}, {3, 4}, {5, 6}}; 51 | 52 | // Slice first two rows 53 | auto sliced = original.slice(0, 2); 54 | std::cout << "Sliced Tensor:\n" << sliced << "\n"; 55 | 56 | // Reshape to 2x3 57 | sliced.reshape({2, 2}); 58 | std::cout << "\nReshaped Tensor:\n" << sliced << "\n"; 59 | 60 | // Flatten to 1D 61 | auto flat = sliced.flatten(); 62 | std::cout << "\nFlattened Tensor:\n" << flat << std::endl; 63 | } 64 | 65 | // ============================================================================================ 66 | // 4. Batch Processing with TensorIterator 67 | // ============================================================================================ 68 | { 69 | std::cout << "\n\n=== 4. Batch Processing ===\n"; 70 | txeo::Tensor batch{ 71 | {{1, 2}, {3, 4}}, // Sample 1 72 | {{5, 6}, {7, 8}} // Sample 2 73 | }; 74 | 75 | // Process using range-based for loop 76 | std::cout << "Batch Values: "; 77 | for (const auto &val : batch) { 78 | std::cout << val << " "; 79 | } 80 | 81 | // Direct data access 82 | float *data = batch.data(); 83 | std::cout << "\nFirst element: " << *data << std::endl; 84 | } 85 | 86 | // ============================================================================================ 87 | // 5. Advanced Initialization & Utilities 88 | // ============================================================================================ 89 | { 90 | std::cout << "\n\n=== 5. Advanced Initialization ===\n"; 91 | // From vector with explicit shape 92 | std::vector values = {1.1, 2.2, 3.3, 4.4}; 93 | txeo::Tensor vector_tensor({4}, values); 94 | std::cout << "Vector Tensor:\n" << vector_tensor << "\n"; 95 | 96 | // Random initialization 97 | txeo::Tensor random_tensor({3, 3}); 98 | random_tensor.fill_with_uniform_random(0.0f, 1.0f, 42, 123); 99 | std::cout << "\nRandom Tensor:\n" << random_tensor << "\n"; 100 | 101 | // Squeeze singleton dimension 102 | txeo::Tensor squeezed({{1}, {2}, {3}}); 103 | squeezed.squeeze(); 104 | std::cout << "\nSqueezed Tensor:\n" << squeezed << std::endl; 105 | } 106 | 107 | // ============================================================================================ 108 | // 6. Tensor Comparison & Shape Operations 109 | // ============================================================================================ 110 | { 111 | std::cout << "\n\n=== 6. Tensor Comparison ===\n"; 112 | txeo::Tensor a{{1, 2}, {3, 4}}; 113 | txeo::Tensor b{{5, 6}, {7, 8}}; 114 | 115 | // Shape comparison 116 | if (a.is_equal_shape(b)) { 117 | std::cout << "Tensors have matching shapes\n"; 118 | } 119 | 120 | // Deep copy demonstration 121 | auto c = a.clone(); 122 | std::cout << "\nOriginal Tensor:\n" << a << "\n"; 123 | std::cout << "Clone created:\n" << c << "\n"; 124 | 125 | // In-place modification 126 | c.fill(0); 127 | std::cout << "\nModified clone:\n" << c << std::endl; 128 | } 129 | 130 | return 0; 131 | } -------------------------------------------------------------------------------- /tests/tPredictor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "txeo/Predictor.h" 11 | #include "txeo/Tensor.h" 12 | #include "txeo/TensorShape.h" 13 | 14 | namespace txeo { 15 | 16 | const std::filesystem::path TEST_MODEL_PATH = "../../../../tests/test_data/model_regression"; 17 | const std::filesystem::path INVALID_MODEL_PATH = "invalid/path"; 18 | 19 | class PredictorTest : public ::testing::Test { 20 | protected: 21 | void SetUp() override {} 22 | void TearDown() override {} 23 | }; 24 | 25 | TEST_F(PredictorTest, ModelLoading) { 26 | ASSERT_NO_THROW({ Predictor predictor(TEST_MODEL_PATH); }); 27 | } 28 | 29 | TEST_F(PredictorTest, InvalidModelPath) { 30 | ASSERT_THROW({ Predictor predictor(INVALID_MODEL_PATH); }, PredictorError); 31 | } 32 | 33 | TEST_F(PredictorTest, MetadataHandling) { 34 | Predictor predictor(TEST_MODEL_PATH); 35 | 36 | const auto &inputs = predictor.get_input_metadata(); 37 | ASSERT_FALSE(inputs.empty()); 38 | EXPECT_EQ(inputs[0].first, "serving_default_dense_8_input:0"); 39 | EXPECT_EQ(inputs[0].second, TensorShape({0, 11})); 40 | 41 | const auto &outputs = predictor.get_output_metadata(); 42 | ASSERT_FALSE(outputs.empty()); 43 | EXPECT_EQ(outputs[0].first, "StatefulPartitionedCall:0"); 44 | EXPECT_EQ(outputs[0].second, TensorShape({0, 1})); 45 | } 46 | 47 | TEST_F(PredictorTest, SinglePrediction) { 48 | Predictor predictor(TEST_MODEL_PATH); 49 | 50 | Tensor input({1, 11}, {0.5869565217391305, 0.24791498520312072, 0.4, 1.0, 0.0, 1.0, 0.0, 51 | 1.0, 0.0, 0.0, 0.0}); 52 | 53 | auto output = predictor.predict(input); 54 | 55 | ASSERT_EQ(output.shape(), TensorShape({1, 1})); 56 | EXPECT_FLOAT_EQ(trunc(output(0, 0)), 9418.0f); 57 | } 58 | 59 | TEST_F(PredictorTest, BatchPrediction) { 60 | Predictor predictor(TEST_MODEL_PATH); 61 | 62 | std::vector>> inputs = { 63 | {"serving_default_dense_8_input:0", 64 | Tensor({1, 11}, {0.5869565217391305, 0.24791498520312072, 0.4, 1.0, 0.0, 1.0, 0.0, 65 | 1.0, 0.0, 0.0, 0.0})}}; 66 | 67 | auto outputs = predictor.predict_batch(inputs); 68 | 69 | ASSERT_FALSE(outputs.empty()); 70 | EXPECT_FLOAT_EQ(trunc(outputs[0](0, 0)), 9418.0f); 71 | } 72 | 73 | TEST_F(PredictorTest, EnableXLA) { 74 | Predictor predictor(TEST_MODEL_PATH); 75 | 76 | ASSERT_NO_THROW(predictor.enable_xla(true)); 77 | 78 | ASSERT_NO_THROW(predictor.enable_xla(false)); 79 | } 80 | 81 | TEST_F(PredictorTest, DeviceListing) { 82 | Predictor predictor(TEST_MODEL_PATH); 83 | 84 | auto devices = predictor.get_devices(); 85 | ASSERT_FALSE(devices.empty()); 86 | 87 | bool has_cpu = std::ranges::any_of(devices, [](const auto &d) { return d.device_type == "CPU"; }); 88 | EXPECT_TRUE(has_cpu); 89 | } 90 | 91 | TEST_F(PredictorTest, ShapeMismatch) { 92 | Predictor predictor(TEST_MODEL_PATH); 93 | 94 | Tensor input({2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); 95 | 96 | ASSERT_THROW({ auto output = predictor.predict(input); }, PredictorError); 97 | } 98 | 99 | TEST_F(PredictorTest, InvalidBatchInput) { 100 | Predictor predictor(TEST_MODEL_PATH); 101 | 102 | std::vector>> inputs = { 103 | {"invalid_input", Tensor({1, 1}, {1.0f})}}; 104 | 105 | ASSERT_THROW({ auto outputs = predictor.predict_batch(inputs); }, PredictorError); 106 | } 107 | 108 | TEST_F(PredictorTest, LoadInvalidModelThrows) { 109 | EXPECT_THROW( 110 | { txeo::Predictor predictor("non_existent_model_dir"); }, txeo::PredictorError); 111 | } 112 | 113 | TEST_F(PredictorTest, ModelWithNoInputMetadataThrows) { 114 | 115 | EXPECT_THROW({ txeo::Predictor predictor("empty_input_model"); }, txeo::PredictorError); 116 | } 117 | 118 | TEST_F(PredictorTest, ModelWithNoOutputMetadataThrows) { 119 | 120 | EXPECT_THROW({ txeo::Predictor predictor("empty_output_model"); }, txeo::PredictorError); 121 | } 122 | 123 | TEST_F(PredictorTest, PredictWithInvalidShapeThrows) { 124 | txeo::Predictor predictor(TEST_MODEL_PATH); 125 | 126 | txeo::Tensor invalid_tensor({1, 224, 224, 3}); 127 | EXPECT_THROW({ auto aux = predictor.predict(invalid_tensor); }, txeo::PredictorError); 128 | } 129 | 130 | TEST_F(PredictorTest, GetOutputMetadataShape) { 131 | txeo::Predictor predictor(TEST_MODEL_PATH); 132 | auto output_shape = predictor.get_output_metadata_shape("StatefulPartitionedCall:0"); 133 | ASSERT_TRUE(output_shape.has_value()); 134 | } 135 | 136 | TEST_F(PredictorTest, PredictBatchInvalidInputNameThrows) { 137 | txeo::Predictor predictor(TEST_MODEL_PATH); 138 | std::vector>> inputs = { 139 | {"invalid_name", txeo::Tensor({1, 224, 224, 3})}}; 140 | EXPECT_THROW({ auto aux = predictor.predict_batch(inputs); }, txeo::PredictorError); 141 | } 142 | 143 | TEST_F(PredictorTest, EnableXLAForFloat) { 144 | txeo::Predictor predictor(TEST_MODEL_PATH); 145 | predictor.enable_xla(true); 146 | predictor.enable_xla(false); 147 | } 148 | 149 | } // namespace txeo 150 | -------------------------------------------------------------------------------- /mkdocs/docs/api-reference/tensor-agg.md: -------------------------------------------------------------------------------- 1 | # TensorAgg 2 | 3 | The `TensorAgg` class of **txeo** library provides aggregation functions to simplify statistical and reduction operations on tensors in the **txeo** library. 4 | 5 | --- 6 | 7 | ## Overview 8 | 9 | `TensorAgg` provides methods for computing sums, products, statistical measures (mean, variance, median), norms, and logical reductions along specified tensor axes. 10 | 11 | --- 12 | 13 | ## API Reference 14 | 15 | | Method | Description | 16 | |----------------------------------|--------------------------------------------------| 17 | | `arg_max(tensor, axis)` | Indices of max values along axis | 18 | | `arg_min(tensor, axis)` | Indices of min values along axis | 19 | | `count_non_zero(tensor, axis)` | Counts non-zero elements along axis | 20 | | `cumulative_prod(tensor, axis)` | Computes cumulative product along axis | 21 | | `cumulative_sum(tensor, axis)` | Computes cumulative sum along axis | 22 | | `reduce_all(tensor, axes)` | Computes logical AND along axes | 23 | | `reduce_any(tensor, axes)` | Computes logical OR along axes | 24 | | `reduce_euclidean_norm(tensor, axes)` | Computes Euclidean norm along axes | 25 | | `reduce_geometric_mean(tensor, axis)` | Computes geometric mean along axis | 26 | | `reduce_max(tensor, axes)` | Finds maximum values along axes | 27 | | `reduce_maximum_norm(tensor, axis)` | Computes maximum norm along axis | 28 | | `reduce_mean(tensor, axes)` | Computes mean along axes | 29 | | `reduce_median(tensor, axis)` | Computes median along axis | 30 | | `reduce_min(tensor, axes)` | Finds minimum values along axes | 31 | | `reduce_prod(tensor, axes)` | Computes product along axes | 32 | | `reduce_standard_deviation(tensor, axis)` | Computes standard deviation along axis | 33 | | `reduce_sum(tensor, axes)` | Computes sum along axes | 34 | | `reduce_variance(tensor, axis)` | Computes variance along axis | 35 | | `sum_all(tensor)` | Sums all elements in tensor | 36 | 37 | --- 38 | 39 | ## Aggregation Operations 40 | 41 | ### Reduction Operations 42 | 43 | Compute sum, product, mean, max, min along specified axes: 44 | 45 | ```cpp 46 | #include "txeo/Tensor.h" 47 | #include "txeo/TensorAgg.h" 48 | 49 | int main() { 50 | txeo::Tensor tensor({2, 3}, {1, 2, 3, 4, 5, 6}); 51 | 52 | auto sum_result = txeo::TensorAgg::reduce_sum(tensor, {1}); // [6, 15] 53 | auto prod_result = txeo::TensorAgg::reduce_prod(tensor, {1}); // [6, 120] 54 | auto mean_result = txeo::TensorAgg::reduce_mean(tensor, {1}); // [2, 5] 55 | auto max_result = txeo::TensorAgg::reduce_max(tensor, {1}); // [3, 6] 56 | auto min_result = txeo::TensorAgg::reduce_min(tensor, {1}); // [1, 4] 57 | } 58 | ``` 59 | 60 | ### Norm Operations 61 | 62 | Compute various norms along specified axes: 63 | 64 | ```cpp 65 | // Euclidean norm 66 | auto norm_result = txeo::TensorAgg::reduce_euclidean_norm(tensor, {1}); // [3.74166, 8.77496] 67 | 68 | // Maximum norm 69 | auto max_norm_result = txeo::TensorAgg::reduce_maximum_norm(tensor, 1); // [3, 6] 70 | ``` 71 | 72 | ### Statistical Operations 73 | 74 | Calculate variance, standard deviation, median, and geometric mean: 75 | 76 | ```cpp 77 | auto var_result = txeo::TensorAgg::reduce_variance(tensor, 1); // [1.0, 1.0] 78 | auto std_result = txeo::TensorAgg::reduce_standard_deviation(tensor, 1); // [1.0, 1.0] 79 | auto median_result = txeo::TensorAgg::reduce_median(tensor, 1); // [2, 5] 80 | auto geo_mean_result = txeo::TensorAgg::reduce_geometric_mean(tensor, 1); // [1.81712, 4.93242] 81 | ``` 82 | 83 | ### Logical Operations 84 | 85 | Perform logical reductions (`all`, `any`): 86 | 87 | ```cpp 88 | txeo::Tensor logical_tensor({2, 3}, {true, false, true, true, true, false}); 89 | auto all_result = txeo::TensorAgg::reduce_all(logical_tensor, {1}); // [false, false] 90 | auto any_result = txeo::TensorAgg::reduce_any(logical_tensor, {1}); // [true, true] 91 | ``` 92 | 93 | ### Cumulative Operations 94 | 95 | Calculate cumulative sums and products: 96 | 97 | ```cpp 98 | auto cum_sum_result = txeo::TensorAgg::cumulative_sum(tensor, 1); // [[1,3,6],[4,9,15]] 99 | auto cum_prod_result = txeo::TensorAgg::cumulative_prod(tensor, 1); // [[1,2,6],[4,20,120]] 100 | ``` 101 | 102 | ### Argmax and Argmin 103 | 104 | Identify indices of max/min elements: 105 | 106 | ```cpp 107 | auto argmax_result = txeo::TensorAgg::arg_max(tensor, 1); // [2, 2] 108 | auto argmin_result = txeo::TensorAgg::arg_min(tensor, 1); // [0, 0] 109 | ``` 110 | 111 | ### Count Operations 112 | 113 | Count non-zero elements: 114 | 115 | ```cpp 116 | auto count_result = txeo::TensorAgg::count_non_zero(tensor, 1); // [3, 3] 117 | ``` 118 | 119 | ### Global Sum 120 | 121 | Compute sum of all tensor elements: 122 | 123 | ```cpp 124 | auto total_sum = txeo::TensorAgg::sum_all(tensor); // 21 125 | ``` 126 | 127 | --- 128 | 129 | For detailed API references, see individual method documentation at [txeo::TensorAgg](https://txeo-doc.netlify.app/classtxeo_1_1_tensor_agg.html). 130 | -------------------------------------------------------------------------------- /src/TensorIO.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/TensorIO.h" 2 | #include "txeo/Tensor.h" 3 | #include "txeo/TensorShape.h" 4 | #include "txeo/detail/utils.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace txeo { 14 | 15 | template 16 | Tensor TensorIO::read_text_file(bool has_header) const { 17 | std::string line; 18 | std::string word; 19 | size_t n_rows{0}; 20 | size_t n_cols{0}; 21 | size_t aux{0}; 22 | 23 | std::ifstream rf{_path}; 24 | if (rf.is_open()) { 25 | while (std::getline(rf, line)) { 26 | if (std::count(line.begin(), line.end(), _separator) == 0) { 27 | rf.close(); 28 | throw TensorIOError("Separator not found!"); 29 | }; 30 | std::stringstream line_stream{line}; 31 | while (std::getline(line_stream, word, _separator)) 32 | ++aux; 33 | if (n_cols != 0 && aux != n_cols) { 34 | rf.close(); 35 | throw TensorIOError("Inconsistent number of columns!"); 36 | } 37 | n_cols = aux; 38 | aux = 0; 39 | ++n_rows; 40 | } 41 | if (n_rows == 0) { 42 | rf.close(); 43 | throw TensorIOError("File can not be empty!"); 44 | } 45 | if (has_header) 46 | --n_rows; 47 | } else 48 | throw TensorIOError("Could not open file!"); 49 | 50 | Tensor resp{TensorShape({n_rows, n_cols})}; 51 | rf.clear(); 52 | rf.seekg(0); 53 | auto iterator = std::begin(resp); 54 | if (has_header) 55 | std::getline(rf, line); 56 | while (std::getline(rf, line)) { 57 | std::stringstream line_stream{line}; 58 | while (std::getline(line_stream, word, _separator)) { 59 | try { 60 | *iterator = static_cast(std::stod(word)); 61 | } catch (...) { 62 | rf.close(); 63 | throw TensorIOError("Invalid element!"); 64 | } 65 | ++iterator; 66 | } 67 | } 68 | rf.close(); 69 | return resp; 70 | } 71 | 72 | template 73 | void TensorIO::write_text_file(const Tensor &tensor) const { 74 | if (tensor.order() != 2) 75 | throw TensorIOError("Tensor is not a matrix!"); 76 | std::ofstream wf{_path, std::ios::out}; 77 | if (wf.is_open()) { 78 | size_t n_rows = detail::to_size_t(tensor.shape().axis_dim(0)); 79 | size_t n_cols = detail::to_size_t(tensor.shape().axis_dim(1)); 80 | auto iterator = std::cbegin(tensor); 81 | size_t aux_r{0}; 82 | while (aux_r < n_rows) { 83 | size_t aux_c{0}; 84 | while (aux_c < n_cols) { 85 | wf << std::to_string(*iterator); 86 | ++iterator; 87 | if (++aux_c < n_cols) 88 | wf << _separator; 89 | } 90 | if (++aux_r < n_rows) 91 | wf << "\n"; 92 | } 93 | wf.close(); 94 | } else 95 | throw TensorIOError("Could not open file!"); 96 | } 97 | 98 | template 99 | requires(std::is_floating_point_v) 100 | void TensorIO::write_text_file(const Tensor &tensor, size_t precision) const { 101 | if (precision <= 1) 102 | throw TensorIOError("Precision must be greater than 1!"); 103 | auto prec = precision - 1; 104 | if (tensor.order() != 2) 105 | throw TensorIOError("Tensor is not a matrix!"); 106 | std::ofstream wf{_path, std::ios::out}; 107 | if (wf.is_open()) { 108 | size_t n_rows = detail::to_size_t(tensor.shape().axis_dim(0)); 109 | size_t n_cols = detail::to_size_t(tensor.shape().axis_dim(1)); 110 | auto iterator = std::cbegin(tensor); 111 | size_t aux_r{0}; 112 | while (aux_r < n_rows) { 113 | size_t aux_c{0}; 114 | while (aux_c < n_cols) { 115 | wf << detail::format(*iterator, prec); 116 | ++iterator; 117 | if (++aux_c < n_cols) 118 | wf << _separator; 119 | } 120 | if (++aux_r < n_rows) 121 | wf << "\n"; 122 | } 123 | wf.close(); 124 | } else 125 | throw TensorIOError("Could not open file!"); 126 | } 127 | 128 | template Tensor TensorIO::read_text_file(bool has_header) const; 129 | template Tensor TensorIO::read_text_file(bool has_header) const; 130 | template Tensor TensorIO::read_text_file(bool has_header) const; 131 | template Tensor TensorIO::read_text_file(bool has_header) const; 132 | template Tensor TensorIO::read_text_file(bool has_header) const; 133 | template Tensor TensorIO::read_text_file(bool has_header) const; 134 | template Tensor TensorIO::read_text_file(bool has_header) const; 135 | template Tensor TensorIO::read_text_file(bool has_header) const; 136 | 137 | template void TensorIO::write_text_file(const Tensor &tensor) const; 138 | template void TensorIO::write_text_file(const Tensor &tensor) const; 139 | template void TensorIO::write_text_file(const Tensor &tensor) const; 140 | template void TensorIO::write_text_file(const Tensor &tensor) const; 141 | template void TensorIO::write_text_file(const Tensor &tensor) const; 142 | template void TensorIO::write_text_file(const Tensor &tensor) const; 143 | template void TensorIO::write_text_file(const Tensor &tensor) const; 144 | template void TensorIO::write_text_file(const Tensor &tensor) const; 145 | 146 | template void TensorIO::write_text_file(const Tensor &tensor, size_t precision) const; 147 | template void TensorIO::write_text_file(const Tensor &tensor, size_t precision) const; 148 | 149 | } // namespace txeo 150 | -------------------------------------------------------------------------------- /src/OlsGDTrainer.cpp: -------------------------------------------------------------------------------- 1 | #include "txeo/OlsGDTrainer.h" 2 | #include "txeo/Loss.h" 3 | #include "txeo/Matrix.h" 4 | #include "txeo/TensorAgg.h" 5 | #include "txeo/TensorFunc.h" 6 | #include "txeo/TensorOp.h" 7 | #include "txeo/TensorPart.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace txeo { 14 | enum class LossFunc; 15 | 16 | template 17 | requires(std::floating_point) 18 | void OlsGDTrainer::set_learning_rate(T learning_rate) { 19 | this->_is_trained = false; 20 | _learning_rate = learning_rate; 21 | } 22 | 23 | template 24 | requires(std::floating_point) 25 | T OlsGDTrainer::learning_rate() const { 26 | return _learning_rate; 27 | } 28 | 29 | template 30 | requires(std::floating_point) 31 | Tensor OlsGDTrainer::predict(const Tensor &input) const { 32 | auto &&x = this->_is_norm_enabled ? this->_data_table_norm.normalize(Matrix::to_matrix(input)) 33 | : input; 34 | auto aux = TensorPart::increase_dimension(x, 1, 1.0); 35 | return TensorOp::product_tensors(aux, this->weight_bias()); 36 | } 37 | 38 | template 39 | requires(std::floating_point) 40 | void OlsGDTrainer::train(size_t epochs, LossFunc metric) { 41 | 42 | this->_logger->info("OLS training started..."); 43 | 44 | auto &dt_norm = this->_data_table_norm; 45 | auto &dt = *this->_data_table; 46 | 47 | auto &&x_train = this->_is_norm_enabled ? dt_norm.x_train_normalized() : dt.x_train(); 48 | auto &&y_train = this->_data_table->y_train(); 49 | 50 | auto &&x_eval = dt.has_eval() 51 | ? (this->_is_norm_enabled ? dt_norm.x_eval_normalized() : *dt.x_eval()) 52 | : x_train; 53 | auto &&y_eval = dt.has_eval() ? *dt.y_eval() : y_train; 54 | 55 | // Input and Output data variables 56 | size_t n = x_train.shape().axis_dim(1); 57 | size_t m = y_train.shape().axis_dim(1); 58 | 59 | auto &&X = Matrix::to_matrix(TensorPart::increase_dimension(x_train, 1, 1.0)); 60 | auto &&Y = TensorFunc::transpose(y_train); 61 | 62 | auto &&Z = TensorFunc::compute_gram_matrix(X); 63 | auto &&K = Y.dot(X); 64 | 65 | _is_converged = false; 66 | 67 | // Initializing the loss class 68 | auto &&X_eval = Matrix::to_matrix(TensorPart::increase_dimension(x_eval, 1, 1.0)); 69 | Loss loss{y_eval, metric}; 70 | 71 | // Initial Guesses 72 | T norm_X = TensorAgg::reduce_euclidean_norm(X, {0, 1})(); 73 | T norm_Y = TensorAgg::reduce_euclidean_norm(Y, {0, 1})(); 74 | Matrix B_prev{m, n + 1, norm_Y / norm_X}; 75 | 76 | if (_variable_lr) 77 | _learning_rate = 1.0 / (norm_X * norm_X); 78 | 79 | auto B = B_prev - (_learning_rate * (B_prev.dot(Z) - K)); 80 | auto L = B - B_prev; 81 | 82 | // Declaring variables to capture trainer params 83 | T loss_value = std::numeric_limits::max(); 84 | T loss_value_prev = std::numeric_limits::max(); 85 | T min_loss = std::numeric_limits::max(); 86 | size_t patience = 0; 87 | Matrix B_best{}; 88 | bool found_best{false}; 89 | 90 | // Iterate OLS 91 | for (size_t e{0}; e < epochs; ++e) { 92 | auto &&B_t = TensorFunc::transpose(B); 93 | loss_value = loss.get_loss(TensorOp::product_tensors(X_eval, B_t)); 94 | this->_logger->debug( 95 | std::format("Epoch {}, Loss {}, Learning Rate {}", e, loss_value, _learning_rate)); 96 | if (std::isnan(loss_value)) { 97 | _is_converged = false; 98 | break; 99 | } 100 | if (loss_value >= loss_value_prev && this->_is_early_stop) { 101 | if (patience == this->_patience) { 102 | _is_converged = false; 103 | break; 104 | } else 105 | ++patience; 106 | } else { 107 | if (loss_value < _tolerance) { 108 | found_best = true; 109 | _is_converged = true; 110 | min_loss = loss_value; 111 | B_best = B; 112 | break; 113 | } 114 | patience = 0; 115 | } 116 | if (loss_value < min_loss) { 117 | found_best = true; 118 | min_loss = loss_value; 119 | B_best = B; 120 | } 121 | loss_value_prev = loss_value; 122 | B_prev = B; 123 | if (_variable_lr) { 124 | auto LZ = L.dot(Z); 125 | _learning_rate = std::fabs(L.inner(LZ)) / LZ.inner(LZ); 126 | }; 127 | B -= _learning_rate * (B.dot(Z) - K); 128 | L = B - B_prev; 129 | } 130 | 131 | if (found_best) { 132 | _min_loss = min_loss; 133 | _weight_bias = std::move(TensorFunc::transpose_by(B_best)); 134 | } else { 135 | _min_loss = loss_value; 136 | _weight_bias = std::move(TensorFunc::transpose_by(B)); 137 | } 138 | 139 | this->_logger->info("OLS training finished..."); 140 | } 141 | 142 | template 143 | requires(std::floating_point) 144 | const Matrix &OlsGDTrainer::weight_bias() const { 145 | if (!this->_is_trained) 146 | throw OlsGDTrainerError("Trainer is not trained."); 147 | return _weight_bias; 148 | } 149 | 150 | template 151 | requires(std::floating_point) 152 | T OlsGDTrainer::min_loss() const { 153 | if (!this->_is_trained) 154 | throw OlsGDTrainerError("Trainer is not trained."); 155 | return _min_loss; 156 | } 157 | 158 | template 159 | requires(std::floating_point) 160 | void OlsGDTrainer::set_tolerance(const T &tolerance) { 161 | this->_is_trained = false; 162 | _tolerance = tolerance; 163 | } 164 | 165 | template class OlsGDTrainer; 166 | template class OlsGDTrainer; 167 | 168 | } // namespace txeo 169 | -------------------------------------------------------------------------------- /include/txeo/Loss.h: -------------------------------------------------------------------------------- 1 | #ifndef LOSS_H 2 | #define LOSS_H 3 | #pragma once 4 | 5 | #include "txeo/Tensor.h" 6 | #include "txeo/types.h" 7 | 8 | #include 9 | #include 10 | namespace txeo { 11 | template 12 | class Tensor; 13 | 14 | /** 15 | * @class Loss 16 | * @brief Computes error metrics between predicted and validation tensors. 17 | * 18 | * Supports multiple loss functions that can be selected at runtime: 19 | * - MSE (Mean Squared Error) 20 | * - MAE (Mean Absolute Error) 21 | * - MSLE (Mean Squared Logarithmic Error) 22 | * - LCHE (Log-Cosh Error) 23 | * 24 | * @tparam T Numeric type of tensor elements (float/double recommended) 25 | * 26 | * @note All operations validate tensor shape compatibility between predictions and validation data; 27 | * @note First axis's dimension of the tensors involved must refer to number of samples 28 | */ 29 | template 30 | class Loss { 31 | public: 32 | Loss(const Loss &) = default; 33 | Loss(Loss &&) = default; 34 | Loss &operator=(const Loss &) = default; 35 | Loss &operator=(Loss &&) = default; 36 | ~Loss() = default; 37 | 38 | /** 39 | * @brief Construct a new Loss object from a label rvalue 40 | * 41 | * @param label Labe tensor containing ground truth values 42 | * @param func Initial loss function (default: MSE) 43 | * 44 | * @par Example: 45 | * @code 46 | * // Create with MAE as default loss 47 | * txeo::Loss loss(validation_tensor, txeo::LossFunc::MAE); 48 | * @endcode 49 | */ 50 | explicit Loss(txeo::Tensor &&label, txeo::LossFunc func = txeo::LossFunc::MSE); 51 | 52 | /** 53 | * @brief Construct a new Loss object 54 | * 55 | * @param label Label tensor containing ground truth values 56 | * @param func Initial loss function (default: MSE) 57 | * 58 | * @par Example: 59 | * @code 60 | * // Create with MAE as default loss 61 | * txeo::Loss loss(validation_tensor, txeo::LossFunc::MAE); 62 | * @endcode 63 | */ 64 | explicit Loss(const txeo::Tensor &label, txeo::LossFunc func = txeo::LossFunc::MSE) 65 | : Loss{label.clone(), func} {}; 66 | 67 | /** 68 | * @brief Compute loss using currently selected function 69 | * 70 | * @param pred Prediction tensor 71 | * @return T Calculated loss value 72 | * @throw LossError If shapes mismatch or invalid input values 73 | * 74 | * @par Example: 75 | * @code 76 | * auto error = loss.get_loss(predictions); 77 | * std::cout << "Current loss: " << error << std::endl; 78 | * @endcode 79 | */ 80 | T get_loss(const txeo::Tensor &pred) const; 81 | 82 | /** 83 | * @brief Set the active loss function 84 | * 85 | * @param func Loss function to use for subsequent calculations 86 | * 87 | * @par Example: 88 | * @code 89 | * // Switch to log-cosh error 90 | * loss.set_loss(txeo::LossFunc::LCHE); 91 | * @endcode 92 | */ 93 | void set_loss(txeo::LossFunc func); 94 | 95 | /** 96 | * @brief Compute Mean Squared Error (MSE) 97 | * 98 | * @f[ MSE = \frac{1}{N}\sum_{i=1}^{N}(y_i - \hat{y}_i)^2 @f] 99 | * 100 | * @param pred Prediction tensor 101 | * @return T MSE value 102 | */ 103 | T mean_squared_error(const txeo::Tensor &pred) const; 104 | 105 | /** 106 | * @brief Compute Mean Absolute Error (MAE) 107 | * 108 | * @f[ MAE = \frac{1}{N}\sum_{i=1}^{N}|y_i - \hat{y}_i| @f] 109 | * 110 | * @param pred Prediction tensor 111 | * @return T MAE value 112 | */ 113 | T mean_absolute_error(const txeo::Tensor &pred) const; 114 | 115 | /** 116 | * @brief Compute Mean Squared Logarithmic Error (MSLE) 117 | * 118 | * @f[ MSLE = \frac{1}{N}\sum_{i=1}^{N}(\log(1+y_i) - \log(1+\hat{y}_i))^2 @f] 119 | * 120 | * @param pred Prediction tensor 121 | * @return T MSLE value 122 | * @throw LossError If any values are negative 123 | */ 124 | T mean_squared_logarithmic_error(const txeo::Tensor &pred) const; 125 | 126 | /** 127 | * @brief Compute Log-Cosh Error (LCHE) 128 | * 129 | * @f[ LCHE = \frac{1}{N}\sum_{i=1}^{N}\log(\cosh(y_i - \hat{y}_i)) @f] 130 | * 131 | * @param pred Prediction tensor 132 | * @return T LCHE value 133 | */ 134 | T log_cosh_error(const txeo::Tensor &pred) const; 135 | 136 | const txeo::Tensor &label() const { return _label; } 137 | 138 | /// @name Shorthand Aliases 139 | /// @{ 140 | T mse(const txeo::Tensor &pred) const { 141 | return mean_squared_error(pred); 142 | }; ///< @see mean_squared_error 143 | 144 | T mae(const txeo::Tensor &pred) const { 145 | return mean_absolute_error(pred); 146 | }; ///< @see mean_absolute_error 147 | 148 | T msle(const txeo::Tensor &pred) const { 149 | return mean_squared_logarithmic_error(pred); 150 | }; ///< @see mean_squared_logarithmic_error 151 | 152 | T lche(const txeo::Tensor &pred) const { 153 | return log_cosh_error(pred); 154 | }; ///< @see log_cosh_error 155 | /// @} 156 | 157 | private: 158 | Loss() = default; 159 | txeo::Tensor _label{}; 160 | 161 | void verify_parameter(const txeo::Tensor &pred) const; 162 | std::function &)> _loss_func; 163 | }; 164 | 165 | /** 166 | * @brief Exceptions concerning @ref txeo::Loss 167 | * 168 | */ 169 | class LossError : public std::runtime_error { 170 | public: 171 | using std::runtime_error::runtime_error; 172 | }; 173 | 174 | } // namespace txeo 175 | 176 | #endif -------------------------------------------------------------------------------- /include/txeo/OlsGDTrainer.h: -------------------------------------------------------------------------------- 1 | #ifndef OLSGDTRAINER_H 2 | #define OLSGDTRAINER_H 3 | #pragma once 4 | 5 | #include "txeo/Matrix.h" 6 | #include "txeo/Tensor.h" 7 | #include "txeo/TensorShape.h" 8 | #include "txeo/Trainer.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace txeo { 15 | enum class LossFunc; 16 | 17 | /** 18 | * @class OlsGDTrainer 19 | * @brief Ordinary Least Squares trainer using Gradient Descent optimization 20 | * 21 | * @tparam T Floating-point type for calculations (float, double, etc.) 22 | * 23 | * Implements linear regression training through gradient descent with: 24 | * - Configurable learning rate 25 | * - Convergence tolerance 26 | * - Variable learning rate support (Barzilai-Borwein Method) 27 | * - Weight/bias matrix access 28 | * 29 | * Inherits from txeo::Trainer and implements required virtual methods. 30 | * 31 | * Implements algorithms based on paper: 32 | * Algarte, R.D., "Tensor-Based Foundations of Ordinary Least Squares and Neural Network Regression 33 | * Models" (https://arxiv.org/abs/2411.12873) 34 | * 35 | * **Example Usage:** 36 | * @code 37 | * // Create training data (y = 2x + 1) 38 | * txeo::Matrix X({{1.0}, {2.0}, {3.0}}); // 3x1 39 | * txeo::Matrix y({{3.0}, {5.0}, {7.0}}); // 3x1 40 | * 41 | * OlsGDTrainer trainer(X, y); 42 | * trainer.set_tolerance(1e-5); 43 | * 44 | * // Train with early stopping 45 | * trainer.fit(1000, LossFunc::MSE, 10); 46 | * 47 | * if(trainer.is_converged()) { 48 | * auto weights = trainer.weight_bias(); 49 | * std::cout << "Model: y = " << weights(0,0) << "x + " << weights(1,0) << std::endl; 50 | * 51 | * // Make prediction 52 | * txeo::Matrix test_input(1,1,{4.0}); 53 | * auto prediction = trainer.predict(test_input); 54 | * std::cout << "Prediction for x=4: " << prediction(0,0) << std::endl; 55 | * } 56 | * @endcode 57 | */ 58 | template 59 | requires(std::floating_point) 60 | class OlsGDTrainer : public txeo::Trainer { 61 | public: 62 | OlsGDTrainer(const OlsGDTrainer &) = delete; 63 | OlsGDTrainer(OlsGDTrainer &&) = delete; 64 | OlsGDTrainer &operator=(const OlsGDTrainer &) = delete; 65 | OlsGDTrainer &operator=(OlsGDTrainer &&) = delete; 66 | ~OlsGDTrainer() = default; 67 | 68 | /** 69 | * @brief Construct a new OlsGD Trainer object from a data table 70 | * 71 | * @param data Training/Evaluation/Test data 72 | */ 73 | OlsGDTrainer(txeo::DataTable &&data) : txeo::Trainer(std::move(data)) {}; 74 | 75 | OlsGDTrainer(const txeo::DataTable &data) : txeo::Trainer(data) {}; 76 | 77 | /** 78 | * @brief Makes predictions using learned weights 79 | * 80 | * @param input Feature matrix (shape: [samples, features]) 81 | * @return Prediction matrix (shape: [samples, outputs]) 82 | * 83 | * @throws OlsGDTrainerError 84 | */ 85 | txeo::Tensor predict(const txeo::Tensor &input) const override; 86 | 87 | /** 88 | * @brief Gets current learning rate 89 | * 90 | * @return Current learning rate value 91 | */ 92 | [[nodiscard]] T learning_rate() const; 93 | 94 | /** 95 | * @brief Sets learning rate for gradient descent 96 | * 97 | * @param learning_rate Must be > 0 98 | * 99 | * @throws OlsGDTrainerError for invalid values 100 | */ 101 | void set_learning_rate(T learning_rate); 102 | 103 | /** 104 | * @brief Enables adaptive learning rate adjustment (Barzilai-Borwein Method). 105 | * When enabled, learning rate automatically reduces when loss plateaus. For the majority of the 106 | * cases, convergence drastically increases. 107 | */ 108 | void enable_variable_lr() { _variable_lr = true; } 109 | 110 | /** 111 | * @brief Disables adaptive learning rate adjustment (Barzilai-Borwein Method) 112 | */ 113 | void disable_variable_lr() { _variable_lr = false; } 114 | 115 | /** 116 | * @brief Gets weight/bias matrix related to the minimum loss during fit 117 | * 118 | * @return Matrix containing model parameters (shape: [features+1, outputs]) 119 | * 120 | * @throws OlsGDTrainerError 121 | */ 122 | const txeo::Matrix &weight_bias() const; 123 | 124 | /** 125 | * @brief Gets convergence tolerance 126 | * 127 | * @return Current tolerance value 128 | */ 129 | T tolerance() const { return _tolerance; } 130 | 131 | /** 132 | * @brief Sets convergence tolerance 133 | * 134 | * @param tolerance Minimum loss difference to consider converged (>0) 135 | */ 136 | void set_tolerance(const T &tolerance); 137 | 138 | /** 139 | * @brief Checks convergence status 140 | * 141 | * @return true if training converged before max epochs 142 | */ 143 | [[nodiscard]] bool is_converged() const { return _is_converged; } 144 | 145 | /** 146 | * @brief Gets the minimum loss during training 147 | * 148 | * @return Value of the minimum loss 149 | */ 150 | T min_loss() const; 151 | 152 | private: 153 | T _learning_rate{0.01}; 154 | T _tolerance{0.001}; 155 | T _min_loss{0}; 156 | txeo::Matrix _weight_bias{}; 157 | bool _variable_lr{false}; 158 | bool _is_converged{false}; 159 | 160 | OlsGDTrainer() = default; 161 | void train(size_t epochs, txeo::LossFunc metric) override; 162 | }; 163 | 164 | /** 165 | * @brief Exceptions concerning @ref txeo::OlsGDTrainer 166 | * 167 | */ 168 | class OlsGDTrainerError : public std::runtime_error { 169 | public: 170 | using std::runtime_error::runtime_error; 171 | }; 172 | 173 | } // namespace txeo 174 | 175 | #endif --------------------------------------------------------------------------------