init: 初始化krylov复现项目
This commit is contained in:
58
.gitignore
vendored
Normal file
58
.gitignore
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env/
|
||||||
|
.venv
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
.pytest_cache/
|
||||||
|
.coverage
|
||||||
|
htmlcov/
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# OS
|
||||||
|
Thumbs.db
|
||||||
|
.DS_Store
|
||||||
78
CMakeLists.txt
Normal file
78
CMakeLists.txt
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
project(krylov_gmres VERSION 0.1.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
option(KRYLOV_BUILD_TESTS "Build krylov unit tests" ON)
|
||||||
|
|
||||||
|
# 避免 Eigen / spdlog 把自己的测试注册进 CTest
|
||||||
|
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
||||||
|
set(EIGEN_BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
||||||
|
set(EIGEN_BUILD_DOC OFF CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
|
# ---------------- 第三方依赖 ----------------
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
eigen
|
||||||
|
GIT_REPOSITORY https://aliyun.mayblog.top/devtools/eigen.git
|
||||||
|
GIT_TAG 3.4.0
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
spdlog
|
||||||
|
GIT_REPOSITORY https://aliyun.mayblog.top/devtools/spdlog.git
|
||||||
|
GIT_TAG v1.11.0
|
||||||
|
)
|
||||||
|
|
||||||
|
# Eigen 是 header-only,避免 add_subdirectory 把其庞大测试集带进 CTest
|
||||||
|
FetchContent_GetProperties(eigen)
|
||||||
|
if(NOT eigen_POPULATED)
|
||||||
|
FetchContent_Populate(eigen)
|
||||||
|
endif()
|
||||||
|
add_library(Eigen3_Eigen INTERFACE)
|
||||||
|
target_include_directories(Eigen3_Eigen INTERFACE ${eigen_SOURCE_DIR})
|
||||||
|
add_library(Eigen3::Eigen ALIAS Eigen3_Eigen)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(spdlog)
|
||||||
|
|
||||||
|
# ---------------- 通用 logger 库(与 krylov 解耦,可独立复用) ----------------
|
||||||
|
add_library(logger STATIC
|
||||||
|
src/logger/logger.cpp
|
||||||
|
)
|
||||||
|
target_include_directories(logger PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
target_link_libraries(logger PUBLIC spdlog::spdlog)
|
||||||
|
|
||||||
|
# ---------------- Krylov 核心库 ----------------
|
||||||
|
# 算法实现(arnoldi / gmres ...)集中到 krylov_core。
|
||||||
|
# 目前仅依赖 Eigen 与通用 logger。
|
||||||
|
add_library(krylov_core INTERFACE)
|
||||||
|
target_include_directories(krylov_core INTERFACE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
target_link_libraries(krylov_core INTERFACE
|
||||||
|
Eigen3::Eigen
|
||||||
|
logger
|
||||||
|
)
|
||||||
|
add_library(krylov::core ALIAS krylov_core)
|
||||||
|
|
||||||
|
# ---------------- 可执行文件 ----------------
|
||||||
|
add_executable(krylov_solver src/main.cpp)
|
||||||
|
target_link_libraries(krylov_solver PRIVATE krylov::core)
|
||||||
|
|
||||||
|
# ---------------- 测试 ----------------
|
||||||
|
if(KRYLOV_BUILD_TESTS)
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
add_executable(test_logger tests/test_logger.cpp)
|
||||||
|
target_link_libraries(test_logger PRIVATE krylov::core)
|
||||||
|
add_test(NAME test_logger COMMAND test_logger)
|
||||||
|
|
||||||
|
add_executable(test_eigen tests/test_eigen.cpp)
|
||||||
|
target_link_libraries(test_eigen PRIVATE krylov::core)
|
||||||
|
add_test(NAME test_eigen COMMAND test_eigen)
|
||||||
|
endif()
|
||||||
0
data/.gitkeep
Normal file
0
data/.gitkeep
Normal file
1
include/krylov/arnoldi.hpp
Normal file
1
include/krylov/arnoldi.hpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#pragma once
|
||||||
1
include/krylov/gmres.hpp
Normal file
1
include/krylov/gmres.hpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#pragma once
|
||||||
31
include/krylov/types/common.hpp
Normal file
31
include/krylov/types/common.hpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Krylov 项目公共数值类型别名。
|
||||||
|
//
|
||||||
|
// 约定:算法代码只使用本文件中的别名,不直接写裸 Eigen 类型。
|
||||||
|
// 后续若要切换精度 (float/double)、索引宽度或矩阵存储布局,
|
||||||
|
// 只需改动此文件,无需触碰算法实现。
|
||||||
|
//
|
||||||
|
// 规模变大后可拆分为:
|
||||||
|
// - krylov/types/dense.hpp
|
||||||
|
// - krylov/types/sparse.hpp
|
||||||
|
// - krylov/types/traits.hpp
|
||||||
|
|
||||||
|
#include <Eigen/Dense>
|
||||||
|
#include <Eigen/Sparse>
|
||||||
|
|
||||||
|
namespace krylov {
|
||||||
|
|
||||||
|
// 标量与索引
|
||||||
|
using Scalar = double;
|
||||||
|
using Index = Eigen::Index;
|
||||||
|
|
||||||
|
// 稠密
|
||||||
|
using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
|
||||||
|
using Matrix = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
|
||||||
|
|
||||||
|
// 稀疏(行主序,方便按行遍历 SpMV)
|
||||||
|
using SparseMatrix = Eigen::SparseMatrix<Scalar, Eigen::RowMajor, Index>;
|
||||||
|
using Triplet = Eigen::Triplet<Scalar, Index>;
|
||||||
|
|
||||||
|
} // namespace krylov
|
||||||
69
include/logger/logger.hpp
Normal file
69
include/logger/logger.hpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <spdlog/async.h>
|
||||||
|
#include <spdlog/sinks/rotating_file_sink.h>
|
||||||
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||||
|
#include <spdlog/details/thread_pool.h> // 新增:引入thread_pool所在头文件
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector> // 新增:用于sink向量转换,避免编译报错
|
||||||
|
|
||||||
|
// 单例模式封装 logger,全局唯一,支持多模块、局部级别、异步输出
|
||||||
|
class Logger {
|
||||||
|
public:
|
||||||
|
// 禁止拷贝构造和赋值运算符(单例)
|
||||||
|
Logger(const Logger&) = delete;
|
||||||
|
Logger& operator=(const Logger&) = delete;
|
||||||
|
|
||||||
|
// 初始化 logger(必须在程序启动时调用,建议main函数开头)
|
||||||
|
// 参数:日志文件路径、日志文件最大大小(MB)、备份文件数量、是否开启异步
|
||||||
|
static void Init(const std::string& log_path = "logs/app.log",
|
||||||
|
size_t max_file_size_mb = 5,
|
||||||
|
size_t max_backup_count = 3,
|
||||||
|
bool is_async = true);
|
||||||
|
|
||||||
|
// 获取全局默认 logger(通用日志)
|
||||||
|
static std::shared_ptr<spdlog::logger> GetDefaultLogger();
|
||||||
|
|
||||||
|
// 获取指定模块的 logger(局部 logger,支持单独设置级别)
|
||||||
|
// 模块名示例:"net"(网络模块)、"db"(数据库模块)、"ui"(界面模块)
|
||||||
|
static std::shared_ptr<spdlog::logger> GetModuleLogger(const std::string& module_name);
|
||||||
|
|
||||||
|
// 设置全局默认日志级别(对所有未单独设置级别的 logger 生效)
|
||||||
|
static void SetGlobalLevel(spdlog::level::level_enum level);
|
||||||
|
|
||||||
|
// 设置指定模块 logger 的局部级别(优先级高于全局级别)
|
||||||
|
static void SetModuleLevel(const std::string& module_name, spdlog::level::level_enum level);
|
||||||
|
|
||||||
|
// 关闭所有 logger,释放资源(建议程序退出时调用)
|
||||||
|
static void Shutdown();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// 私有构造函数(单例)
|
||||||
|
Logger();
|
||||||
|
// 析构函数
|
||||||
|
~Logger() = default;
|
||||||
|
|
||||||
|
// 单例实例
|
||||||
|
static Logger& GetInstance();
|
||||||
|
|
||||||
|
// 全局线程池(异步日志使用)- 修复:thread_pool在spdlog::details命名空间下
|
||||||
|
std::shared_ptr<spdlog::details::thread_pool> thread_pool_;
|
||||||
|
// 全局默认 logger
|
||||||
|
std::shared_ptr<spdlog::logger> default_logger_;
|
||||||
|
// 新增:存储全局日志格式,供模块logger复用(避免formatter()方法兼容问题)
|
||||||
|
std::string log_pattern_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 便捷宏定义(简化调用,可根据需求开启/关闭)
|
||||||
|
#define LOG_INFO(...) Logger::GetDefaultLogger()->info(__VA_ARGS__)
|
||||||
|
#define LOG_WARN(...) Logger::GetDefaultLogger()->warn(__VA_ARGS__)
|
||||||
|
#define LOG_ERROR(...) Logger::GetDefaultLogger()->error(__VA_ARGS__)
|
||||||
|
#define LOG_DEBUG(...) Logger::GetDefaultLogger()->debug(__VA_ARGS__)
|
||||||
|
#define LOG_CRITICAL(...) Logger::GetDefaultLogger()->critical(__VA_ARGS__)
|
||||||
|
#define LOG_TRACE(...) Logger::GetDefaultLogger()->trace(__VA_ARGS__)
|
||||||
|
|
||||||
|
// 模块日志宏定义(示例,可自行扩展)
|
||||||
|
#define LOG_NET_INFO(...) Logger::GetModuleLogger("net")->info(__VA_ARGS__)
|
||||||
|
#define LOG_DB_WARN(...) Logger::GetModuleLogger("db")->warn(__VA_ARGS__)
|
||||||
|
#define LOG_UI_ERROR(...) Logger::GetModuleLogger("ui")->error(__VA_ARGS__)
|
||||||
0
python/.gitkeep
Normal file
0
python/.gitkeep
Normal file
156
src/logger/logger.cpp
Normal file
156
src/logger/logger.cpp
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
#include "logger/logger.hpp"
|
||||||
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
|
#include <spdlog/details/thread_pool.h> // 新增:引入thread_pool所在头文件
|
||||||
|
|
||||||
|
// 私有构造函数,初始化日志核心配置
|
||||||
|
Logger::Logger() {
|
||||||
|
// 1. 创建日志目录(若不存在)
|
||||||
|
std::filesystem::path log_dir = std::filesystem::path("logs");
|
||||||
|
if (!std::filesystem::exists(log_dir)) {
|
||||||
|
try {
|
||||||
|
std::filesystem::create_directories(log_dir);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Failed to create log directory: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单例实例获取(懒汉模式,线程安全)
|
||||||
|
Logger& Logger::GetInstance() {
|
||||||
|
static Logger instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化 logger(核心方法)
|
||||||
|
void Logger::Init(const std::string& log_path, size_t max_file_size_mb, size_t max_backup_count, bool is_async) {
|
||||||
|
auto& instance = GetInstance();
|
||||||
|
|
||||||
|
// 1. 配置日志格式(统一格式,包含时间、模块名、级别、线程ID、日志内容)
|
||||||
|
std::string log_pattern = "[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] [thread %t] %v";
|
||||||
|
|
||||||
|
// 2. 创建 sink(控制台 + 滚动文件)
|
||||||
|
// 控制台 sink(带颜色)
|
||||||
|
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||||
|
// 滚动文件 sink(按大小滚动,避免单个文件过大)
|
||||||
|
size_t max_file_size = max_file_size_mb * 1024 * 1024; // 转换为字节
|
||||||
|
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
|
||||||
|
log_path, max_file_size, max_backup_count, true // true = 追加模式
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. 组合 sink(同时输出到控制台和文件)
|
||||||
|
spdlog::sinks_init_list sinks = {console_sink, file_sink};
|
||||||
|
|
||||||
|
// 4. 初始化异步日志(若开启)
|
||||||
|
if (is_async) {
|
||||||
|
// 线程池配置:队列大小 8192,线程数 4(可根据CPU核心数调整)
|
||||||
|
// 修复1:thread_pool在spdlog::details命名空间下
|
||||||
|
instance.thread_pool_ = std::make_shared<spdlog::details::thread_pool>(8192, 4);
|
||||||
|
// 创建异步默认 logger
|
||||||
|
instance.default_logger_ = std::make_shared<spdlog::async_logger>(
|
||||||
|
"default", sinks.begin(), sinks.end(),
|
||||||
|
instance.thread_pool_,
|
||||||
|
spdlog::async_overflow_policy::block // 队列满时阻塞(避免日志丢失,生产环境推荐)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 同步日志(简单场景使用)
|
||||||
|
instance.default_logger_ = std::make_shared<spdlog::logger>("default", sinks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 全局配置(默认级别、格式、刷新策略)
|
||||||
|
instance.default_logger_->set_pattern(log_pattern);
|
||||||
|
instance.default_logger_->set_level(spdlog::level::info); // 默认全局级别:info
|
||||||
|
spdlog::set_default_logger(instance.default_logger_);
|
||||||
|
|
||||||
|
// 6. 刷新策略(确保日志及时写入,避免崩溃丢失)
|
||||||
|
spdlog::flush_every(std::chrono::seconds(3)); // 每3秒自动刷新
|
||||||
|
spdlog::flush_on(spdlog::level::err); // 错误级别日志立即刷新
|
||||||
|
|
||||||
|
// 初始化提示(仅控制台输出)
|
||||||
|
// 修复2:sink的log方法只接受log_msg参数,改用logger输出
|
||||||
|
instance.default_logger_->info("Logger initialized successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取全局默认 logger
|
||||||
|
std::shared_ptr<spdlog::logger> Logger::GetDefaultLogger() {
|
||||||
|
auto& instance = GetInstance();
|
||||||
|
if (!instance.default_logger_) {
|
||||||
|
std::cerr << "Logger not initialized! Call Logger::Init() first." << std::endl;
|
||||||
|
// 若未初始化,返回一个临时控制台 logger,避免崩溃
|
||||||
|
return spdlog::stdout_color_mt("temp_default");
|
||||||
|
}
|
||||||
|
return instance.default_logger_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取指定模块的 logger(局部 logger)
|
||||||
|
std::shared_ptr<spdlog::logger> Logger::GetModuleLogger(const std::string& module_name) {
|
||||||
|
auto& instance = GetInstance();
|
||||||
|
if (!instance.default_logger_) {
|
||||||
|
std::cerr << "Logger not initialized! Call Logger::Init() first." << std::endl;
|
||||||
|
return spdlog::stdout_color_mt(module_name + "_temp");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 若模块 logger 已存在,直接返回;不存在则创建
|
||||||
|
auto module_logger = spdlog::get(module_name);
|
||||||
|
if (!module_logger) {
|
||||||
|
// 模块 logger 复用 控制台+文件 sink,与默认 logger 输出一致
|
||||||
|
// 修复3:sinks()返回vector,无法直接转为sinks_init_list,改用手动添加(适配所有spdlog版本)
|
||||||
|
auto& default_sinks = instance.default_logger_->sinks();
|
||||||
|
std::vector<std::shared_ptr<spdlog::sinks::sink>> module_sinks;
|
||||||
|
for (auto& sink : default_sinks) {
|
||||||
|
module_sinks.push_back(sink);
|
||||||
|
}
|
||||||
|
// 若开启异步,使用全局线程池;否则同步创建
|
||||||
|
// 修复4:thread_pool在spdlog::details命名空间下
|
||||||
|
if (instance.thread_pool_) {
|
||||||
|
module_logger = std::make_shared<spdlog::async_logger>(
|
||||||
|
module_name, module_sinks.begin(), module_sinks.end(),
|
||||||
|
instance.thread_pool_,
|
||||||
|
spdlog::async_overflow_policy::block
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
module_logger = std::make_shared<spdlog::logger>(module_name, module_sinks.begin(), module_sinks.end());
|
||||||
|
}
|
||||||
|
// 模块 logger 继承全局格式,级别可后续单独设置
|
||||||
|
module_logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] [thread %t] %v");
|
||||||
|
module_logger->set_level(instance.default_logger_->level()); // 初始继承全局级别
|
||||||
|
spdlog::register_logger(module_logger); // 注册到 spdlog 全局管理
|
||||||
|
}
|
||||||
|
return module_logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置全局默认日志级别
|
||||||
|
void Logger::SetGlobalLevel(spdlog::level::level_enum level) {
|
||||||
|
auto& instance = GetInstance();
|
||||||
|
if (instance.default_logger_) {
|
||||||
|
instance.default_logger_->set_level(level);
|
||||||
|
// 同步所有未单独设置级别的模块 logger(可选,根据需求调整)
|
||||||
|
// 修复6:spdlog无get_all()方法,改用spdlog::get()遍历已注册模块(这里简化实现,适配所有版本)
|
||||||
|
// 常用模块名可手动添加,避免版本兼容问题
|
||||||
|
std::vector<std::string> module_names = {"net", "db", "ui"};
|
||||||
|
for (const auto& name : module_names) {
|
||||||
|
auto logger = spdlog::get(name);
|
||||||
|
if (logger && logger->level() == instance.default_logger_->level()) {
|
||||||
|
logger->set_level(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cerr << "Logger not initialized! Call Logger::Init() first." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置指定模块 logger 的局部级别
|
||||||
|
void Logger::SetModuleLevel(const std::string& module_name, spdlog::level::level_enum level) {
|
||||||
|
auto module_logger = spdlog::get(module_name);
|
||||||
|
if (module_logger) {
|
||||||
|
module_logger->set_level(level);
|
||||||
|
} else {
|
||||||
|
std::cerr << "Module logger [" << module_name << "] not found! Call GetModuleLogger() first." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭所有 logger,释放资源
|
||||||
|
void Logger::Shutdown() {
|
||||||
|
spdlog::shutdown();
|
||||||
|
std::cout << "Logger shutdown successfully!" << std::endl;
|
||||||
|
}
|
||||||
8
src/main.cpp
Normal file
8
src/main.cpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include "logger/logger.hpp"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Logger::Init();
|
||||||
|
Logger::SetGlobalLevel(spdlog::level::debug);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
59
tests/test_eigen.cpp
Normal file
59
tests/test_eigen.cpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#include "krylov/types/common.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
static bool approx(double a, double b, double eps = 1e-10) {
|
||||||
|
return std::abs(a - b) < eps;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using krylov::Matrix;
|
||||||
|
using krylov::Vector;
|
||||||
|
using MatrixXd = Matrix;
|
||||||
|
using VectorXd = Vector;
|
||||||
|
|
||||||
|
// 1) 基本矩阵 / 向量运算
|
||||||
|
MatrixXd A(2, 2);
|
||||||
|
A << 4, 1,
|
||||||
|
2, 3;
|
||||||
|
VectorXd b(2);
|
||||||
|
b << 1, 2;
|
||||||
|
|
||||||
|
VectorXd Ab = A * b;
|
||||||
|
assert(approx(Ab(0), 4 * 1 + 1 * 2));
|
||||||
|
assert(approx(Ab(1), 2 * 1 + 3 * 2));
|
||||||
|
|
||||||
|
// 2) 行列式 / 逆
|
||||||
|
assert(approx(A.determinant(), 4 * 3 - 1 * 2));
|
||||||
|
MatrixXd I = A * A.inverse();
|
||||||
|
assert(approx(I(0, 0), 1.0));
|
||||||
|
assert(approx(I(1, 1), 1.0));
|
||||||
|
assert(approx(I(0, 1), 0.0));
|
||||||
|
assert(approx(I(1, 0), 0.0));
|
||||||
|
|
||||||
|
// 3) 线性方程求解 A x = b
|
||||||
|
VectorXd x = A.colPivHouseholderQr().solve(b);
|
||||||
|
VectorXd r = A * x - b;
|
||||||
|
assert(r.norm() < 1e-10);
|
||||||
|
|
||||||
|
// 4) 范数
|
||||||
|
VectorXd v(3);
|
||||||
|
v << 3, 0, 4;
|
||||||
|
assert(approx(v.norm(), 5.0));
|
||||||
|
assert(approx(v.squaredNorm(), 25.0));
|
||||||
|
|
||||||
|
// 5) 稀疏矩阵基础
|
||||||
|
krylov::SparseMatrix S(3, 3);
|
||||||
|
S.insert(0, 0) = 1.0;
|
||||||
|
S.insert(1, 1) = 2.0;
|
||||||
|
S.insert(2, 2) = 3.0;
|
||||||
|
S.makeCompressed();
|
||||||
|
VectorXd y(3);
|
||||||
|
y << 1, 1, 1;
|
||||||
|
VectorXd Sy = S * y;
|
||||||
|
assert(approx(Sy(0), 1.0));
|
||||||
|
assert(approx(Sy(1), 2.0));
|
||||||
|
assert(approx(Sy(2), 3.0));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
57
tests/test_logger.cpp
Normal file
57
tests/test_logger.cpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#include "logger/logger.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
static std::string read_file(const fs::path& p) {
|
||||||
|
std::ifstream in(p);
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << in.rdbuf();
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
const fs::path log_path = "logs/test_logger.log";
|
||||||
|
if (fs::exists(log_path)) fs::remove(log_path);
|
||||||
|
|
||||||
|
// 同步模式便于立即断言文件内容
|
||||||
|
Logger::Init(log_path.string(), 1, 2, /*is_async=*/false);
|
||||||
|
|
||||||
|
// 1) 默认 logger 可用
|
||||||
|
auto def = Logger::GetDefaultLogger();
|
||||||
|
assert(def != nullptr);
|
||||||
|
|
||||||
|
// 2) 全局级别设置生效
|
||||||
|
Logger::SetGlobalLevel(spdlog::level::debug);
|
||||||
|
assert(def->level() == spdlog::level::debug);
|
||||||
|
|
||||||
|
// 3) 模块 logger 创建 + 复用
|
||||||
|
auto net1 = Logger::GetModuleLogger("net");
|
||||||
|
auto net2 = Logger::GetModuleLogger("net");
|
||||||
|
assert(net1 != nullptr);
|
||||||
|
assert(net1.get() == net2.get());
|
||||||
|
|
||||||
|
// 4) 模块级别独立设置
|
||||||
|
Logger::SetModuleLevel("net", spdlog::level::warn);
|
||||||
|
assert(net1->level() == spdlog::level::warn);
|
||||||
|
|
||||||
|
// 5) 写日志并落盘
|
||||||
|
LOG_INFO("hello {}", "logger");
|
||||||
|
LOG_DEBUG("debug value = {}", 123);
|
||||||
|
net1->error("net module error {}", 7);
|
||||||
|
def->flush();
|
||||||
|
net1->flush();
|
||||||
|
|
||||||
|
assert(fs::exists(log_path));
|
||||||
|
std::string content = read_file(log_path);
|
||||||
|
assert(content.find("hello logger") != std::string::npos);
|
||||||
|
assert(content.find("debug value = 123") != std::string::npos);
|
||||||
|
assert(content.find("net module error 7") != std::string::npos);
|
||||||
|
|
||||||
|
Logger::Shutdown();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user