Initial commit: extract M20 sim2real into ROS1 invicta project
Source: DeepRoboticsLab/sdk_deploy (BSD-3-Clause), M20 sim2real part only. Packages: - invicta_msgs: JointCommandArray, MotionCommand, MotionState; standard messages (sensor_msgs/JointState, sensor_msgs/Imu) elsewhere; shared motion value defs. - invicta_deploy: state machine (idle/standup/rl/joint-damping/lie-down), ONNX policy with per-gait models, auto RL entry after standup with readiness checks, safety loop, gait->model table; no protocol/network code. - invicta_remote: vendor basic_server protocol (UDP + JSON, proto.md V1.2.0), header/MsgId, 0xE0xx error codes, motion/usage-mode/gait translation, telemetry 1002/3,4,5,6 (2/10/2/2 Hz); publishes /motion_command, subscribes /motion_state. - invicta_hardware: joint/IMU bridge skeleton (SocketCAN I/O is TODO), publishes sensor_msgs/JointState + sensor_msgs/Imu, consumes /joint_commands. Verified on ROS Noetic (Ubuntu 20.04) in docker: clean catkin_make, 200 Hz joint state / 50 Hz RL commands / 20 Hz state report, protocol conformance (MotionParam, gait preconditions, error codes), telemetry push, and end-to-end switching of two policy models with a real remote controller.
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
|
||||
# 目标平台:x86(本机/仿真)或 arm(SBC,aarch64)
|
||||
set(BUILD_PLATFORM "x86" CACHE STRING "Target platform (x86 or arm)")
|
||||
if(BUILD_PLATFORM STREQUAL "arm" AND NOT CMAKE_CXX_COMPILER)
|
||||
# 交叉编译需要在 project() 之前指定编译器;更推荐在 SBC 上原生编译,或传 CMAKE_TOOLCHAIN_FILE
|
||||
set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc")
|
||||
set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++")
|
||||
endif()
|
||||
|
||||
project(invicta_deploy)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
add_definitions(-w)
|
||||
add_compile_options(-fPIC)
|
||||
|
||||
find_package(catkin REQUIRED COMPONENTS
|
||||
roscpp
|
||||
roslib
|
||||
sensor_msgs
|
||||
invicta_msgs
|
||||
)
|
||||
|
||||
catkin_package(
|
||||
CATKIN_DEPENDS roscpp roslib sensor_msgs invicta_msgs
|
||||
)
|
||||
|
||||
set(THIRD_PARTY ${CMAKE_CURRENT_SOURCE_DIR}/third_party)
|
||||
set(ORT_ROOT ${THIRD_PARTY}/onnxruntime/${BUILD_PLATFORM})
|
||||
|
||||
include_directories(
|
||||
include/types
|
||||
include/utils
|
||||
interface
|
||||
interface/robot
|
||||
interface/robot/hardware
|
||||
interface/user_command
|
||||
state_machine
|
||||
state_machine/parameters
|
||||
run_policy
|
||||
${THIRD_PARTY}/eigen
|
||||
${ORT_ROOT}/include
|
||||
${catkin_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE STATE_MACHINE_SRC "state_machine/*.cpp")
|
||||
|
||||
add_executable(invicta_deploy
|
||||
main.cpp
|
||||
${STATE_MACHINE_SRC}
|
||||
)
|
||||
|
||||
add_library(onnxruntime SHARED IMPORTED)
|
||||
set_target_properties(onnxruntime PROPERTIES
|
||||
IMPORTED_LOCATION "${ORT_ROOT}/lib/libonnxruntime.so"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${ORT_ROOT}/include"
|
||||
)
|
||||
|
||||
target_link_libraries(invicta_deploy
|
||||
${catkin_LIBRARIES}
|
||||
onnxruntime
|
||||
-lpthread
|
||||
-lm
|
||||
-lrt
|
||||
-ldl
|
||||
-lstdc++
|
||||
)
|
||||
|
||||
# onnxruntime 是预编译动态库:构建时用源码树里的绝对路径,安装后靠同目录下的 $ORIGIN
|
||||
set_target_properties(invicta_deploy PROPERTIES
|
||||
BUILD_RPATH "${ORT_ROOT}/lib"
|
||||
INSTALL_RPATH "\$ORIGIN;${ORT_ROOT}/lib"
|
||||
)
|
||||
|
||||
install(TARGETS invicta_deploy
|
||||
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||
)
|
||||
install(DIRECTORY ${ORT_ROOT}/lib/
|
||||
DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
|
||||
FILES_MATCHING PATTERN "libonnxruntime.so*"
|
||||
)
|
||||
install(DIRECTORY policy
|
||||
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
|
||||
)
|
||||
install(DIRECTORY config launch
|
||||
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
|
||||
)
|
||||
@@ -0,0 +1,148 @@
|
||||
# invicta_deploy
|
||||
|
||||
RL 控制节点:ROS 回调跑在 main 线程,状态机跑在 200 Hz 控制线程,策略在独立线程 50 Hz 推理。
|
||||
|
||||
**不含任何网络/协议代码**——遥控协议在 `invicta_remote`,本节点只订阅 `/motion_command`、发布 `/motion_state`。
|
||||
|
||||
## 源码结构
|
||||
|
||||
```
|
||||
main.cpp ros::init("invicta_deploy") + 状态机启动
|
||||
include/types/ RobotBasicState / RobotAction / UserCommand / 枚举
|
||||
include/utils/ basic_function(Eigen 工具)、safe_controller(1 kHz 安全检查)、
|
||||
motion_state_feedback(状态回执)
|
||||
interface/motion_state_reporter.hpp 20 Hz 发布 /motion_state(真实状态给协议节点)
|
||||
interface/robot/robot_interface.h 状态机依赖的机器人抽象(读状态 + 下发指令)
|
||||
interface/robot/hardware/
|
||||
invicta_interface.hpp 数据面:订阅 /joint_states、/imu/data,发布 /joint_commands
|
||||
interface/user_command/
|
||||
user_command_interface.h 指令输入抽象
|
||||
ros_command_interface.hpp 订阅 /motion_command,翻译成状态机意图并做合法性判断
|
||||
state_machine/state_machine_base.h 控制线程框架(timerfd + epoll,默认 5 ms)
|
||||
state_machine/state_base.h 状态基类
|
||||
state_machine/quadruped_wheel/ 五个状态 + 状态机装配(invicta_state_machine.hpp)
|
||||
state_machine/parameters/ 控制参数(全部来自 ROS 参数,默认值 = 上游 M20)
|
||||
run_policy/ ONNX 推理:policy_runner_base + invicta_policy_runner
|
||||
policy/policy.onnx 策略模型(与关节顺序/动作尺度绑定)
|
||||
scripts/smoke_test.sh 无硬件自检
|
||||
config/ launch/ 参数与启动文件
|
||||
```
|
||||
|
||||
## 状态机
|
||||
|
||||
```
|
||||
┌───────────── 站立(1) ────────────┐
|
||||
idle ──────────→ standup ────── RL(17) ─────────→ rl_control ──┬─ 趴下(4) → liedown → idle
|
||||
↑ │ ↑ │
|
||||
└── 阻尼(2/3)/失控 ┴──── joint_damping ──────┘────────────────┘
|
||||
```
|
||||
|
||||
括号里是协议 `MotionParam` 的值,映射关系在 `RosCommandInterface::RequestMotionState()`:
|
||||
|
||||
| MotionParam | 状态机 | 前置条件 |
|
||||
|---|---|---|
|
||||
| 0 空闲 | 不请求 | 状态机没有"直接回空闲"的路径(RL/站立只能经阻尼或趴下退出) |
|
||||
| 1 站立 | `StandingUp` | 当前为空闲或趴下 |
|
||||
| 2 关节阻尼 | `JointDamping` | 无条件(等价软急停) |
|
||||
| 3 开机阻尼 | `JointDamping` | 无条件(日志注明按关节阻尼处理) |
|
||||
| 4 趴下 | `LieDown` | 当前站立或 RL |
|
||||
| 17 RL 控制 | `RLControlMode` | 当前站立 |
|
||||
|
||||
非法跳转会打印 `[MODE] 拒绝 ...`,并通过 `/motion_state` 让协议节点/遥控器看到真实状态。
|
||||
|
||||
### 站立完成后自动进入 RL
|
||||
|
||||
原厂机制是「站立完成 + 自检通过 → 自动切 RL」,不等用户指令;用户显式请求 `MotionParam=17` 也同样接受,但必须通过同一套自检:
|
||||
|
||||
| 自检项 | 参数 | 默认 |
|
||||
|---|---|---|
|
||||
| 安全标志为 0 | — | — |
|
||||
| 关节角到达站立位姿(轮关节除外) | `rl/require_pose`、`rl/joint_tolerance` | true / 0.15 rad |
|
||||
| 关节速度足够小 | `rl/velocity_tolerance` | 1.0 rad/s |
|
||||
| IMU 数据有效(无 NaN、加速度在 0.1~3 g) | `rl/require_imu` | true |
|
||||
| 到达站立位姿后稳定一段时间 | `rl/enter_delay` | 0.5 s |
|
||||
|
||||
自检不通过时保持站立,并每秒打印一次原因(`[RL] 暂不进入 RL:...`),`/motion_state` 如实报 1。
|
||||
另外推理输出若出现 NaN/Inf,会立刻停发指令并落回关节阻尼。
|
||||
|
||||
> 无硬件台架(`invicta_hardware` 只发零位状态)时必须关掉位姿与 IMU 自检,否则永远进不了 RL:
|
||||
> `roslaunch invicta_deploy invicta_deploy.launch rl_require_pose:=false rl_require_imu:=false`
|
||||
|
||||
### 关节阻尼是「过渡态」,不是保持态
|
||||
|
||||
`MotionParam=2`(关节阻尼/软急停)与 `3`(开机阻尼)都映射到 `JointDamping`:只给 `kd`(腿 4.0、轮 1.0),关节在重力下缓慢下沉,机器人着地后转入 `Idle`(零增益 = 完全自由)。时长由 `timing/joint_damping_duration` 配置(默认 3 s,范围 0.1~30 s),进入/退出都会打印实测耗时。
|
||||
|
||||
- 计时用单调时钟,不用关节数据时间戳:后者在数据断流时不前进,会导致永远停在阻尼。
|
||||
- 从 `idle` 请求阻尼没有意义(机器人已经在地上),状态机不消费,这一点与上游一致。
|
||||
- 阻尼超时后不会自行回到阻尼;要继续松腿需要重新请求。
|
||||
|
||||
## 步态 → RL 模型
|
||||
|
||||
协议里的 `GaitParam` 不是普通参数,**每个步态对应一个 RL 模型**,所以只有"真的提供了模型"的步态才可用:
|
||||
|
||||
```yaml
|
||||
gait:
|
||||
default: 4097 # 0x1001 基础(协议:起立后回到基础步态)
|
||||
policy_map:
|
||||
"4097": "" # 空路径 = 复用 policy_path 的默认模型
|
||||
# "12290": "/path/to/flat_agile.onnx" # 训练好后填路径即可
|
||||
# "4099": "/path/to/stairs.onnx"
|
||||
```
|
||||
|
||||
行为:
|
||||
|
||||
| 情况 | 结果 |
|
||||
|---|---|
|
||||
| 步态 = 默认步态 | 用 `policy_path` 的模型,始终可用 |
|
||||
| 步态给了模型路径且加载成功 | 启动时**预加载**,切换时真正换模型(并清空该模型的 last_action) |
|
||||
| 步态给了路径但文件缺失/加载失败 | 启动日志报 `模型加载失败(该步态将不可用)`,该步态不可用 |
|
||||
| 步态留空且不是默认步态 | 不加载、不可用;请求时打印 `[GAIT] 拒绝 ... 没有对应的 RL 模型` |
|
||||
|
||||
`/motion_state.gait` 只上报**实际生效**的步态,所以遥控器看到的永远是真实值,不会出现"显示切了但还在用旧模型"。
|
||||
|
||||
> 实测(把同一份 ONNX 复制成另一个文件模拟新模型):预加载成功、来回切换 3 轮共 6 次,`gait` 正确跟随、`/joint_commands` 保持 50 Hz、无报错。当前仓库配置只登记 `0x1001`,其余步态请求会被拒绝。
|
||||
|
||||
## 参数(私有命名空间,`config/invicta_deploy.yaml`)
|
||||
|
||||
| 参数 | 默认 | 说明 |
|
||||
|---|---|---|
|
||||
| `control_period_ms` | 5 | 控制周期,5 ms = 200 Hz |
|
||||
| `policy_path` | 空 | 空 = `$(find invicta_deploy)/policy/policy.onnx` |
|
||||
| `topics/joint_states` `topics/imu` `topics/joint_commands` | 见 yaml | 数据面话题 |
|
||||
| `topics/motion_command` / `topics/motion_state` | `motion_command` / `motion_state` | 与协议节点的接口 |
|
||||
| `queues/motion_command` | 1 | 指令只取最新值 |
|
||||
| `queues/joint_commands` / `queues/state` | 1 / 10 | 指令队列 1(新鲜度优先),状态队列 10 |
|
||||
| `motion_state_report_hz` | 20.0 | `/motion_state` 频率 |
|
||||
| `robot_version` | `INVICTA` | 协议 `BasicStatus.Version` |
|
||||
| `gait/default` `gait/policy_map` | 4097 / 两项 | 步态与模型 |
|
||||
| `joint_names` | 16 个 | 关节顺序,与 policy 绑定 |
|
||||
| `calibration/*` | 恒等 | 见根 README「硬件约定 vs policy 约定」 |
|
||||
| `wheel_kp_zero` | true | 轮关节 `kp` 强制 0 |
|
||||
| `timing/joint_damping_duration` | 3.0 | 阻尼过渡时长(0.1~30 s) |
|
||||
| `geometry/*` `gains/*` `limits/*` `timing/stand_duration` `timing/liedown_duration` | M20 值 | 换机器人主要改这里 |
|
||||
|
||||
启动时会打印实际读到的 `joint_dir`、`joint_offset_deg`、话题名与模型路径。
|
||||
|
||||
## 关节顺序(与 `policy.onnx` 绑定,勿改)
|
||||
|
||||
```
|
||||
0 fl_hipx 1 fl_hipy 2 fl_knee 3 fl_wheel
|
||||
4 fr_hipx 5 fr_hipy 6 fr_knee 7 fr_wheel
|
||||
8 hl_hipx 9 hl_hipy 10 hl_knee 11 hl_wheel
|
||||
12 hr_hipx 13 hr_hipy 14 hr_knee 15 hr_wheel
|
||||
```
|
||||
|
||||
策略内部顺序不同(12 个腿关节在前、4 个轮在后),`InvictaPolicyRunner` 用 `robot2policy_idx` / `policy2robot_idx` 映射。
|
||||
|
||||
## 数据面行为
|
||||
|
||||
- `/joint_states`:优先按 `name` 匹配关节(顺序可不同);`name` 缺失时按数组下标解析并告警一次;长度不等于 16 的帧丢弃;缺某个关节名时保留上一帧值并告警。
|
||||
- `/imu/data`:`orientation_covariance[0] == -1` 视为"不提供姿态",丢弃该帧并告警(不伪造姿态);四元数模长近零的帧也丢弃。rpy 由四元数换算(ZYX,与 `RpyToRm` 一致)。
|
||||
- `/joint_commands`:`control_word` 见 `invicta_msgs/control_word.h`;启动时依次发 `kDisable → kErrorReset → kEnable`,运行时恒为 `kMotorControl`。
|
||||
|
||||
## 无硬件自检
|
||||
|
||||
```bash
|
||||
source devel/setup.bash
|
||||
bash src/invicta_deploy/scripts/smoke_test.sh # 三节点 + 话题/频率/协议/ONNX
|
||||
```
|
||||
@@ -0,0 +1,105 @@
|
||||
# invicta_deploy 参数(私有命名空间 ~,由 launch 加载到 /invicta_deploy/ 下)
|
||||
|
||||
# ---- 控制周期 ----
|
||||
control_period_ms: 5 # 5 ms = 200 Hz,与策略 decimation=4(50 Hz)配套
|
||||
|
||||
# ---- 策略 ----
|
||||
policy_path: "" # 留空 = $(find invicta_deploy)/policy/policy.onnx
|
||||
|
||||
# ---- 话题 ----
|
||||
topics:
|
||||
joint_states: joint_states # 订阅 sensor_msgs/JointState
|
||||
imu: imu/data # 订阅 sensor_msgs/Imu
|
||||
joint_commands: joint_commands # 发布 invicta_msgs/JointCommandArray
|
||||
motion_command: motion_command # 订阅 invicta_msgs/MotionCommand(来自 invicta_remote)
|
||||
motion_state: motion_state # 发布 invicta_msgs/MotionState(给 invicta_remote)
|
||||
|
||||
queues:
|
||||
motion_command: 1 # 指令只关心最新值
|
||||
joint_commands: 1 # 指令只关心最新值,队列不堆积
|
||||
state: 10 # 状态流按 200 Hz 设计,队列给足以吸收抖动
|
||||
|
||||
# ---- 站立完成后自动进入 RL(原厂机制)----
|
||||
# 原厂不是等用户发 MotionParam=17,而是站立完成后自检通过就自动切 RL;用户指令也可以,
|
||||
# 但同样要满足自检。自检不通过时一直保持站立(/motion_state 报 1),每秒打印一次原因。
|
||||
rl:
|
||||
auto_enter: true
|
||||
enter_delay: 0.5 # 到达站立位姿后再稳定多久 [s]
|
||||
require_pose: true # 关节角必须到达站立位姿(无硬件台架时设为 false)
|
||||
joint_tolerance: 0.15 # 关节角容差 [rad]
|
||||
velocity_tolerance: 1.0 # 关节速度容差 [rad/s]
|
||||
require_imu: true # IMU 数据必须有效(无硬件台架时设为 false)
|
||||
|
||||
# ---- 状态回报 ----
|
||||
motion_state_report_hz: 20.0 # /motion_state 发布频率(协议状态上报 2 Hz 时从这里取)
|
||||
robot_version: "INVICTA" # 对应协议 BasicStatus.Version
|
||||
|
||||
# ---- 步态 → RL 模型 ----
|
||||
# 不同步态对应不同的 RL 模型:
|
||||
# 0x1001 基础(平地) / 0x3002 平地(敏捷) → 当前共用 policy_path 里的模型
|
||||
# 0x1003 楼梯 / 0x3003 楼梯(敏捷) → 模型尚未训练,请求会被拒绝并记录日志
|
||||
# 键是十进制,等号右边是模型文件路径(空 = 用 policy_path)
|
||||
gait:
|
||||
default: 4097 # 0x1001 基础,协议规定起立后回到基础步态
|
||||
# 键必须加引号(roslaunch 不接受整数键);值 = 模型文件路径,留空表示"没有模型"。
|
||||
# 只有这里提供了模型路径的步态才会在启动时加载、才允许切换;填了路径但加载失败的也不可用。
|
||||
policy_map:
|
||||
"4097": "" # 0x1001 基础(平地) → 复用 policy_path 的默认模型
|
||||
# "12290": "/path/to/flat_agile.onnx" # 0x3002 平地(敏捷),训练好后填这里
|
||||
# "4099": "/path/to/stairs.onnx" # 0x1003 楼梯
|
||||
# "12291": "/path/to/stairs_agile.onnx" # 0x3003 楼梯(敏捷)
|
||||
|
||||
# ---- 关节顺序(索引即指令/状态数组下标,与 policy.onnx 绑定,勿随意改)----
|
||||
joint_names:
|
||||
[fl_hipx_joint, fl_hipy_joint, fl_knee_joint, fl_wheel_joint,
|
||||
fr_hipx_joint, fr_hipy_joint, fr_knee_joint, fr_wheel_joint,
|
||||
hl_hipx_joint, hl_hipy_joint, hl_knee_joint, hl_wheel_joint,
|
||||
hr_hipx_joint, hr_hipy_joint, hr_knee_joint, hr_wheel_joint]
|
||||
|
||||
# ---- 关节标定 ----
|
||||
# 默认恒等:约定硬件约定(方向/零点/单位)由 invicta_hardware 负责,
|
||||
# 话题上流动的就是 policy 约定下的量。
|
||||
# 如果反过来让本节点承担 M20 的原始约定,就把下面两张表填成 M20 的值并打开 auto_calibrate,
|
||||
# 参考值(上游 M20,角度制):
|
||||
# joint_dir = [1,1,-1,1, 1,-1,1,-1, -1,1,-1,1, -1,-1,1,-1]
|
||||
# joint_offset_deg = [-25,-131,160,0, 25,-131,160,0, -25,131,-160,0, 25,131,-160,0]
|
||||
# 二者只能选一处施加,不要两边都做。
|
||||
calibration:
|
||||
joint_dir: [1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0]
|
||||
joint_offset_deg: [0.0,0.0,0.0,0.0, 0.0,0.0,0.0,0.0, 0.0,0.0,0.0,0.0, 0.0,0.0,0.0,0.0]
|
||||
auto_calibrate: false # 仅当上报的是原始编码器角(需要等 16 关节数据更新并做 ±360 回绕修正)时打开
|
||||
wrap_hip_deg: 140.0 # 标定用回绕阈值,对应 hipy(下标 %4==1)
|
||||
wrap_knee_deg: 164.0 # 标定用回绕阈值,对应 knee(下标 %4==2)
|
||||
|
||||
# ---- 轮关节是否强制 kp=0(速度/力矩模式)----
|
||||
wheel_kp_zero: true
|
||||
|
||||
# ---- 机器人几何(默认值来自上游 M20,换机器人时改这里)----
|
||||
geometry:
|
||||
body_len_x: 0.619
|
||||
body_len_y: 0.13
|
||||
hip_len: 0.104
|
||||
thigh_len: 0.25
|
||||
shank_len: 0.25
|
||||
pre_height: 0.12
|
||||
stand_height: 0.48
|
||||
wheel_link_len: 0.040575
|
||||
|
||||
# ---- PD 增益(站立/摆动相)----
|
||||
gains:
|
||||
swing_leg_kp: [200.0, 200.0, 200.0]
|
||||
swing_leg_kd: [4.0, 4.0, 4.0]
|
||||
|
||||
# ---- 限制 ----
|
||||
limits:
|
||||
fl_joint_lower: [-0.4363, -2.443, -2.758] # rad
|
||||
fl_joint_upper: [0.6109, 2.443, 2.758] # rad
|
||||
joint_vel_limit: [22.4, 22.4, 22.4] # rad/s
|
||||
torque_limit: [76.4, 76.4, 76.4] # Nm
|
||||
wheel_vel_limit: 100.0 # rad/s
|
||||
|
||||
# ---- 时长 ----
|
||||
timing:
|
||||
stand_duration: 1.5 # 起立曲线时长(总时长约为 2 倍)
|
||||
liedown_duration: 2.0 # 趴下曲线时长(总时长约为 2 倍)
|
||||
joint_damping_duration: 3.0 # 阻尼过渡时长:松腿→着地→转空闲(0.1~30 s)
|
||||
@@ -0,0 +1,119 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <csignal>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
namespace types {
|
||||
using Vec3f = Eigen::Vector3f;
|
||||
using Vec3d = Eigen::Vector3d;
|
||||
using Vec4f = Eigen::Vector4f;
|
||||
using Vec4d = Eigen::Vector4d;
|
||||
using VecXf = Eigen::VectorXf;
|
||||
using VecXd = Eigen::VectorXd;
|
||||
|
||||
using Mat3f = Eigen::Matrix3f;
|
||||
using Mat3d = Eigen::Matrix3d;
|
||||
using MatXf = Eigen::MatrixXf;
|
||||
using MatXd = Eigen::MatrixXd;
|
||||
|
||||
const float gravity = 9.815;
|
||||
|
||||
struct RobotBasicState {
|
||||
Vec3f base_rpy;
|
||||
Vec4f base_quat;
|
||||
Mat3f base_rot_mat;
|
||||
Vec3f base_omega;
|
||||
Vec3f base_acc;
|
||||
MatXf flt_base_acc_mat;
|
||||
VecXf joint_pos;
|
||||
VecXf joint_vel;
|
||||
VecXf joint_tau;
|
||||
|
||||
RobotBasicState(int dof = 16) {
|
||||
base_rpy.setZero();
|
||||
base_quat.setZero();
|
||||
base_rot_mat.setIdentity();
|
||||
base_omega.setZero();
|
||||
base_acc.setZero();
|
||||
flt_base_acc_mat = Eigen::MatrixXf::Zero(20, 3);
|
||||
joint_pos = VecXf::Zero(dof);
|
||||
joint_vel = VecXf::Zero(dof);
|
||||
joint_tau = VecXf::Zero(dof);
|
||||
}
|
||||
};
|
||||
|
||||
struct RobotAction {
|
||||
VecXf goal_joint_pos;
|
||||
VecXf goal_joint_vel;
|
||||
VecXf kp;
|
||||
VecXf kd;
|
||||
VecXf tau_ff;
|
||||
|
||||
MatXf ConvertToMat() {
|
||||
MatXf res(goal_joint_pos.rows(), 5);
|
||||
res.col(0) = kp;
|
||||
res.col(1) = goal_joint_pos;
|
||||
res.col(2) = kd;
|
||||
res.col(3) = goal_joint_vel;
|
||||
res.col(4) = tau_ff;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct UserCommand {
|
||||
double time_stamp;
|
||||
uint8_t safe_control_mode; // 0 normal, 1 stand, 2 sit, 3 joint damping
|
||||
uint8_t target_mode; // 状态机意图,取值同 RobotMotionState
|
||||
float forward_vel_scale = 0;
|
||||
float side_vel_scale = 0;
|
||||
float turnning_vel_scale = 0;
|
||||
float reserved_scale;
|
||||
uint32_t gait = 0; // 请求/生效的步态(协议 GaitParam),0 = 未请求
|
||||
uint8_t usage_mode = 0; // 协议使用模式:0 常规 / 1 导航 / 2 辅助
|
||||
};
|
||||
|
||||
enum FromType {
|
||||
inside = 0,
|
||||
user,
|
||||
};
|
||||
struct NetInfo {
|
||||
std::string ip;
|
||||
int port;
|
||||
FromType fromType;
|
||||
};
|
||||
|
||||
struct DataInfo : public NetInfo {
|
||||
const char* buffer;
|
||||
ssize_t len;
|
||||
};
|
||||
struct CmdInfo : public NetInfo {
|
||||
int type;
|
||||
int command;
|
||||
};
|
||||
}; // namespace types
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file custom_types.h
|
||||
* @brief invicta 自定义枚举与工具
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common_types.h"
|
||||
|
||||
namespace types {
|
||||
|
||||
enum RobotMotionState {
|
||||
WaitingForStand = 0,
|
||||
StandingUp = 1,
|
||||
JointDamping = 2,
|
||||
LieDown = 4,
|
||||
RLControlMode = 6,
|
||||
};
|
||||
|
||||
enum StateName {
|
||||
kInvalid = -1,
|
||||
kIdle = 0,
|
||||
kStandUp = 1,
|
||||
kJointDamping = 2,
|
||||
kLieDown = 4,
|
||||
kRLControl = 6,
|
||||
};
|
||||
|
||||
/// 手柄按键(云卓 G20 遥测 App 上报的键名,见 gamepad_interface.hpp)
|
||||
enum KeyCode {
|
||||
L1,
|
||||
L2,
|
||||
R1,
|
||||
R2,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
inline std::string GetAbsPath() {
|
||||
char buffer[PATH_MAX];
|
||||
if (getcwd(buffer, sizeof(buffer)) != NULL) {
|
||||
return std::string(buffer);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}; // namespace types
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @file basic_function.hpp
|
||||
* @brief basic function
|
||||
* @author DeepRobotics
|
||||
* @version 1.0
|
||||
* @date 2025-11-07
|
||||
*
|
||||
* @copyright Copyright (c) 2025 DeepRobotics
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include "common_types.h"
|
||||
#include "custom_types.h"
|
||||
|
||||
using namespace types;
|
||||
|
||||
inline float Deg2Rad(float deg){
|
||||
return deg /180.f * M_PI;
|
||||
}
|
||||
|
||||
inline float Rad2Deg(float rad){
|
||||
return rad / M_PI * 180.;
|
||||
}
|
||||
|
||||
inline float LimitNumber(float data, float limit){
|
||||
limit = fabs(limit);
|
||||
if(data > limit) data = limit;
|
||||
else if(data < -limit) data = -limit;
|
||||
return data;
|
||||
}
|
||||
|
||||
inline float LimitNumber(float data, float low, float high){
|
||||
if(low > high){
|
||||
std::cerr << "error limit range" << std::endl;
|
||||
return data;
|
||||
}
|
||||
if(data > high) return high;
|
||||
if(data < low) return low;
|
||||
return data;
|
||||
}
|
||||
|
||||
inline Mat3f RpyToRm(const Vec3f &rpy){
|
||||
Eigen::AngleAxisf yawAngle(rpy(2), Vec3f::UnitZ());
|
||||
Eigen::AngleAxisf pitchAngle(rpy(1), Vec3f::UnitY());
|
||||
Eigen::AngleAxisf rollAngle(rpy(0), Vec3f::UnitX());
|
||||
Eigen::Quaternion<float> q = yawAngle*pitchAngle*rollAngle;
|
||||
return q.matrix();
|
||||
}
|
||||
|
||||
inline float NormalizeAngle(float angle) {
|
||||
float result = std::fmod(angle, 2 * M_PI);
|
||||
if (result < 0) {
|
||||
result += 2 * M_PI;
|
||||
}
|
||||
if (result > M_PI) {
|
||||
result -= 2 * M_PI;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline float Sign(const float &i){
|
||||
if (i > 0) {
|
||||
return 1.;
|
||||
} else if (i == 0) {
|
||||
return 0.;
|
||||
} else {
|
||||
return -1.;
|
||||
}
|
||||
}
|
||||
|
||||
inline double GetTimestampMs(){
|
||||
static timespec startup_timestamp;
|
||||
timespec now_timestamp;
|
||||
if (startup_timestamp.tv_sec + startup_timestamp.tv_nsec == 0) {
|
||||
clock_gettime(CLOCK_MONOTONIC,&startup_timestamp);
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC,&now_timestamp);
|
||||
return (now_timestamp.tv_sec-startup_timestamp.tv_sec)*1e3 + (now_timestamp.tv_nsec-startup_timestamp.tv_nsec)/1e6;
|
||||
}
|
||||
|
||||
inline float GetCubicSplinePos(float x0, float v0, float xf, float vf, float t, float T){
|
||||
if(t >= T) return xf;
|
||||
float a, b, c, d;
|
||||
d = x0;
|
||||
c = v0;
|
||||
a = (vf*T - 2*xf + v0*T + 2*x0) / pow(T, 3);
|
||||
b = (3*xf - vf*T - 2*v0*T - 3*x0) / pow(T, 2);
|
||||
return a*pow(t, 3)+b*pow(t, 2)+c*t+d;
|
||||
}
|
||||
|
||||
inline float GetCubicSplineVel(float x0, float v0, float xf, float vf, float t, float T){
|
||||
if(t >= T) return 0;
|
||||
float a, b, c;
|
||||
c = v0;
|
||||
a = (vf*T - 2*xf + v0*T + 2*x0) / pow(T, 3);
|
||||
b = (3*xf - vf*T - 2*v0*T - 3*x0) / pow(T, 2);
|
||||
return 3.*a*pow(t, 2) + 2.*b*t + c;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file motion_state_feedback.hpp
|
||||
* @brief motion state feedback
|
||||
* @author DeepRobotics
|
||||
* @version 1.0
|
||||
* @date 2025-11-07
|
||||
*
|
||||
* @copyright Copyright (c) 2025 DeepRobotics
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include "common_types.h"
|
||||
|
||||
class MotionStateFeedback
|
||||
{
|
||||
private:
|
||||
uint8_t current_state_;
|
||||
uint32_t current_gait_; // 协议 GaitParam(0x1001/0x3002 等),16 位值
|
||||
uint8_t last_state_;
|
||||
uint32_t last_gait_;
|
||||
|
||||
Vec3f current_vel_;
|
||||
Vec3f cmd_vel_;
|
||||
Vec3f max_vel_;
|
||||
|
||||
union{
|
||||
struct{
|
||||
uint32_t joint_pos_limit : 1;
|
||||
uint32_t posture_limit : 1;
|
||||
uint32_t reserved : 30;
|
||||
}error_code_bit_;
|
||||
uint32_t error_code_;
|
||||
};
|
||||
public:
|
||||
MotionStateFeedback(/* args */){
|
||||
memset(this, 0, sizeof(MotionStateFeedback));
|
||||
std::cout << "Motion State Feedback" << std::endl;
|
||||
}
|
||||
~MotionStateFeedback(){
|
||||
|
||||
}
|
||||
|
||||
void UpdateCurrentState(int state){
|
||||
if(uint8_t(state) != current_state_){
|
||||
last_state_ = current_state_;
|
||||
current_state_ = uint8_t(state);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateCurrentGait(uint32_t gait){
|
||||
if(gait != current_gait_){
|
||||
last_gait_ = current_gait_;
|
||||
current_gait_ = gait;
|
||||
}
|
||||
}
|
||||
|
||||
void ClearMotionError(){error_code_ = 0;}
|
||||
void SetJointPosLimitError(){
|
||||
error_code_bit_.joint_pos_limit = 1;
|
||||
}
|
||||
void SetPostureLimitError(){
|
||||
error_code_bit_.posture_limit = 1;
|
||||
}
|
||||
|
||||
inline uint8_t GetCurrentState(){return current_state_;}
|
||||
inline uint32_t GetCurrentGait(){return current_gait_;}
|
||||
inline uint8_t GetLastState(){return last_state_;}
|
||||
inline uint32_t GetLastGait(){return last_gait_;}
|
||||
};
|
||||
@@ -0,0 +1,337 @@
|
||||
/**
|
||||
* @file safe_controller.hpp
|
||||
* @brief 独立线程的安全检查(1 ms 周期):驱动器状态、关节数据、温度、IMU
|
||||
*
|
||||
* 与上游 M20 的差异:删掉电池检查(上游 IsBatteryNormal 定义了但从未被调用,属死代码)。
|
||||
*
|
||||
* 已知未接线的项(当前阶段按「硬件急停兜底」处理,未改动):
|
||||
* - IsUserCommandNormal():手柄断连不会让机器人停(上游同样如此)
|
||||
* - 关节温度 / 驱动器状态字:invicta 硬件桥接节点暂不提供,见 robot_interface.h
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "robot_interface.h"
|
||||
#include "user_command_interface.h"
|
||||
|
||||
union RobotErrorState {
|
||||
struct {
|
||||
uint32_t imu_num_error : 1;
|
||||
uint32_t imu_update_overtime : 1;
|
||||
uint32_t command_heartbeat_overtime : 1;
|
||||
uint32_t driver_error : 1;
|
||||
uint32_t motor_heat_warn : 1;
|
||||
uint32_t joint_num_error : 1;
|
||||
uint32_t joint_update_error : 1;
|
||||
uint32_t cpu_heat_warn : 1;
|
||||
uint32_t cpu_freq_warn : 1;
|
||||
uint32_t reserved : 23;
|
||||
};
|
||||
uint32_t error_code;
|
||||
};
|
||||
|
||||
class SafeController {
|
||||
private:
|
||||
std::shared_ptr<interface::RobotInterface> ri_ptr_;
|
||||
std::shared_ptr<interface::UserCommandInterface> uc_ptr_;
|
||||
std::thread judge_thread_;
|
||||
int run_cnt_ = 0;
|
||||
|
||||
double last_imu_ts_, imu_check_time_;
|
||||
bool imu_check_flag_ = true;
|
||||
|
||||
double ri_check_time_, last_ri_ts_;
|
||||
VecXf last_joint_pos_, last_joint_vel_, last_joint_tau_;
|
||||
std::vector<int> joint_data_same_cnt_;
|
||||
bool joint_check_flag_ = true;
|
||||
|
||||
float max_temp_;
|
||||
int max_temp_idx_;
|
||||
|
||||
double last_cmd_ts_, cmd_check_time_;
|
||||
bool cmd_check_flag_ = true;
|
||||
|
||||
types::UserCommand* usr_cmd_;
|
||||
bool start_thread_flag_ = false;
|
||||
|
||||
double current_time_;
|
||||
|
||||
RobotErrorState robot_error_state_;
|
||||
uint32_t last_error_code_;
|
||||
std::map<uint8_t, uint16_t> error_driver_map_;
|
||||
uint32_t joint_update_state_;
|
||||
|
||||
bool IsImuDataNormal() {
|
||||
double current_imu_ts_ = ri_ptr_->GetImuTimestamp();
|
||||
Vec3f rpy = ri_ptr_->GetImuRpy();
|
||||
Vec3f acc = ri_ptr_->GetImuAcc();
|
||||
Vec3f omg = ri_ptr_->GetImuOmega();
|
||||
if (imu_check_flag_) {
|
||||
last_imu_ts_ = current_imu_ts_;
|
||||
imu_check_time_ = current_time_;
|
||||
imu_check_flag_ = false;
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
robot_error_state_.imu_update_overtime = 0;
|
||||
if (current_imu_ts_ != last_imu_ts_) {
|
||||
last_imu_ts_ = current_imu_ts_;
|
||||
imu_check_time_ = current_time_;
|
||||
}
|
||||
if (current_time_ - imu_check_time_ == 0.2) {
|
||||
std::cout << "========== imu lag warning ========>> " << current_time_ - imu_check_time_ << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (std::isnan(rpy(i)) || std::isnan(acc(i)) || std::isnan(omg(i))) {
|
||||
res = false;
|
||||
robot_error_state_.imu_num_error = 1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool IsJointDataNormal() {
|
||||
double ri_ts_ = ri_ptr_->GetInterfaceTimeStamp();
|
||||
VecXf joint_pos = ri_ptr_->GetJointPosition();
|
||||
VecXf joint_vel = ri_ptr_->GetJointVelocity();
|
||||
VecXf joint_tau = ri_ptr_->GetJointTorque();
|
||||
if (joint_check_flag_) {
|
||||
joint_check_flag_ = false;
|
||||
last_ri_ts_ = ri_ts_;
|
||||
last_joint_pos_ = joint_pos;
|
||||
last_joint_vel_ = joint_vel;
|
||||
last_joint_tau_ = joint_tau;
|
||||
}
|
||||
bool res = true;
|
||||
robot_error_state_.joint_update_error = 0;
|
||||
if (last_ri_ts_ != ri_ts_) {
|
||||
last_ri_ts_ = ri_ts_;
|
||||
ri_check_time_ = current_time_;
|
||||
}
|
||||
|
||||
robot_error_state_.joint_num_error = 0;
|
||||
joint_update_state_ = 0;
|
||||
for (int i = 0; i < joint_pos.size(); ++i) {
|
||||
if (std::isnan(joint_pos(i)) || std::isnan(joint_vel(i)) || std::isnan(joint_tau(i))) {
|
||||
robot_error_state_.joint_num_error = 1;
|
||||
res = false;
|
||||
}
|
||||
if (joint_pos(i) == last_joint_pos_(i) && joint_vel(i) == last_joint_vel_(i) &&
|
||||
joint_tau(i) == last_joint_tau_(i)) {
|
||||
joint_data_same_cnt_[i]++;
|
||||
} else {
|
||||
joint_data_same_cnt_[i] = 0;
|
||||
}
|
||||
// 数据长时间不变的判据阈值未标定,上游同样注释掉
|
||||
}
|
||||
last_joint_pos_ = joint_pos;
|
||||
last_joint_vel_ = joint_vel;
|
||||
last_joint_tau_ = joint_tau;
|
||||
if (run_cnt_ % 5000 == 0) {
|
||||
std::cout << "joint_pos: " << joint_pos.transpose() << std::endl;
|
||||
std::cout << "joint_vel: " << joint_vel.transpose() << std::endl;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool IsDriverStatusNormal() {
|
||||
std::vector<uint16_t> status_word = ri_ptr_->GetDriverStatusWord();
|
||||
bool res = true;
|
||||
robot_error_state_.driver_error = 0;
|
||||
for (size_t i = 0; i < status_word.size(); ++i) {
|
||||
if (status_word[i] != 1) {
|
||||
error_driver_map_[uint8_t(i)] = status_word[i];
|
||||
robot_error_state_.driver_error = 1;
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
if (robot_error_state_.driver_error == 0) {
|
||||
error_driver_map_.clear();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool IsMotorTempertureNormal() {
|
||||
VecXf m_t = ri_ptr_->GetMotorTemperture();
|
||||
VecXf::Index max_idx, min_idx;
|
||||
float max_temp = m_t.maxCoeff(&max_idx);
|
||||
float min_temp = m_t.minCoeff(&min_idx);
|
||||
max_temp_ = max_temp;
|
||||
max_temp_idx_ = max_idx;
|
||||
if (run_cnt_ % 5000 == 0) {
|
||||
std::cout << "Motor Temperture: " << m_t.transpose() << std::endl;
|
||||
std::cout << "Max&Min: " << max_idx << " : " << max_temp << " | " << min_idx << " : " << min_temp
|
||||
<< std::endl;
|
||||
}
|
||||
if (max_temp > 100) {
|
||||
robot_error_state_.motor_heat_warn = 1;
|
||||
return false;
|
||||
}
|
||||
robot_error_state_.motor_heat_warn = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsUserCommandNormal() {
|
||||
double cmd_ts_ = uc_ptr_->GetUserCommand()->time_stamp;
|
||||
if (cmd_check_flag_) {
|
||||
cmd_check_flag_ = false;
|
||||
last_cmd_ts_ = cmd_ts_;
|
||||
cmd_check_time_ = current_time_;
|
||||
}
|
||||
robot_error_state_.command_heartbeat_overtime = 0;
|
||||
if (last_cmd_ts_ != cmd_ts_) {
|
||||
last_cmd_ts_ = cmd_ts_;
|
||||
cmd_check_time_ = current_time_;
|
||||
}
|
||||
if (current_time_ - cmd_check_time_ > 1000.0) {
|
||||
robot_error_state_.command_heartbeat_overtime = 1;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintRobotErrorState() {
|
||||
std::cout << "Error occurred!" << std::endl;
|
||||
|
||||
if (robot_error_state_.imu_num_error) {
|
||||
std::cout << "IMU number error: invalid IMU data count | " << ri_ptr_->GetImuRpy().transpose() << " | "
|
||||
<< ri_ptr_->GetImuAcc().transpose() << " | " << ri_ptr_->GetImuOmega().transpose() << std::endl;
|
||||
}
|
||||
|
||||
if (robot_error_state_.imu_update_overtime) {
|
||||
std::cout << "IMU update overtime: no IMU data received since timestamp " << last_imu_ts_ << std::endl;
|
||||
}
|
||||
|
||||
if (robot_error_state_.command_heartbeat_overtime) {
|
||||
std::cout << "Heartbeat overtime: lost communication with controller (no heartbeat signal received)"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if (robot_error_state_.driver_error) {
|
||||
std::cout << "Driver error: motor driver reported fault(s):" << std::endl;
|
||||
for (const auto& pair : error_driver_map_) {
|
||||
std::cout << " Driver " << int(pair.first) << ": error code 0x" << std::hex << std::uppercase
|
||||
<< int(pair.second) << std::dec << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (robot_error_state_.motor_heat_warn) {
|
||||
std::cout << "Motor overheat warning: motor " << max_temp_idx_ << " reached " << max_temp_ << "°C"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if (robot_error_state_.joint_num_error) {
|
||||
std::cout << "Joint number error: mismatched joint count | pos: "
|
||||
<< ri_ptr_->GetJointPosition().transpose()
|
||||
<< " | vel: " << ri_ptr_->GetJointVelocity().transpose()
|
||||
<< " | tau: " << ri_ptr_->GetJointTorque().transpose() << std::endl;
|
||||
}
|
||||
|
||||
if (robot_error_state_.joint_update_error) {
|
||||
std::cout << "Joint update error: no joint data update (current_time 0x" << std::hex << current_time_
|
||||
<< " vs last_check 0x" << ri_check_time_ << ")" << std::dec << std::endl;
|
||||
}
|
||||
|
||||
if (robot_error_state_.cpu_heat_warn) {
|
||||
std::cout << "CPU overheat warning: CPU temperature exceeds safe limit" << std::endl;
|
||||
}
|
||||
|
||||
if (robot_error_state_.cpu_freq_warn) {
|
||||
std::cout << "CPU frequency warning: CPU throttling due to thermal or power limits" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
SafeController() {
|
||||
robot_error_state_.error_code = 0;
|
||||
last_error_code_ = 0;
|
||||
error_driver_map_.clear();
|
||||
}
|
||||
|
||||
~SafeController() {}
|
||||
|
||||
void SetRobotDataSource(std::shared_ptr<interface::RobotInterface> ri) {
|
||||
ri_ptr_ = ri;
|
||||
joint_data_same_cnt_.resize(ri_ptr_->dof_num_, 0);
|
||||
}
|
||||
|
||||
void SetUserCommandDataSource(std::shared_ptr<interface::UserCommandInterface> uc) {
|
||||
uc_ptr_ = uc;
|
||||
usr_cmd_ = uc_ptr_->GetUserCommand();
|
||||
}
|
||||
|
||||
void Start() {
|
||||
start_thread_flag_ = true;
|
||||
judge_thread_ = std::thread(std::bind(&SafeController::Run, this));
|
||||
}
|
||||
|
||||
void Run() {
|
||||
int tfd, efd, fds;
|
||||
uint64_t value;
|
||||
struct epoll_event ev, *evptr;
|
||||
struct itimerspec time_intv;
|
||||
|
||||
tfd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
if (tfd == -1) return;
|
||||
|
||||
time_intv.it_value.tv_sec = 1.;
|
||||
time_intv.it_value.tv_nsec = 1000 * 1000;
|
||||
time_intv.it_interval.tv_sec = 0;
|
||||
time_intv.it_interval.tv_nsec = time_intv.it_value.tv_nsec;
|
||||
timerfd_settime(tfd, 0, &time_intv, NULL);
|
||||
|
||||
efd = epoll_create1(0);
|
||||
if (efd == -1) close(tfd);
|
||||
|
||||
evptr = (struct epoll_event*)calloc(1, sizeof(struct epoll_event));
|
||||
if (evptr == NULL) {
|
||||
close(tfd);
|
||||
close(efd);
|
||||
}
|
||||
|
||||
ev.data.fd = tfd;
|
||||
ev.events = EPOLLIN;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, tfd, &ev);
|
||||
|
||||
while (start_thread_flag_) {
|
||||
fds = epoll_wait(efd, evptr, 1, -1);
|
||||
if (evptr[0].events & EPOLLIN) {
|
||||
int ret = read(evptr->data.fd, &value, sizeof(uint64_t));
|
||||
if (ret == -1) continue;
|
||||
}
|
||||
run_cnt_++;
|
||||
current_time_ = GetTimestampMs() / 1000;
|
||||
if (!IsDriverStatusNormal()) {
|
||||
usr_cmd_->safe_control_mode = 2;
|
||||
std::cout << "Driver status error!" << std::endl;
|
||||
}
|
||||
if (!IsJointDataNormal()) {
|
||||
usr_cmd_->safe_control_mode = 3;
|
||||
std::cout << "Joint data error!" << std::endl;
|
||||
}
|
||||
if (run_cnt_ % 1000 == 0 && !IsMotorTempertureNormal()) {
|
||||
usr_cmd_->safe_control_mode = 2;
|
||||
std::cout << "Motor temperture error!" << std::endl;
|
||||
}
|
||||
if (!IsImuDataNormal()) {
|
||||
std::cout << "IMU error!" << std::endl;
|
||||
usr_cmd_->safe_control_mode = 2;
|
||||
}
|
||||
if (last_error_code_ != robot_error_state_.error_code) {
|
||||
if (robot_error_state_.error_code != 0) {
|
||||
std::cout << "========== error_code ========>> " << std::hex << robot_error_state_.error_code
|
||||
<< std::endl;
|
||||
PrintRobotErrorState();
|
||||
}
|
||||
last_error_code_ = robot_error_state_.error_code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
start_thread_flag_ = false;
|
||||
if (judge_thread_.joinable()) {
|
||||
judge_thread_.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @file motion_state_reporter.hpp
|
||||
* @brief 把状态机当前状态发布到 /motion_state,供 invicta_remote 判断与上报
|
||||
*
|
||||
* 值域与 proto.md 的 MotionParam / BasicStatus.MotionState 对齐(invicta_msgs/motion_defs.h)。
|
||||
* 目前能上报运动状态、步态、使用模式;charge / hes / sleep 需要硬件侧提供(充电状态、硬急停信号、
|
||||
* 休眠管理),当前恒为 0,等硬件桥接补齐后再接。
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ros/ros.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "common_types.h"
|
||||
#include "custom_types.h"
|
||||
#include "invicta_msgs/MotionState.h"
|
||||
#include "invicta_msgs/motion_defs.h"
|
||||
#include "motion_state_feedback.hpp"
|
||||
|
||||
namespace interface {
|
||||
|
||||
using namespace invicta_msgs;
|
||||
|
||||
class MotionStateReporter {
|
||||
public:
|
||||
MotionStateReporter(MotionStateFeedback* msfb, UserCommand* user_cmd, const std::string& topic, double hz,
|
||||
const std::string& version)
|
||||
: msfb_(msfb), user_cmd_(user_cmd), hz_(hz > 0 ? hz : 20.0), version_(version) {
|
||||
pub_ = nh_.advertise<invicta_msgs::MotionState>(topic, 1);
|
||||
}
|
||||
|
||||
~MotionStateReporter() { Stop(); }
|
||||
|
||||
void Start() {
|
||||
if (running_) return;
|
||||
running_ = true;
|
||||
thread_ = std::thread(&MotionStateReporter::Loop, this);
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
running_ = false;
|
||||
if (thread_.joinable()) thread_.join();
|
||||
}
|
||||
|
||||
/// 状态机状态 → 协议 MotionParam
|
||||
static uint8_t MapState(uint8_t fsm_state) {
|
||||
switch (fsm_state) {
|
||||
case uint8_t(RobotMotionState::WaitingForStand): return kMotionIdle;
|
||||
case uint8_t(RobotMotionState::StandingUp): return kMotionStanding;
|
||||
case uint8_t(RobotMotionState::JointDamping): return kMotionJointDamping;
|
||||
case uint8_t(RobotMotionState::LieDown): return kMotionLieDown;
|
||||
case uint8_t(RobotMotionState::RLControlMode): return kMotionRlControl;
|
||||
default: return kMotionIdle;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void Loop() {
|
||||
const auto period = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::duration<double>(1.0 / hz_));
|
||||
auto next = std::chrono::steady_clock::now();
|
||||
while (ros::ok() && running_) {
|
||||
next += period;
|
||||
invicta_msgs::MotionState msg;
|
||||
msg.header.stamp = ros::Time::now();
|
||||
msg.motion_state = msfb_ ? MapState(msfb_->GetCurrentState()) : uint8_t(kMotionIdle);
|
||||
const uint32_t gait = msfb_ ? msfb_->GetCurrentGait() : 0;
|
||||
msg.gait = (gait == 0) ? kGaitBasic : gait;
|
||||
msg.usage_mode = user_cmd_ ? user_cmd_->usage_mode : uint8_t(kUsageNormal);
|
||||
msg.charge = 0; // 待硬件:充电状态
|
||||
msg.hes = 0; // 待硬件:硬急停信号
|
||||
msg.sleep = 0; // 待实现:休眠管理
|
||||
msg.version = version_;
|
||||
pub_.publish(msg);
|
||||
std::this_thread::sleep_until(next);
|
||||
}
|
||||
}
|
||||
|
||||
ros::NodeHandle nh_;
|
||||
ros::Publisher pub_;
|
||||
MotionStateFeedback* msfb_ = nullptr;
|
||||
UserCommand* user_cmd_ = nullptr;
|
||||
double hz_ = 20.0;
|
||||
std::string version_ = "INVICTA";
|
||||
std::atomic<bool> running_{false};
|
||||
std::thread thread_;
|
||||
};
|
||||
|
||||
} // namespace interface
|
||||
@@ -0,0 +1,329 @@
|
||||
/**
|
||||
* @file invicta_interface.hpp
|
||||
* @brief invicta 的 ROS1 数据面:订阅关节状态与 IMU,发布关节指令
|
||||
*
|
||||
* 由上游 M20 的 DdsInterface + M20Interface 合并而来(原来分两层是为了和 Lite3 共用,
|
||||
* 这里只有一台机器人,合成一个类更好读)。差异:
|
||||
* - ros2/drdds → ROS1 + sensor_msgs/JointState + sensor_msgs/Imu
|
||||
* - 控制字从原厂驱动器私有值改为 invicta_msgs/control_word.h 的平台无关集合
|
||||
* - 删除电池订阅(上游是死代码)
|
||||
* - 关节方向/零点标定改为 ROS 参数,默认「恒等」,即约定硬件桥接节点已给出 policy 约定下的数据
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ros/ros.h>
|
||||
#include <sensor_msgs/Imu.h>
|
||||
#include <sensor_msgs/JointState.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "basic_function.hpp"
|
||||
#include "common_types.h"
|
||||
#include "invicta_msgs/JointCommandArray.h"
|
||||
#include "invicta_msgs/control_word.h"
|
||||
#include "robot_interface.h"
|
||||
|
||||
namespace interface {
|
||||
|
||||
class InvictaInterface : public RobotInterface {
|
||||
protected:
|
||||
ros::NodeHandle nh_; ///< 话题用:相对节点命名空间(默认 /joint_states 等)
|
||||
ros::NodeHandle pnh_{"~"}; ///< 参数用:私有命名空间 ~topics/... ~calibration/...
|
||||
|
||||
// ---- 话题与队列 ----
|
||||
std::string joints_topic_ = "joint_states";
|
||||
std::string imu_topic_ = "imu/data";
|
||||
std::string cmd_topic_ = "joint_commands";
|
||||
int cmd_queue_ = 1; ///< 指令流只关心最新值,队列不堆积
|
||||
int state_queue_ = 10; ///< 状态流按 200 Hz 设计,队列给足以吸收抖动
|
||||
|
||||
// ---- 关节约定 ----
|
||||
std::vector<std::string> joint_names_;
|
||||
std::vector<float> joint_dir_; ///< +1 / -1
|
||||
std::vector<float> pos_offset_deg_; ///< 关节零点偏置 [deg]
|
||||
|
||||
bool auto_calibrate_ = false;
|
||||
float wrap_hip_deg_ = 140.f; ///< 标定时 hipy(k%4==1) 的回绕阈值
|
||||
float wrap_knee_deg_ = 164.f; ///< 标定时 knee(k%4==2) 的回绕阈值
|
||||
bool wheel_kp_zero_ = true; ///< 轮关节 (k%4==3) 强制 kp=0,速度/力矩模式
|
||||
|
||||
// ---- 状态缓存 ----
|
||||
double ri_ts_ = 0., imu_ts_ = 0.;
|
||||
Vec3f omega_body_, rpy_, acc_;
|
||||
VecXf joint_pos_, joint_vel_, joint_tau_;
|
||||
std::unordered_map<std::string, int> name2slot_;
|
||||
uint16_t joint_data_frame_ = 0;
|
||||
std::vector<uint16_t> joint_data_id_;
|
||||
std::vector<bool> joint_data_updated_; ///< 标定用:该关节是否已看到数据变化
|
||||
std::vector<uint16_t> driver_status_;
|
||||
bool warned_name_mismatch_ = false;
|
||||
bool warned_imu_no_orientation_ = false;
|
||||
|
||||
ros::Publisher cmd_pub_;
|
||||
ros::Subscriber joint_state_sub_, imu_sub_;
|
||||
|
||||
public:
|
||||
InvictaInterface(const std::string& robot_name, int dof_num) : RobotInterface(robot_name, dof_num) {
|
||||
joint_pos_ = VecXf::Zero(dof_num_);
|
||||
joint_vel_ = VecXf::Zero(dof_num_);
|
||||
joint_tau_ = VecXf::Zero(dof_num_);
|
||||
joint_data_id_.resize(dof_num_, 0);
|
||||
driver_status_.resize(dof_num_, 1);
|
||||
|
||||
LoadParams();
|
||||
|
||||
cmd_pub_ = nh_.advertise<invicta_msgs::JointCommandArray>(cmd_topic_, cmd_queue_);
|
||||
joint_state_sub_ = nh_.subscribe(joints_topic_, state_queue_, &InvictaInterface::JointStateHandler, this);
|
||||
imu_sub_ = nh_.subscribe(imu_topic_, state_queue_, &InvictaInterface::ImuHandler, this);
|
||||
}
|
||||
|
||||
virtual ~InvictaInterface() {}
|
||||
|
||||
// ------------------------------------------------------------------ 接口实现
|
||||
virtual void Start() {
|
||||
// 启动控制序列:先关使能,清错误,再使能。此后恒发 kMotorControl。
|
||||
SendStartupSequence();
|
||||
if (auto_calibrate_) {
|
||||
ResetPositionOffset();
|
||||
} else {
|
||||
std::cout << "[InvictaInterface] auto_calibrate=false,按参数给定的 dir/offset 直接使用\n";
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Stop() {}
|
||||
|
||||
virtual double GetInterfaceTimeStamp() { return ri_ts_; }
|
||||
virtual VecXf GetJointPosition() { return joint_pos_; }
|
||||
virtual VecXf GetJointVelocity() { return joint_vel_; }
|
||||
virtual VecXf GetJointTorque() { return joint_tau_; }
|
||||
virtual Vec3f GetImuRpy() { return rpy_; }
|
||||
virtual Vec3f GetImuAcc() { return acc_; }
|
||||
virtual Vec3f GetImuOmega() { return omega_body_; }
|
||||
virtual VecXf GetContactForce() { return VecXf::Zero(4); }
|
||||
virtual double GetImuTimestamp() { return imu_ts_; }
|
||||
virtual std::vector<uint16_t> GetJointDataID() { return joint_data_id_; }
|
||||
virtual std::vector<uint16_t> GetDriverStatusWord() { return driver_status_; }
|
||||
|
||||
virtual void SetJointCommand(Eigen::Matrix<float, Eigen::Dynamic, 5> input) {
|
||||
joint_cmd_ = input;
|
||||
invicta_msgs::JointCommandArray msg;
|
||||
msg.header.stamp = ros::Time::now();
|
||||
msg.name = joint_names_;
|
||||
msg.position.resize(dof_num_);
|
||||
msg.velocity.resize(dof_num_);
|
||||
msg.effort.resize(dof_num_);
|
||||
msg.kp.resize(dof_num_);
|
||||
msg.kd.resize(dof_num_);
|
||||
for (int i = 0; i < dof_num_; ++i) {
|
||||
msg.position[i] = (input(i, 1) - Deg2Rad(pos_offset_deg_[i])) * joint_dir_[i];
|
||||
msg.velocity[i] = input(i, 3) * joint_dir_[i];
|
||||
msg.effort[i] = input(i, 4) * joint_dir_[i];
|
||||
msg.kp[i] = input(i, 0);
|
||||
msg.kd[i] = input(i, 2);
|
||||
}
|
||||
if (wheel_kp_zero_) {
|
||||
for (int i = 3; i < dof_num_; i += 4) msg.kp[i] = 0.;
|
||||
}
|
||||
msg.control_word = invicta_msgs::kMotorControl;
|
||||
cmd_pub_.publish(msg);
|
||||
}
|
||||
|
||||
virtual void RefreshRobotData() {}
|
||||
|
||||
protected:
|
||||
// ------------------------------------------------------------------ 参数
|
||||
void LoadParams() {
|
||||
pnh_.param<std::string>("topics/joint_states", joints_topic_, "joint_states");
|
||||
pnh_.param<std::string>("topics/imu", imu_topic_, "imu/data");
|
||||
pnh_.param<std::string>("topics/joint_commands", cmd_topic_, "joint_commands");
|
||||
pnh_.param<int>("queues/joint_commands", cmd_queue_, 1);
|
||||
pnh_.param<int>("queues/state", state_queue_, 10);
|
||||
|
||||
joint_names_ = DefaultJointNames();
|
||||
pnh_.getParam("joint_names", joint_names_);
|
||||
if (static_cast<int>(joint_names_.size()) != dof_num_) {
|
||||
ROS_ERROR("[InvictaInterface] 参数 joint_names 长度 %zu != dof_num %d,使用默认顺序",
|
||||
joint_names_.size(), dof_num_);
|
||||
joint_names_ = DefaultJointNames();
|
||||
}
|
||||
name2slot_.clear();
|
||||
for (int i = 0; i < dof_num_; ++i) {
|
||||
name2slot_[joint_names_[i]] = i;
|
||||
}
|
||||
|
||||
joint_dir_.assign(dof_num_, 1.f);
|
||||
pos_offset_deg_.assign(dof_num_, 0.f);
|
||||
pnh_.getParam("calibration/joint_dir", joint_dir_);
|
||||
pnh_.getParam("calibration/joint_offset_deg", pos_offset_deg_);
|
||||
if (static_cast<int>(joint_dir_.size()) != dof_num_) joint_dir_.assign(dof_num_, 1.f);
|
||||
if (static_cast<int>(pos_offset_deg_.size()) != dof_num_) pos_offset_deg_.assign(dof_num_, 0.f);
|
||||
|
||||
pnh_.param<bool>("calibration/auto_calibrate", auto_calibrate_, false);
|
||||
pnh_.param("calibration/wrap_hip_deg", wrap_hip_deg_, 140.f);
|
||||
pnh_.param("calibration/wrap_knee_deg", wrap_knee_deg_, 164.f);
|
||||
pnh_.param<bool>("wheel_kp_zero", wheel_kp_zero_, true);
|
||||
|
||||
ROS_INFO_STREAM("[InvictaInterface] topics: " << joints_topic_ << " / " << imu_topic_ << " / " << cmd_topic_
|
||||
<< " | auto_calibrate=" << auto_calibrate_
|
||||
<< " wheel_kp_zero=" << wheel_kp_zero_);
|
||||
std::cout << "[InvictaInterface] joint_dir: ";
|
||||
for (float d : joint_dir_) std::cout << d << " ";
|
||||
std::cout << "\n[InvictaInterface] joint_offset_deg: ";
|
||||
for (float o : pos_offset_deg_) std::cout << o << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
static std::vector<std::string> DefaultJointNames() {
|
||||
// 与 policy.onnx 的动作/观测顺序一致,见 invicta_deploy/README.md
|
||||
return {"fl_hipx_joint", "fl_hipy_joint", "fl_knee_joint", "fl_wheel_joint",
|
||||
"fr_hipx_joint", "fr_hipy_joint", "fr_knee_joint", "fr_wheel_joint",
|
||||
"hl_hipx_joint", "hl_hipy_joint", "hl_knee_joint", "hl_wheel_joint",
|
||||
"hr_hipx_joint", "hr_hipy_joint", "hr_knee_joint", "hr_wheel_joint"};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ 启动/标定
|
||||
void PublishRawCommand(uint16_t control_word) {
|
||||
invicta_msgs::JointCommandArray msg;
|
||||
msg.header.stamp = ros::Time::now();
|
||||
msg.name = joint_names_;
|
||||
msg.position.assign(dof_num_, 0.);
|
||||
msg.velocity.assign(dof_num_, 0.);
|
||||
msg.effort.assign(dof_num_, 0.);
|
||||
msg.kp.assign(dof_num_, 0.);
|
||||
msg.kd.assign(dof_num_, 0.);
|
||||
msg.control_word = control_word;
|
||||
cmd_pub_.publish(msg);
|
||||
}
|
||||
|
||||
void SendStartupSequence() {
|
||||
const uint16_t seq[] = {invicta_msgs::kDisable, invicta_msgs::kErrorReset, invicta_msgs::kEnable};
|
||||
for (uint16_t word : seq) {
|
||||
PublishRawCommand(word);
|
||||
ros::Duration(0.01).sleep();
|
||||
}
|
||||
std::cout << "[InvictaInterface] 启动控制序列完成 (disable -> error_reset -> enable)\n";
|
||||
}
|
||||
|
||||
bool IsDataUpdatedFinished() {
|
||||
bool res = true;
|
||||
for (int i = 0; i < dof_num_; ++i) res = res && joint_data_updated_[i];
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 上电标定:等待 16 个关节数据都发生更新,并按阈值修正 ±360° 回绕
|
||||
*
|
||||
* 只有在硬件桥接节点上报的是「原始编码器角 + M20 约定」时才需要打开
|
||||
* (calibration/auto_calibrate=true)。若桥接节点已经给出 policy 约定的角度,
|
||||
* 保持 false。
|
||||
*/
|
||||
void ResetPositionOffset() {
|
||||
joint_data_updated_.assign(dof_num_, false);
|
||||
SetJointCommand(MatXf::Zero(dof_num_, 5));
|
||||
ros::Duration(0.1).sleep();
|
||||
|
||||
VecXf last = GetJointPosition();
|
||||
int cnt = 0;
|
||||
while (!IsDataUpdatedFinished()) {
|
||||
++cnt;
|
||||
ros::spinOnce();
|
||||
VecXf cur = GetJointPosition();
|
||||
for (int i = 0; i < dof_num_; ++i) {
|
||||
if (!joint_data_updated_[i] && cur(i) != last(i) && !std::isnan(cur(i))) {
|
||||
joint_data_updated_[i] = true;
|
||||
std::cout << "joint " << i << " data updated at " << cnt << " cnt!" << std::endl;
|
||||
}
|
||||
}
|
||||
last = cur;
|
||||
ros::Duration(0.001).sleep();
|
||||
if (cnt > 10000) {
|
||||
ROS_ERROR("[InvictaInterface] 关节数据未全部更新,标定失败,继续用参数值");
|
||||
return;
|
||||
}
|
||||
}
|
||||
VecXf cur = GetJointPosition();
|
||||
for (int k = 0; k < dof_num_; ++k) {
|
||||
float th = (k % 4 == 1) ? wrap_hip_deg_ : wrap_knee_deg_;
|
||||
if (k % 4 == 3) continue; // 轮关节不做回绕
|
||||
if (cur(k) < -th / 180. * M_PI) {
|
||||
pos_offset_deg_[k] += 360.;
|
||||
std::cout << "joint " << k << " offset -> " << pos_offset_deg_[k] << "\n";
|
||||
} else if (cur(k) > th / 180. * M_PI) {
|
||||
pos_offset_deg_[k] -= 360.;
|
||||
std::cout << "joint " << k << " offset -> " << pos_offset_deg_[k] << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ 回调
|
||||
void JointStateHandler(const sensor_msgs::JointState::ConstPtr& msg) {
|
||||
if (static_cast<int>(msg->position.size()) != dof_num_ ||
|
||||
static_cast<int>(msg->velocity.size()) != dof_num_ ||
|
||||
static_cast<int>(msg->effort.size()) != dof_num_) {
|
||||
ROS_WARN_THROTTLE(5.0, "[InvictaInterface] %s 长度应为 %d,收到 pos=%zu vel=%zu eff=%zu,丢帧",
|
||||
joints_topic_.c_str(), dof_num_, msg->position.size(), msg->velocity.size(),
|
||||
msg->effort.size());
|
||||
return;
|
||||
}
|
||||
|
||||
bool by_name = static_cast<int>(msg->name.size()) == dof_num_;
|
||||
int unknown = 0;
|
||||
for (int j = 0; j < dof_num_; ++j) {
|
||||
int i = by_name ? LookupSlot(msg->name[j]) : j;
|
||||
if (i < 0) {
|
||||
++unknown;
|
||||
continue;
|
||||
}
|
||||
joint_pos_(i) = float(msg->position[j]) * joint_dir_[i] + Deg2Rad(pos_offset_deg_[i]);
|
||||
joint_vel_(i) = float(msg->velocity[j]) * joint_dir_[i];
|
||||
joint_tau_(i) = float(msg->effort[j]) * joint_dir_[i];
|
||||
}
|
||||
if (!by_name && !warned_name_mismatch_) {
|
||||
warned_name_mismatch_ = true;
|
||||
ROS_WARN("[InvictaInterface] %s 未按约定给出 %d 个 name,按数组下标解析",
|
||||
joints_topic_.c_str(), dof_num_);
|
||||
}
|
||||
if (unknown > 0) {
|
||||
ROS_WARN_THROTTLE(5.0, "[InvictaInterface] %s 有 %d 个关节名不认识,已忽略",
|
||||
joints_topic_.c_str(), unknown);
|
||||
}
|
||||
|
||||
for (int i = 0; i < dof_num_; ++i) joint_data_id_[i] = joint_data_frame_;
|
||||
++joint_data_frame_;
|
||||
ri_ts_ = msg->header.stamp.toSec();
|
||||
}
|
||||
|
||||
int LookupSlot(const std::string& name) const {
|
||||
auto it = name2slot_.find(name);
|
||||
return it == name2slot_.end() ? -1 : it->second;
|
||||
}
|
||||
|
||||
void ImuHandler(const sensor_msgs::Imu::ConstPtr& msg) {
|
||||
// orientation_covariance[0] == -1 表示「不提供姿态」,此时不能拿它当有效姿态用
|
||||
if (msg->orientation_covariance[0] == -1.0) {
|
||||
if (!warned_imu_no_orientation_) {
|
||||
warned_imu_no_orientation_ = true;
|
||||
ROS_WARN("[InvictaInterface] %s 没有提供 orientation(covariance=-1),姿态观测无效",
|
||||
imu_topic_.c_str());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Eigen::Quaternionf q(float(msg->orientation.w), float(msg->orientation.x), float(msg->orientation.y),
|
||||
float(msg->orientation.z));
|
||||
if (q.norm() < 1e-6f) {
|
||||
ROS_WARN_THROTTLE(5.0, "[InvictaInterface] %s 四元数模长近零,忽略该帧", imu_topic_.c_str());
|
||||
return;
|
||||
}
|
||||
q.normalize();
|
||||
// eulerAngles(0,1,2) 即 ZYX 顺序,与 basic_function.hpp 的 RpyToRm 一致
|
||||
rpy_ = q.toRotationMatrix().eulerAngles(0, 1, 2).cast<float>();
|
||||
omega_body_ << msg->angular_velocity.x, msg->angular_velocity.y, msg->angular_velocity.z;
|
||||
acc_ << msg->linear_acceleration.x, msg->linear_acceleration.y, msg->linear_acceleration.z;
|
||||
imu_ts_ = msg->header.stamp.toSec();
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace interface
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @file robot_interface.h
|
||||
* @brief 机器人控制接口抽象:状态机只依赖这个接口,不关心数据来自话题还是别的通道
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include "common_types.h"
|
||||
|
||||
using namespace types;
|
||||
|
||||
namespace interface {
|
||||
|
||||
class RobotInterface {
|
||||
public:
|
||||
/**
|
||||
* @param robot_name 机器人名(仅用于打印)
|
||||
* @param dof_num 自由度数量(invicta 固定 16,与 policy.onnx 绑定)
|
||||
*/
|
||||
RobotInterface(const std::string& robot_name, int dof_num) : robot_name_(robot_name), dof_num_(dof_num) {
|
||||
start_flag_ = true;
|
||||
joint_cmd_ = Eigen::Matrix<float, Eigen::Dynamic, 5>::Zero(dof_num_, 5);
|
||||
}
|
||||
virtual ~RobotInterface(){};
|
||||
|
||||
std::string robot_name_;
|
||||
const int dof_num_;
|
||||
Eigen::Matrix<float, Eigen::Dynamic, 5> joint_cmd_;
|
||||
std::atomic<bool> start_flag_;
|
||||
|
||||
/// 建立通信、做启动标定
|
||||
virtual void Start() = 0;
|
||||
|
||||
/// 停止控制、释放通信
|
||||
virtual void Stop() = 0;
|
||||
|
||||
/// 最近一帧关节数据的时间戳 [s]
|
||||
virtual double GetInterfaceTimeStamp() = 0;
|
||||
|
||||
/// 关节角 [rad],长度 dof_num_
|
||||
virtual VecXf GetJointPosition() = 0;
|
||||
|
||||
/// 关节角速度 [rad/s]
|
||||
virtual VecXf GetJointVelocity() = 0;
|
||||
|
||||
/// 关节力矩 [Nm]
|
||||
virtual VecXf GetJointTorque() = 0;
|
||||
|
||||
/// 基座 roll-pitch-yaw [rad]
|
||||
virtual Vec3f GetImuRpy() = 0;
|
||||
|
||||
/// 基座加速度 [m/s^2]
|
||||
virtual Vec3f GetImuAcc() = 0;
|
||||
|
||||
/// 基座角速度,机体系 [rad/s]
|
||||
virtual Vec3f GetImuOmega() = 0;
|
||||
|
||||
/**
|
||||
* @brief 下发关节指令(标准形式)
|
||||
* torque = kp * (qDes - q) + kd * (vDes - v) + tff
|
||||
* @param input dof_num_ × 5 矩阵,列为 [kp, qDes, kd, vDes, tff]
|
||||
*/
|
||||
virtual void SetJointCommand(Eigen::Matrix<float, Eigen::Dynamic, 5> input) = 0;
|
||||
|
||||
virtual MatXf GetJointCommand() { return joint_cmd_; }
|
||||
|
||||
/// 接触力(invicta 无足端力传感器,返回零)
|
||||
virtual VecXf GetContactForce() = 0;
|
||||
|
||||
/// IMU 数据时间戳 [s]
|
||||
virtual double GetImuTimestamp() { return 0.; }
|
||||
|
||||
/**
|
||||
* @brief 关节电机温度 [℃]
|
||||
*
|
||||
* invicta 的硬件桥接节点目前不发布温度:sensor_msgs/JointState 没有对应字段。
|
||||
* 这里返回常温常量,结果是 SafeController 的过温检查恒不触发(保护由硬件急停兜底)。
|
||||
* 若以后桥接节点通过独立诊断话题提供温度,在此覆盖该函数即可。
|
||||
*/
|
||||
virtual VecXf GetMotorTemperture() { return 30. * VecXf::Ones(dof_num_); }
|
||||
|
||||
virtual VecXf GetDriverTemperture() { return VecXf::Zero(dof_num_); }
|
||||
|
||||
/**
|
||||
* @brief 驱动器状态字,1 表示正常
|
||||
*
|
||||
* 同 GetMotorTemperture:invicta 暂不提供,返回全 1 使 DriveStatus 检查不报警。
|
||||
*/
|
||||
virtual std::vector<uint16_t> GetDriverStatusWord() { return std::vector<uint16_t>(dof_num_, 1); }
|
||||
|
||||
/**
|
||||
* @brief 关节数据帧号,用于判断数据是否在更新
|
||||
*/
|
||||
virtual std::vector<uint16_t> GetJointDataID() { return std::vector<uint16_t>(dof_num_, 0); }
|
||||
|
||||
virtual void RefreshRobotData() {}
|
||||
};
|
||||
|
||||
}; // namespace interface
|
||||
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* @file ros_command_interface.hpp
|
||||
* @brief 指令输入实现:订阅 /motion_command(由 invicta_remote 发布),翻译成状态机意图
|
||||
*
|
||||
* 从上游 M20 的 GamepadInterface 演变而来:网络/JSON/协议部分已移到 invicta_remote,
|
||||
* 这里只保留「协议语义 → 状态机意图」的翻译,以及状态切换与步态的合法性判断。
|
||||
* 值域依据 proto.md(invicta_msgs/motion_defs.h)。
|
||||
*
|
||||
* 关于合法性判断的分工(与 invicta_remote 的边界):
|
||||
* - invicta_remote 只回「命令已接收」(ErrorCode=0,协议明确其含义不含业务成功)
|
||||
* - 真正的接受/拒绝发生在这里,结果由本节点通过 /motion_state 回报真实状态
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ros/ros.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "basic_function.hpp"
|
||||
#include "custom_types.h"
|
||||
#include "invicta_msgs/MotionCommand.h"
|
||||
#include "invicta_msgs/motion_defs.h"
|
||||
#include "user_command_interface.h"
|
||||
|
||||
namespace interface {
|
||||
|
||||
using namespace invicta_msgs;
|
||||
|
||||
class RosCommandInterface : public UserCommandInterface {
|
||||
public:
|
||||
/**
|
||||
* @param loaded_gaits 实际加载成功的步态集合(由 RLControlState 在构造时填充)
|
||||
* @param default_gait 默认步态(协议 GaitParam)
|
||||
*/
|
||||
RosCommandInterface(std::shared_ptr<std::set<int>> loaded_gaits, int default_gait)
|
||||
: loaded_gaits_(std::move(loaded_gaits)), default_gait_(default_gait) {
|
||||
pnh_.param<std::string>("topics/motion_command", topic_, "motion_command");
|
||||
pnh_.param<int>("queues/motion_command", cmd_queue_, 1);
|
||||
sub_ = nh_.subscribe(topic_, cmd_queue_, &RosCommandInterface::CommandCallback, this);
|
||||
}
|
||||
|
||||
~RosCommandInterface() {}
|
||||
|
||||
void Start() override {
|
||||
if (msfb_) msfb_->UpdateCurrentGait(uint32_t(default_gait_));
|
||||
std::cout << "\n╔════════════════════════════════════════════════╗\n"
|
||||
<< "║ INVICTA MOTION COMMAND LINK ║\n"
|
||||
<< "╚════════════════════════════════════════════════╝\n"
|
||||
<< " 指令来源: " << topic_ << "(由 invicta_remote 发布)\n"
|
||||
<< " 默认步态: " << GaitName(uint32_t(default_gait_)) << "\n"
|
||||
<< " 已支持步态: " << SupportedGaitList() << "\n\n";
|
||||
}
|
||||
|
||||
void Stop() override {}
|
||||
|
||||
UserCommand* GetUserCommand() override { return usr_cmd_; }
|
||||
|
||||
private:
|
||||
std::string SupportedGaitList() const {
|
||||
if (!loaded_gaits_ || loaded_gaits_->empty()) return "(无)";
|
||||
std::string s;
|
||||
for (int gait : *loaded_gaits_) {
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "0x%04X", gait);
|
||||
s += std::string(GaitName(uint32_t(gait))) + "(" + buf + ") ";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 状态切换统一入口(前置条件沿用上游 M20 的按键逻辑)
|
||||
* @param target proto.md 的 MotionParam 值
|
||||
*/
|
||||
bool RequestMotionState(uint8_t target, const std::string& src) {
|
||||
const uint8_t cur = msfb_->GetCurrentState();
|
||||
uint8_t next = 0;
|
||||
bool accepted = false;
|
||||
const char* name = "?";
|
||||
|
||||
switch (int(target)) {
|
||||
case kMotionStanding:
|
||||
name = "站立";
|
||||
next = uint8_t(RobotMotionState::StandingUp);
|
||||
accepted = (cur == RobotMotionState::WaitingForStand || cur == RobotMotionState::LieDown);
|
||||
break;
|
||||
case kMotionJointDamping:
|
||||
name = "关节阻尼";
|
||||
next = uint8_t(RobotMotionState::JointDamping);
|
||||
accepted = true;
|
||||
break;
|
||||
case kMotionBootDamping:
|
||||
name = "开机阻尼(按关节阻尼处理)";
|
||||
next = uint8_t(RobotMotionState::JointDamping);
|
||||
accepted = true;
|
||||
break;
|
||||
case kMotionLieDown:
|
||||
name = "趴下";
|
||||
next = uint8_t(RobotMotionState::LieDown);
|
||||
accepted = (cur == RobotMotionState::StandingUp || cur == RobotMotionState::RLControlMode);
|
||||
break;
|
||||
case kMotionRlControl:
|
||||
name = "RL控制";
|
||||
next = uint8_t(RobotMotionState::RLControlMode);
|
||||
accepted = (cur == RobotMotionState::StandingUp);
|
||||
break;
|
||||
case kMotionIdle:
|
||||
// 状态机没有「直接回空闲」的路径(RL / 站立只能经阻尼或趴下退出),不作为请求
|
||||
if (last_request_ != kMotionIdle) {
|
||||
std::cout << "[MODE] 空闲(0):不作为切换请求(退出 RL 请先切关节阻尼或趴下)" << std::endl;
|
||||
}
|
||||
last_request_ = kMotionIdle;
|
||||
return false;
|
||||
default:
|
||||
std::cout << "[MODE] 未知目标状态 " << int(target) << "(来自 " << src << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 已经处于目标状态:视为成功,不重复打日志(遥控器可能反复发同一档位)
|
||||
if (next == cur) {
|
||||
last_request_ = target;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (accepted) {
|
||||
usr_cmd_->target_mode = next;
|
||||
if (last_request_ != target) std::cout << "[MODE] " << name << "(来自 " << src << ")" << std::endl;
|
||||
} else if (last_request_ != target) {
|
||||
std::cout << "[MODE] 拒绝 " << name << "(来自 " << src << ",当前状态 " << int(cur) << ")" << std::endl;
|
||||
}
|
||||
last_request_ = target;
|
||||
return accepted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 步态切换:每个步态对应一个 RL 模型
|
||||
*
|
||||
* 未注册(模型尚未训练)的步态在这里被拒绝并记录;真实生效的步态由 /motion_state 回报,
|
||||
* 所以遥控器看到的是「已接收」,而实际值以状态上报为准。
|
||||
*/
|
||||
void ApplyGait(uint32_t gait, const std::string& src) {
|
||||
if (gait == 0 || gait == last_gait_request_) return;
|
||||
// 只有"启动时真的加载了模型"的步态才接受;否则状态会上报未切换,而不是假成功
|
||||
if (!loaded_gaits_ || loaded_gaits_->count(int(gait)) == 0) {
|
||||
std::cout << "[GAIT] 拒绝 " << GaitName(gait) << "(来自 " << src
|
||||
<< "):该步态没有对应的 RL 模型(启动时未加载,见 gait/policy_map)" << std::endl;
|
||||
last_gait_request_ = gait;
|
||||
return;
|
||||
}
|
||||
usr_cmd_->gait = gait;
|
||||
if (msfb_) msfb_->UpdateCurrentGait(gait);
|
||||
std::cout << "[GAIT] " << GaitName(gait) << "(来自 " << src << "),实际生效" << std::endl;
|
||||
last_gait_request_ = gait;
|
||||
}
|
||||
|
||||
void CommandCallback(const invicta_msgs::MotionCommand::ConstPtr& msg) {
|
||||
const std::string src = "invicta_remote";
|
||||
if (!has_command_) {
|
||||
has_command_ = true;
|
||||
std::cout << "[MODE] 收到第一条运动指令(" << topic_ << ")" << std::endl;
|
||||
}
|
||||
|
||||
// 轴指令:协议里是比例 [-1,1],策略直接用这三个分量
|
||||
usr_cmd_->forward_vel_scale = msg->x;
|
||||
usr_cmd_->side_vel_scale = msg->y;
|
||||
usr_cmd_->turnning_vel_scale = msg->yaw;
|
||||
usr_cmd_->time_stamp = GetTimestampMs() / 1000.; // 秒;断连判断目前未接线(见 README 已知缺口)
|
||||
|
||||
if (msg->usage_mode != usr_cmd_->usage_mode) {
|
||||
usr_cmd_->usage_mode = msg->usage_mode;
|
||||
std::cout << "[MODE] 使用模式 -> " << int(msg->usage_mode) << "(0 常规 / 1 导航 / 2 辅助)" << std::endl;
|
||||
}
|
||||
|
||||
RequestMotionState(msg->target_state, src);
|
||||
ApplyGait(msg->gait, src);
|
||||
}
|
||||
|
||||
ros::NodeHandle nh_;
|
||||
ros::NodeHandle pnh_{"~"};
|
||||
ros::Subscriber sub_;
|
||||
std::string topic_ = "motion_command";
|
||||
int cmd_queue_ = 1;
|
||||
|
||||
std::shared_ptr<std::set<int>> loaded_gaits_; ///< 实际加载成功的步态(由 RLControlState 填充)
|
||||
int default_gait_ = int(kGaitBasic);
|
||||
|
||||
uint8_t last_request_ = kMotionIdle;
|
||||
uint32_t last_gait_request_ = 0;
|
||||
bool has_command_ = false;
|
||||
};
|
||||
|
||||
}; // namespace interface
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file user_command_interface.h
|
||||
* @brief 用户指令输入接口(invicta 只有 UDP 手柄一路)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "common_types.h"
|
||||
#include "custom_types.h"
|
||||
#include "motion_state_feedback.hpp"
|
||||
|
||||
using namespace types;
|
||||
|
||||
namespace interface {
|
||||
|
||||
class UserCommandInterface {
|
||||
public:
|
||||
UserCommandInterface() {
|
||||
usr_cmd_ = new UserCommand();
|
||||
std::memset(usr_cmd_, 0, sizeof(UserCommand));
|
||||
}
|
||||
virtual ~UserCommandInterface() { delete usr_cmd_; }
|
||||
|
||||
/// 启动指令解析(手柄走网络,这里只做提示打印)
|
||||
virtual void Start() = 0;
|
||||
|
||||
virtual void Stop() = 0;
|
||||
|
||||
virtual UserCommand* GetUserCommand() = 0;
|
||||
|
||||
virtual void SetMotionStateFeedback(MotionStateFeedback* msfb) { msfb_ = msfb; }
|
||||
|
||||
MotionStateFeedback* msfb_;
|
||||
UserCommand* usr_cmd_;
|
||||
};
|
||||
|
||||
}; // namespace interface
|
||||
@@ -0,0 +1,14 @@
|
||||
<launch>
|
||||
<!-- RL 部署节点:状态机 + 策略推理。参数在节点的私有命名空间下。
|
||||
无硬件台架自测时(invicta_hardware 只发零位状态)关掉两个自检,
|
||||
否则站立完成后永远不会自动进入 RL:
|
||||
roslaunch invicta_deploy invicta_deploy.launch rl_require_pose:=false rl_require_imu:=false
|
||||
-->
|
||||
<arg name="rl_require_pose" default="true"/>
|
||||
<arg name="rl_require_imu" default="true"/>
|
||||
<node pkg="invicta_deploy" type="invicta_deploy" name="invicta_deploy" output="screen">
|
||||
<rosparam command="load" file="$(find invicta_deploy)/config/invicta_deploy.yaml"/>
|
||||
<param name="rl/require_pose" value="$(arg rl_require_pose)"/>
|
||||
<param name="rl/require_imu" value="$(arg rl_require_imu)"/>
|
||||
</node>
|
||||
</launch>
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @file main.cpp
|
||||
* @brief invicta RL deploy 入口:ROS 回调跑在 main 线程,控制线程跑 200 Hz 状态机
|
||||
*/
|
||||
#include <ros/ros.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "quadruped_wheel/invicta_state_machine.hpp"
|
||||
|
||||
using namespace types;
|
||||
|
||||
MotionStateFeedback StateBase::msfb_ = MotionStateFeedback();
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ros::init(argc, argv, "invicta_deploy");
|
||||
std::cout << "Invicta State Machine Start Running" << std::endl;
|
||||
|
||||
std::shared_ptr<StateMachineBase> fsm = std::make_shared<invicta::InvictaStateMachine>();
|
||||
fsm->Start();
|
||||
fsm->Run();
|
||||
fsm->Stop();
|
||||
|
||||
ros::shutdown();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<package format="2">
|
||||
<name>invicta_deploy</name>
|
||||
<version>0.1.0</version>
|
||||
<description>
|
||||
invicta 的 RL sim2real 部署节点:状态机 + ONNX 策略推理 + UDP 手柄遥控。
|
||||
数据面复用标准消息 sensor_msgs/JointState、sensor_msgs/Imu,指令用 invicta_msgs/JointCommandArray。
|
||||
</description>
|
||||
<maintainer email="todo@example.com">TODO</maintainer>
|
||||
<license>BSD-3-Clause</license>
|
||||
|
||||
<buildtool_depend>catkin</buildtool_depend>
|
||||
|
||||
<depend>roscpp</depend>
|
||||
<depend>roslib</depend>
|
||||
<depend>sensor_msgs</depend>
|
||||
<depend>invicta_msgs</depend>
|
||||
</package>
|
||||
Binary file not shown.
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @file invicta_policy_runner.hpp
|
||||
* @brief ONNX 策略推理(由上游 M20PolicyRunner 移植)
|
||||
*
|
||||
* 策略与关节顺序、动作尺度、默认关节角绑定,改这些就等于换策略,请一起改。
|
||||
* 观测 57 维 = 角速度(3) + 投影重力(3) + 速度指令(3) + 关节角(16) + 关节角速度(16) + 上一步动作(16)
|
||||
*/
|
||||
#pragma once
|
||||
#define PI 3.14159265358979323846
|
||||
|
||||
#include <onnxruntime_c_api.h>
|
||||
#include <onnxruntime_cxx_api.h>
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "policy_runner_base.hpp"
|
||||
|
||||
class InvictaPolicyRunner : public PolicyRunnerBase {
|
||||
private:
|
||||
VecXf kp_, kd_;
|
||||
VecXf dof_default_eigen_policy, dof_default_eigen_robot;
|
||||
Vec3f gravity_direction = Vec3f(0., 0., -1.);
|
||||
|
||||
const int motor_num = 16;
|
||||
const int observation_dim = 57;
|
||||
const int action_dim = 16;
|
||||
float agent_timestep = 0.02; ///< 策略决策周期 0.02 s = 50 Hz
|
||||
|
||||
VecXf joint_pos_rl = VecXf(action_dim); ///< policy 关节顺序
|
||||
VecXf joint_vel_rl = VecXf(action_dim);
|
||||
|
||||
const std::string policy_path_;
|
||||
|
||||
float omega_scale_ = 0.25;
|
||||
float dof_vel_scale_ = 0.05;
|
||||
VecXf imu_w_eigen, base_acc_eigen, motor_p_eigen, motor_v_eigen, current_action_eigen, last_action_eigen,
|
||||
current_observation_, tmp_action_eigen;
|
||||
|
||||
RobotAction robot_action;
|
||||
|
||||
/// 机器人(话题)关节顺序 = /joint_states 的 name 顺序
|
||||
std::vector<std::string> robot_order = {"fl_hipx_joint", "fl_hipy_joint", "fl_knee_joint", "fl_wheel_joint",
|
||||
"fr_hipx_joint", "fr_hipy_joint", "fr_knee_joint", "fr_wheel_joint",
|
||||
"hl_hipx_joint", "hl_hipy_joint", "hl_knee_joint", "hl_wheel_joint",
|
||||
"hr_hipx_joint", "hr_hipy_joint", "hr_knee_joint", "hr_wheel_joint"};
|
||||
|
||||
/// 策略内部关节顺序(12 个腿关节在前,4 个轮在后),与训练导出绑定
|
||||
std::vector<std::string> policy_order = {
|
||||
"fl_hipx_joint", "fl_hipy_joint", "fl_knee_joint", "fr_hipx_joint", "fr_hipy_joint", "fr_knee_joint",
|
||||
"hl_hipx_joint", "hl_hipy_joint", "hl_knee_joint", "hr_hipx_joint", "hr_hipy_joint", "hr_knee_joint",
|
||||
"fl_wheel_joint", "fr_wheel_joint", "hl_wheel_joint", "hr_wheel_joint",
|
||||
};
|
||||
|
||||
std::vector<float> action_scale_robot = {0.125, 0.25, 0.25, 5, 0.125, 0.25, 0.25, 5,
|
||||
0.125, 0.25, 0.25, 5, 0.125, 0.25, 0.25, 5};
|
||||
|
||||
Ort::SessionOptions session_options_;
|
||||
Ort::Session session_{nullptr};
|
||||
Ort::Env env_;
|
||||
std::vector<int> robot2policy_idx, policy2robot_idx;
|
||||
|
||||
const char* input_names_[1] = {"obs"}; // 必须与模型导出时一致
|
||||
const char* output_names_[1] = {"actions"};
|
||||
Ort::MemoryInfo memory_info{nullptr};
|
||||
const std::array<int64_t, 2> input_observationShape = {1, observation_dim};
|
||||
|
||||
public:
|
||||
InvictaPolicyRunner(const std::string& policy_name, const std::string& policy_path)
|
||||
: PolicyRunnerBase(policy_name),
|
||||
policy_path_(policy_path),
|
||||
env_(ORT_LOGGING_LEVEL_WARNING, "InvictaPolicyRunner"),
|
||||
session_options_{},
|
||||
session_{nullptr},
|
||||
memory_info(Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault)) {
|
||||
dof_default_eigen_policy.setZero(action_dim);
|
||||
dof_default_eigen_robot.setZero(action_dim);
|
||||
dof_default_eigen_policy << 0.0, -0.3, 0.6, 0.0, -0.3, 0.6, 0.0, 0.3, -0.6, 0.0, 0.3, -0.6, 0.0, 0.0, 0.0, 0.0;
|
||||
dof_default_eigen_robot << 0.0, -0.3, 0.6, 0.0, 0.0, -0.3, 0.6, 0.0, 0.0, 0.3, -0.6, 0.0, 0.0, 0.3, -0.6, 0.0;
|
||||
SetDecimation(4);
|
||||
session_options_.SetIntraOpNumThreads(4);
|
||||
session_options_.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
|
||||
|
||||
if (access(policy_path_.c_str(), F_OK) != 0) {
|
||||
std::cerr << "Model file not found: " << policy_path_ << std::endl;
|
||||
throw std::runtime_error("Model file missing");
|
||||
}
|
||||
|
||||
session_ = Ort::Session(env_, policy_path_.c_str(), session_options_);
|
||||
kp_ = Vec4f(80, 80, 80, 0.).replicate(4, 1);
|
||||
kd_ = Vec4f(2, 2, 2, 0.6).replicate(4, 1);
|
||||
|
||||
robot2policy_idx = generate_permutation(robot_order, policy_order);
|
||||
policy2robot_idx = generate_permutation(policy_order, robot_order);
|
||||
|
||||
robot_action.kp = kp_;
|
||||
robot_action.kd = kd_;
|
||||
robot_action.tau_ff = VecXf::Zero(motor_num);
|
||||
robot_action.goal_joint_pos = VecXf::Zero(motor_num);
|
||||
robot_action.goal_joint_vel = VecXf::Zero(motor_num);
|
||||
|
||||
current_observation_.setZero(observation_dim);
|
||||
last_action_eigen.setZero(action_dim);
|
||||
tmp_action_eigen.setZero(action_dim);
|
||||
current_action_eigen.setZero(action_dim);
|
||||
}
|
||||
|
||||
~InvictaPolicyRunner() override = default;
|
||||
|
||||
static std::vector<int> generate_permutation(const std::vector<std::string>& from,
|
||||
const std::vector<std::string>& to, int default_index = 0) {
|
||||
std::unordered_map<std::string, int> idx_map;
|
||||
for (int i = 0; i < static_cast<int>(from.size()); ++i) idx_map[from[i]] = i;
|
||||
|
||||
std::vector<int> perm;
|
||||
for (const auto& name : to) {
|
||||
auto it = idx_map.find(name);
|
||||
perm.push_back(it != idx_map.end() ? it->second : default_index);
|
||||
}
|
||||
return perm;
|
||||
}
|
||||
|
||||
void DisplayPolicyInfo() {}
|
||||
|
||||
void OnEnter() {
|
||||
run_cnt_ = 0;
|
||||
cmd_vel_input_.setZero();
|
||||
last_action_eigen.setZero(action_dim);
|
||||
tmp_action_eigen.setZero(action_dim);
|
||||
motor_p_eigen.setZero(12);
|
||||
motor_v_eigen.setZero(motor_num);
|
||||
}
|
||||
|
||||
VecXf Onnx_infer(VecXf current_observation) {
|
||||
Ort::Value input_tensor =
|
||||
Ort::Value::CreateTensor<float>(memory_info, current_observation.data(),
|
||||
current_observation.size(), input_observationShape.data(),
|
||||
input_observationShape.size());
|
||||
|
||||
std::vector<Ort::Value> inputs;
|
||||
inputs.emplace_back(std::move(input_tensor));
|
||||
|
||||
auto outputs =
|
||||
session_.Run(Ort::RunOptions{nullptr}, input_names_, inputs.data(), 1, output_names_, 1);
|
||||
|
||||
float* action_data = outputs[0].GetTensorMutableData<float>();
|
||||
Eigen::Map<Eigen::VectorXf> action_map(action_data, action_dim);
|
||||
return VecXf(action_map);
|
||||
}
|
||||
|
||||
RobotAction getRobotAction(const RobotBasicState& ro, const UserCommand& uc) {
|
||||
Vec3f base_omega = ro.base_omega * omega_scale_;
|
||||
Vec3f projected_gravity_vec = ro.base_rot_mat.inverse() * gravity_direction;
|
||||
Vec3f cmd = Vec3f(uc.forward_vel_scale, uc.side_vel_scale, uc.turnning_vel_scale);
|
||||
|
||||
for (int i = 0; i < action_dim; ++i) {
|
||||
joint_pos_rl(i) = ro.joint_pos(robot2policy_idx[i]);
|
||||
joint_vel_rl(i) = ro.joint_vel(robot2policy_idx[i]) * dof_vel_scale_;
|
||||
}
|
||||
joint_pos_rl.segment(12, 4).setZero(); // 轮关节角不进观测
|
||||
|
||||
joint_pos_rl -= dof_default_eigen_policy;
|
||||
current_observation_ << base_omega, projected_gravity_vec, cmd, joint_pos_rl, joint_vel_rl,
|
||||
last_action_eigen;
|
||||
|
||||
current_action_eigen = Onnx_infer(current_observation_);
|
||||
last_action_eigen = current_action_eigen;
|
||||
|
||||
for (int i = 0; i < action_dim; ++i) {
|
||||
tmp_action_eigen(i) = current_action_eigen(policy2robot_idx[i]);
|
||||
tmp_action_eigen(i) *= action_scale_robot[i];
|
||||
}
|
||||
tmp_action_eigen += dof_default_eigen_robot;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
robot_action.goal_joint_pos.segment(i * 4, 3) = tmp_action_eigen.segment(i * 4, 3);
|
||||
robot_action.goal_joint_vel(i * 4 + 3) = tmp_action_eigen(i * 4 + 3);
|
||||
}
|
||||
|
||||
++run_cnt_;
|
||||
return robot_action;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file policy_runner_base.hpp
|
||||
* @brief policy runner base class
|
||||
* @author DeepRobotics
|
||||
* @version 1.0
|
||||
* @date 2025-11-07
|
||||
*
|
||||
* @copyright Copyright (c) 2025 DeepRobotics
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common_types.h"
|
||||
#include "basic_function.hpp"
|
||||
#include "onnxruntime_cxx_api.h"
|
||||
|
||||
using namespace types;
|
||||
|
||||
class PolicyRunnerBase{
|
||||
public:
|
||||
PolicyRunnerBase(std::string policy_name):policy_name_(policy_name){
|
||||
vel_delta_const_ << 0.3, 0.2, 0.3;
|
||||
cmd_vel_input_.setZero();
|
||||
}
|
||||
virtual ~PolicyRunnerBase(){}
|
||||
/**
|
||||
* @brief use to display policy detail
|
||||
*/
|
||||
virtual void DisplayPolicyInfo(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the robot action object by run your policy
|
||||
* @return RobotAction
|
||||
*/
|
||||
virtual RobotAction getRobotAction(const RobotBasicState&, const UserCommand&) = 0;
|
||||
|
||||
/**
|
||||
* @brief execute function when first entering policy runner
|
||||
*/
|
||||
virtual void OnEnter() = 0;
|
||||
|
||||
/**
|
||||
* @brief Set the decimation
|
||||
* @param d decimation
|
||||
*/
|
||||
virtual void SetDecimation(int d){
|
||||
decimation_ = d;
|
||||
}
|
||||
|
||||
const std::string policy_name_;
|
||||
int decimation_;
|
||||
int run_cnt_;
|
||||
Vec3f vel_delta_const_, cmd_vel_input_;
|
||||
};
|
||||
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env bash
|
||||
# 无硬件冒烟测试:拉起 roscore + invicta_hardware(骨架)+ invicta_deploy,
|
||||
# 检查话题、频率、参数是否按预期工作。需要先 catkin_make 并 source devel/setup.bash。
|
||||
#
|
||||
# source /opt/ros/noetic/setup.bash && source devel/setup.bash
|
||||
# bash src/invicta_deploy/scripts/smoke_test.sh # 或任意路径下调用本脚本
|
||||
|
||||
set -u
|
||||
WS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" # scripts -> invicta_deploy -> src -> ws
|
||||
cd "$WS_DIR" || exit 1
|
||||
|
||||
echo "=== 1. onnxruntime 动态库解析 ==="
|
||||
ldd devel/lib/invicta_deploy/invicta_deploy | grep -i onnx || echo "!! libonnxruntime.so 未解析,检查 CMakeLists 的 RPATH"
|
||||
|
||||
echo "=== 2. 启动 roscore ==="
|
||||
nohup roscore >/tmp/roscore.log 2>&1 &
|
||||
sleep 8
|
||||
|
||||
echo "=== 3. 启动 invicta_hardware(骨架:发零位状态)==="
|
||||
nohup roslaunch invicta_hardware invicta_hardware.launch >/tmp/hw.log 2>&1 &
|
||||
sleep 4
|
||||
|
||||
echo "--- 话题 ---"
|
||||
rostopic list
|
||||
|
||||
echo "--- /joint_states 频率(期望 ~200 Hz)---"
|
||||
timeout 5 rostopic hz /joint_states 2>&1 | tail -2
|
||||
|
||||
echo "--- /joint_states 样例 ---"
|
||||
timeout 5 rostopic echo -n1 /joint_states 2>&1 | sed -n '1,12p'
|
||||
|
||||
echo "--- /imu/data 样例 ---"
|
||||
timeout 5 rostopic echo -n1 /imu/data 2>&1 | sed -n '1,18p'
|
||||
|
||||
echo "=== 4. 启动 invicta_remote(协议节点)==="
|
||||
nohup roslaunch invicta_remote invicta_remote.launch >/tmp/remote.log 2>&1 &
|
||||
sleep 3
|
||||
python3 "$WS_DIR/src/invicta_remote/scripts/protocol_udp_test.py" --port 30000 --steer 0.2,0,0.1 --motion 1 >/tmp/proto_test.log 2>&1
|
||||
tail -4 /tmp/proto_test.log
|
||||
|
||||
echo "=== 5. 启动 invicta_deploy(RL 节点)==="
|
||||
nohup roslaunch invicta_deploy invicta_deploy.launch >/tmp/dep.log 2>&1 &
|
||||
sleep 8
|
||||
|
||||
echo "--- /joint_commands 频率(idle 状态期望 ~200 Hz)---"
|
||||
timeout 5 rostopic hz /joint_commands 2>&1 | tail -2
|
||||
|
||||
echo "--- 参数是否从 yaml 读到 ---"
|
||||
rosparam get /invicta_deploy/geometry/stand_height
|
||||
rosparam get /invicta_deploy/calibration/joint_dir
|
||||
|
||||
echo "--- 节点连接关系 ---"
|
||||
rosnode info /invicta_deploy 2>&1 | sed -n '1,14p'
|
||||
|
||||
echo "--- /motion_state 频率(期望 ~20 Hz)---"
|
||||
timeout 4 rostopic hz /motion_state 2>&1 | tail -2
|
||||
|
||||
echo "=== 6. 日志 ==="
|
||||
echo "--- invicta_deploy ---"
|
||||
tail -35 /tmp/dep.log
|
||||
echo "--- invicta_remote ---"
|
||||
tail -12 /tmp/remote.log
|
||||
echo "--- invicta_hardware ---"
|
||||
tail -8 /tmp/hw.log
|
||||
|
||||
pkill -f roslaunch >/dev/null 2>&1
|
||||
pkill roscore >/dev/null 2>&1
|
||||
sleep 1
|
||||
echo "=== 冒烟测试结束 ==="
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file control_parameters.h
|
||||
* @brief 机器人几何/控制参数。全部来自 ROS 参数,默认值是上游 M20 的取值
|
||||
*
|
||||
* 换成 invicta 自己的机器人时,改 config/invicta_deploy.yaml 即可,不用改代码。
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ros/ros.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common_types.h"
|
||||
#include "custom_types.h"
|
||||
|
||||
using namespace types;
|
||||
|
||||
class ControlParameters {
|
||||
public:
|
||||
explicit ControlParameters(const ros::NodeHandle& nh) { Load(nh); }
|
||||
~ControlParameters() {}
|
||||
|
||||
/// 机身尺寸 [m]
|
||||
float body_len_x_, body_len_y_;
|
||||
float hip_len_, thigh_len_, shank_len_;
|
||||
|
||||
/// 站立高度配置 [m]
|
||||
float pre_height_, stand_height_;
|
||||
|
||||
/// 单腿摆动相 PD 增益
|
||||
Vec3f swing_leg_kp_, swing_leg_kd_;
|
||||
|
||||
/// 腿关节位置限制 [rad](左前腿;右侧镜像)
|
||||
Vec3f fl_joint_lower_, fl_joint_upper_;
|
||||
|
||||
/// 关节速度限制 [rad/s]、力矩限制 [Nm]
|
||||
Vec3f joint_vel_limit_;
|
||||
Vec3f torque_limit_;
|
||||
|
||||
/// 站立/卧倒时长 [s]
|
||||
float stand_duration_ = 1.5;
|
||||
float liedown_duration_ = 2.0;
|
||||
|
||||
/// 关节阻尼时长 [s]:缓慢松下 → 机器人着地 → 转入空闲(自由)
|
||||
float joint_damping_duration_ = 3.0;
|
||||
|
||||
// ---- 站立完成后自动进入 RL(原厂机制:模型推理健康 + 姿态检查通过即切换,不等指令)----
|
||||
bool rl_auto_enter_ = true;
|
||||
float rl_enter_delay_ = 0.5f; ///< 到达站立位姿后再稳定多久 [s]
|
||||
bool rl_require_pose_ = true; ///< 是否检查关节角已到站立位姿(无硬件台架要关掉)
|
||||
float rl_joint_tolerance_ = 0.15f; ///< 关节角容差 [rad]
|
||||
float rl_velocity_tolerance_ = 1.0f; ///< 关节速度容差 [rad/s]
|
||||
bool rl_require_imu_ = true; ///< 是否检查 IMU 数据有效
|
||||
|
||||
/// 轮关节速度限制与轮半径相关长度 [m]
|
||||
float wheel_vel_limit_ = 100;
|
||||
float wheel_link_len_ = 0.040575;
|
||||
|
||||
private:
|
||||
void Load(const ros::NodeHandle& nh);
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file invicta_control_parameters.cpp
|
||||
* @brief 从 ROS 参数读取控制参数,默认值为上游 M20
|
||||
*/
|
||||
#include "parameters/control_parameters.h"
|
||||
|
||||
namespace {
|
||||
|
||||
Vec3f GetVec3(const ros::NodeHandle& nh, const std::string& key, const Vec3f& fallback) {
|
||||
std::vector<double> v;
|
||||
if (!nh.getParam(key, v) || v.size() != 3) {
|
||||
return fallback;
|
||||
}
|
||||
return Vec3f(static_cast<float>(v[0]), static_cast<float>(v[1]), static_cast<float>(v[2]));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ControlParameters::Load(const ros::NodeHandle& nh) {
|
||||
nh.param<float>("geometry/body_len_x", body_len_x_, 0.3095f * 2.f);
|
||||
nh.param<float>("geometry/body_len_y", body_len_y_, 0.065f * 2.f);
|
||||
nh.param<float>("geometry/hip_len", hip_len_, 0.104f);
|
||||
nh.param<float>("geometry/thigh_len", thigh_len_, 0.25f);
|
||||
nh.param<float>("geometry/shank_len", shank_len_, 0.25f);
|
||||
|
||||
nh.param<float>("geometry/pre_height", pre_height_, 0.12f);
|
||||
nh.param<float>("geometry/stand_height", stand_height_, 0.48f);
|
||||
|
||||
swing_leg_kp_ = GetVec3(nh, "gains/swing_leg_kp", Vec3f(200., 200., 200.));
|
||||
swing_leg_kd_ = GetVec3(nh, "gains/swing_leg_kd", Vec3f(4., 4., 4.));
|
||||
|
||||
fl_joint_lower_ = GetVec3(nh, "limits/fl_joint_lower", Vec3f(-0.4363, -2.443, -2.758));
|
||||
fl_joint_upper_ = GetVec3(nh, "limits/fl_joint_upper", Vec3f(0.6109, 2.443, 2.758));
|
||||
joint_vel_limit_ = GetVec3(nh, "limits/joint_vel_limit", Vec3f(22.4, 22.4, 22.4));
|
||||
torque_limit_ = GetVec3(nh, "limits/torque_limit", Vec3f(76.4, 76.4, 76.4));
|
||||
|
||||
nh.param<float>("timing/stand_duration", stand_duration_, 1.5f);
|
||||
nh.param<float>("timing/liedown_duration", liedown_duration_, 2.0f);
|
||||
nh.param<float>("timing/joint_damping_duration", joint_damping_duration_, 3.0f);
|
||||
if (joint_damping_duration_ < 0.1f || joint_damping_duration_ > 30.f) {
|
||||
ROS_WARN("[ControlParameters] timing/joint_damping_duration=%.2f 超出 [0.1, 30] s,回退到 3.0 s",
|
||||
joint_damping_duration_);
|
||||
joint_damping_duration_ = 3.0f;
|
||||
}
|
||||
ROS_INFO("[ControlParameters] joint_damping_duration = %.2f s", joint_damping_duration_);
|
||||
|
||||
nh.param<bool>("rl/auto_enter", rl_auto_enter_, true);
|
||||
nh.param<float>("rl/enter_delay", rl_enter_delay_, 0.5f);
|
||||
nh.param<bool>("rl/require_pose", rl_require_pose_, true);
|
||||
nh.param<float>("rl/joint_tolerance", rl_joint_tolerance_, 0.15f);
|
||||
nh.param<float>("rl/velocity_tolerance", rl_velocity_tolerance_, 1.0f);
|
||||
nh.param<bool>("rl/require_imu", rl_require_imu_, true);
|
||||
ROS_INFO("[ControlParameters] 站立后自动进 RL: %s(delay %.2f s, require_pose=%d, require_imu=%d)",
|
||||
rl_auto_enter_ ? "开" : "关", rl_enter_delay_, int(rl_require_pose_), int(rl_require_imu_));
|
||||
|
||||
nh.param<float>("limits/wheel_vel_limit", wheel_vel_limit_, 100.f);
|
||||
nh.param<float>("geometry/wheel_link_len", wheel_link_len_, 0.040575f);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @file idle_state.hpp
|
||||
* @brief 待机:确认关节/IMU 数据正常,等手柄指令
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "state_base.h"
|
||||
|
||||
namespace invicta {
|
||||
|
||||
class IdleState : public StateBase {
|
||||
private:
|
||||
int joint_normal_flag_ = -1;
|
||||
bool first_enter_flag_ = true;
|
||||
VecXf joint_pos_, joint_vel_, joint_tau_;
|
||||
Vec3f rpy_, acc_, omg_;
|
||||
double last_print_time = 0;
|
||||
|
||||
void GetProprioceptiveData() {
|
||||
joint_pos_ = ri_ptr_->GetJointPosition();
|
||||
joint_vel_ = ri_ptr_->GetJointVelocity();
|
||||
joint_tau_ = ri_ptr_->GetJointTorque();
|
||||
rpy_ = ri_ptr_->GetImuRpy();
|
||||
acc_ = ri_ptr_->GetImuAcc();
|
||||
omg_ = ri_ptr_->GetImuOmega();
|
||||
}
|
||||
|
||||
int JointDataNormalCheck() {
|
||||
VecXf joint_pos_lower(16), joint_pos_upper(16);
|
||||
Vec4f fl_lower, fl_upper;
|
||||
fl_lower << cp_ptr_->fl_joint_lower_, -INFINITY;
|
||||
fl_upper << cp_ptr_->fl_joint_upper_, INFINITY;
|
||||
Vec4f fr_lower(-fl_upper(0), fl_lower(1), fl_lower(2), -INFINITY);
|
||||
Vec4f fr_upper(-fl_lower(0), fl_upper(1), fl_upper(2), INFINITY);
|
||||
joint_pos_lower << fl_lower, fr_lower, fl_lower, fr_lower;
|
||||
joint_pos_upper << fl_upper, fr_upper, fl_upper, fr_upper;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (std::isnan(joint_pos_(i))) return 1;
|
||||
if (joint_pos_(i) > joint_pos_upper(i) + 0.2) return 2;
|
||||
if (joint_pos_(i) < joint_pos_lower(i) - 0.2) return 3;
|
||||
if (std::isnan(joint_vel_(i))) return 4;
|
||||
if (i % 4 == 3) {
|
||||
if (joint_vel_(i) > cp_ptr_->wheel_vel_limit_ + 0.1) return 5;
|
||||
} else {
|
||||
if (joint_vel_(i) > cp_ptr_->joint_vel_limit_(i % 4) + 0.1) return 6;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ImuDataNormalCheck() {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (std::isnan(rpy_(i)) || fabs(rpy_(i)) > M_PI) return 1;
|
||||
if (std::isnan(omg_(i)) || fabs(omg_(i)) > M_PI) return 2;
|
||||
}
|
||||
if (acc_.norm() < 0.1 * gravity || acc_.norm() > 3.0 * gravity) return 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PrintEigenVectorf(const VecXf& vec, int width = 6) {
|
||||
for (int i = 0; i < vec.size(); ++i) {
|
||||
std::cout << std::setw(width) << std::setprecision(3) << std::right << vec(i) << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
void DisplayProprioceptiveInfo() {
|
||||
std::cout << "Joint Data: \n";
|
||||
std::cout << "FL pos: ";
|
||||
PrintEigenVectorf(joint_pos_.segment(0, 4));
|
||||
std::cout << "FR pos: ";
|
||||
PrintEigenVectorf(joint_pos_.segment(4, 4));
|
||||
std::cout << "HL pos: ";
|
||||
PrintEigenVectorf(joint_pos_.segment(8, 4));
|
||||
std::cout << "HR pos: ";
|
||||
PrintEigenVectorf(joint_pos_.segment(12, 4));
|
||||
std::cout << "vel: ";
|
||||
PrintEigenVectorf(joint_vel_);
|
||||
std::cout << "tau: ";
|
||||
PrintEigenVectorf(joint_tau_);
|
||||
std::cout << "Imu Data: \n";
|
||||
std::cout << "rpy: " << rpy_.transpose() << std::endl;
|
||||
std::cout << "acc: " << acc_.transpose() << std::endl;
|
||||
std::cout << "omg: " << omg_.transpose() << std::endl;
|
||||
}
|
||||
|
||||
void DisplayAxisValue() {
|
||||
auto cmd = uc_ptr_->GetUserCommand();
|
||||
std::cout << "User Command Input: \n";
|
||||
std::cout << "axis value: " << cmd->forward_vel_scale << " " << cmd->side_vel_scale << " "
|
||||
<< cmd->turnning_vel_scale << std::endl;
|
||||
std::cout << "target mode: " << int(cmd->target_mode) << std::endl;
|
||||
}
|
||||
|
||||
public:
|
||||
IdleState(const std::string& state_name, std::shared_ptr<ControllerData> data_ptr)
|
||||
: StateBase(state_name, data_ptr) {}
|
||||
|
||||
~IdleState() {}
|
||||
|
||||
virtual void OnEnter() {
|
||||
StateBase::msfb_.UpdateCurrentState(RobotMotionState::WaitingForStand);
|
||||
}
|
||||
|
||||
virtual void OnExit() { first_enter_flag_ = false; }
|
||||
|
||||
virtual void Run() {
|
||||
GetProprioceptiveData();
|
||||
joint_normal_flag_ = JointDataNormalCheck();
|
||||
if (((ri_ptr_->GetInterfaceTimeStamp() - last_print_time) > 1)) {
|
||||
DisplayProprioceptiveInfo();
|
||||
DisplayAxisValue();
|
||||
last_print_time = ri_ptr_->GetInterfaceTimeStamp();
|
||||
}
|
||||
MatXf cmd = MatXf::Zero(16, 5);
|
||||
ri_ptr_->SetJointCommand(cmd);
|
||||
}
|
||||
|
||||
virtual bool LoseControlJudge() { return false; }
|
||||
|
||||
virtual StateName GetNextStateName() {
|
||||
if ((joint_normal_flag_ != 0)) {
|
||||
std::cout << "========== warning ========>> "
|
||||
<< "joint status: " << joint_normal_flag_ << std::endl;
|
||||
return StateName::kIdle;
|
||||
}
|
||||
if (uc_ptr_->GetUserCommand()->safe_control_mode != 0) {
|
||||
return StateName::kIdle;
|
||||
}
|
||||
if (uc_ptr_->GetUserCommand()->target_mode == uint8_t(RobotMotionState::StandingUp))
|
||||
return StateName::kStandUp;
|
||||
return StateName::kIdle;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace invicta
|
||||
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @file invicta_state_machine.hpp
|
||||
* @brief 状态机装配:运动指令来源(ROS 话题)+ 数据面 + 五个状态 + 安全检查 + 状态回报
|
||||
*
|
||||
* 遥控协议(UDP/JSON)已拆到 invicta_remote 节点,本节点只消费 /motion_command:
|
||||
* invicta_remote --/motion_command--> invicta_deploy --/motion_state--> invicta_remote
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ros/package.h>
|
||||
#include <ros/ros.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "hardware/invicta_interface.hpp"
|
||||
#include "motion_state_reporter.hpp"
|
||||
#include "quadruped_wheel/idle_state.hpp"
|
||||
#include "quadruped_wheel/joint_damping_state.hpp"
|
||||
#include "quadruped_wheel/liedown_state.hpp"
|
||||
#include "quadruped_wheel/rl_control_state.hpp"
|
||||
#include "quadruped_wheel/standup_state.hpp"
|
||||
#include "ros_command_interface.hpp"
|
||||
#include "state_base.h"
|
||||
#include "state_machine_base.h"
|
||||
|
||||
namespace invicta {
|
||||
|
||||
/// 关节数量,与 policy.onnx 绑定(M20 是 4 腿 × 4 关节)
|
||||
constexpr int kDofNum = 16;
|
||||
|
||||
class InvictaStateMachine : public StateMachineBase {
|
||||
private:
|
||||
std::shared_ptr<StateBase> idle_controller_;
|
||||
std::shared_ptr<StateBase> standup_controller_;
|
||||
std::shared_ptr<StateBase> rl_controller_;
|
||||
std::shared_ptr<StateBase> joint_damping_controller_;
|
||||
std::shared_ptr<StateBase> liedown_controller_;
|
||||
|
||||
std::shared_ptr<interface::MotionStateReporter> state_reporter_;
|
||||
|
||||
public:
|
||||
InvictaStateMachine() : StateMachineBase() {}
|
||||
~InvictaStateMachine() {}
|
||||
|
||||
void Start() {
|
||||
ros::NodeHandle pnh("~"); // 参数都在 ~ 下,见 config/invicta_deploy.yaml
|
||||
|
||||
pnh.param<int>("control_period_ms", control_period_ms_, 5); // 默认 200 Hz
|
||||
|
||||
std::string policy_path;
|
||||
pnh.param<std::string>("policy_path", policy_path, "");
|
||||
if (policy_path.empty()) {
|
||||
policy_path = ros::package::getPath("invicta_deploy") + "/policy/policy.onnx";
|
||||
}
|
||||
|
||||
std::string state_topic = "motion_state";
|
||||
double state_hz = 20.0;
|
||||
std::string version = "INVICTA";
|
||||
pnh.param<std::string>("topics/motion_state", state_topic, "motion_state");
|
||||
pnh.param<double>("motion_state_report_hz", state_hz, 20.0);
|
||||
pnh.param<std::string>("robot_version", version, "INVICTA");
|
||||
|
||||
std::map<std::string, std::string> gait_policy_map;
|
||||
pnh.getParam("gait/policy_map", gait_policy_map);
|
||||
int default_gait = invicta_msgs::kGaitBasic;
|
||||
pnh.param<int>("gait/default", default_gait, int(invicta_msgs::kGaitBasic));
|
||||
auto loaded_gaits = std::make_shared<std::set<int>>();
|
||||
|
||||
// ---- 指令来源:订阅 /motion_command ----
|
||||
uc_ptr_ = std::make_shared<interface::RosCommandInterface>(loaded_gaits, default_gait);
|
||||
uc_ptr_->SetMotionStateFeedback(&StateBase::msfb_);
|
||||
|
||||
// ---- 机器人数据面 + 控制参数 ----
|
||||
ri_ptr_ = std::make_shared<interface::InvictaInterface>("invicta", kDofNum);
|
||||
cp_ptr_ = std::make_shared<ControlParameters>(pnh);
|
||||
|
||||
std::shared_ptr<ControllerData> data_ptr = std::make_shared<ControllerData>();
|
||||
data_ptr->ri_ptr = ri_ptr_;
|
||||
data_ptr->uc_ptr = uc_ptr_;
|
||||
data_ptr->cp_ptr = cp_ptr_;
|
||||
|
||||
sc_ptr_ = std::make_shared<SafeController>();
|
||||
sc_ptr_->SetRobotDataSource(ri_ptr_);
|
||||
sc_ptr_->SetUserCommandDataSource(uc_ptr_);
|
||||
|
||||
idle_controller_ = std::make_shared<IdleState>("idle_state", data_ptr);
|
||||
standup_controller_ = std::make_shared<StandUpState>("standup_state", data_ptr);
|
||||
joint_damping_controller_ = std::make_shared<JointDampingState>("joint_damping", data_ptr);
|
||||
liedown_controller_ = std::make_shared<LieDownState>("liedown_state", data_ptr);
|
||||
rl_controller_ = std::make_shared<RLControlState>("rl_control", data_ptr, policy_path, gait_policy_map,
|
||||
default_gait, loaded_gaits);
|
||||
|
||||
current_controller_ = idle_controller_;
|
||||
current_state_name_ = kIdle;
|
||||
next_state_name_ = kIdle;
|
||||
|
||||
std::cout << "control period: " << control_period_ms_ << " ms, policy: " << policy_path << std::endl;
|
||||
|
||||
// ---- 状态回报(供 invicta_remote 判前提 + 将来做状态上报)----
|
||||
state_reporter_ = std::make_shared<interface::MotionStateReporter>(
|
||||
&StateBase::msfb_, uc_ptr_->GetUserCommand(), state_topic, state_hz, version);
|
||||
|
||||
ri_ptr_->Start();
|
||||
uc_ptr_->Start();
|
||||
sc_ptr_->Start();
|
||||
state_reporter_->Start();
|
||||
current_controller_->OnEnter();
|
||||
std::cout << "state report: " << state_topic << " @ " << state_hz << " Hz" << std::endl;
|
||||
}
|
||||
|
||||
std::shared_ptr<StateBase> GetStateControllerPtr(StateName state_name) {
|
||||
switch (state_name) {
|
||||
case StateName::kInvalid:
|
||||
return nullptr;
|
||||
case StateName::kIdle:
|
||||
return idle_controller_;
|
||||
case StateName::kStandUp:
|
||||
return standup_controller_;
|
||||
case StateName::kRLControl:
|
||||
return rl_controller_;
|
||||
case StateName::kJointDamping:
|
||||
return joint_damping_controller_;
|
||||
case StateName::kLieDown:
|
||||
return liedown_controller_;
|
||||
default:
|
||||
std::cerr << "error state name" << std::endl;
|
||||
return joint_damping_controller_;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
state_reporter_->Stop();
|
||||
sc_ptr_->Stop();
|
||||
uc_ptr_->Stop();
|
||||
ri_ptr_->Stop();
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace invicta
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @file joint_damping_state.hpp
|
||||
* @brief 关节阻尼(过渡态):缓慢松下 → 机器人着地 → 转入空闲(自由)
|
||||
*
|
||||
* 设计意图:这不是一个「保持」状态,而是松腿过程。只给 kd、不给位置增益,关节在重力下缓慢下沉;
|
||||
* 到时后转 Idle(Idle 输出零增益 = 完全自由)。
|
||||
*
|
||||
* 相对上游 M20 的两处改动:
|
||||
* 1. 3 s 写死 → 改为参数 timing/joint_damping_duration(0.1~30 s)
|
||||
* 2. 计时源从「关节数据时间戳」改为单调时钟:原先若关节数据断流,时间戳不前进,
|
||||
* 状态会永远停在阻尼(真机上等于松不了腿也进不了后续状态)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "state_base.h"
|
||||
|
||||
namespace invicta {
|
||||
|
||||
class JointDampingState : public StateBase {
|
||||
private:
|
||||
MatXf joint_cmd_;
|
||||
std::chrono::steady_clock::time_point start_time_;
|
||||
|
||||
public:
|
||||
JointDampingState(const std::string& state_name, std::shared_ptr<ControllerData> data_ptr)
|
||||
: StateBase(state_name, data_ptr) {
|
||||
Vec4f one_leg_kd;
|
||||
one_leg_kd << cp_ptr_->swing_leg_kd_, 1.;
|
||||
VecXf kd_ = one_leg_kd.replicate(4, 1);
|
||||
joint_cmd_ = MatXf::Zero(16, 5);
|
||||
joint_cmd_.col(2) = kd_;
|
||||
}
|
||||
~JointDampingState() {}
|
||||
|
||||
virtual void OnEnter() {
|
||||
start_time_ = std::chrono::steady_clock::now();
|
||||
std::cout << "[DAMPING] 进入关节阻尼,持续 " << cp_ptr_->joint_damping_duration_ << " s 后转入空闲"
|
||||
<< std::endl;
|
||||
msfb_.UpdateCurrentState(RobotMotionState::JointDamping);
|
||||
}
|
||||
|
||||
virtual void OnExit() {
|
||||
const double elapsed = Elapsed();
|
||||
std::cout << "[DAMPING] 结束(实际 " << elapsed << " s),转入空闲" << std::endl;
|
||||
}
|
||||
|
||||
virtual void Run() { ri_ptr_->SetJointCommand(joint_cmd_); }
|
||||
|
||||
virtual bool LoseControlJudge() { return false; }
|
||||
|
||||
virtual StateName GetNextStateName() {
|
||||
if (Elapsed() < double(cp_ptr_->joint_damping_duration_)) {
|
||||
return StateName::kJointDamping;
|
||||
}
|
||||
return StateName::kIdle;
|
||||
}
|
||||
|
||||
private:
|
||||
double Elapsed() const {
|
||||
return std::chrono::duration<double>(std::chrono::steady_clock::now() - start_time_).count();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace invicta
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @file liedown_state.hpp
|
||||
* @brief liedown state
|
||||
* @author DeepRobotics
|
||||
* @version 1.0
|
||||
* @date 2026-02-12
|
||||
*
|
||||
* @copyright Copyright (c) 2025 DeepRobotics
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "state_base.h"
|
||||
|
||||
namespace invicta {
|
||||
class LieDownState : public StateBase{
|
||||
private:
|
||||
VecXf init_joint_pos_, init_joint_vel_, current_joint_pos_, current_joint_vel_;
|
||||
double time_stamp_record_, run_time_;
|
||||
VecXf goal_joint_pos_, kp_, kd_;
|
||||
MatXf joint_cmd_;
|
||||
float liedown_duration_ = 2.;
|
||||
|
||||
const float init_hipx_pos_ = Deg2Rad(0.);
|
||||
const float set_wheel_kd_ = 1.;
|
||||
|
||||
void GetRobotJointValue(){
|
||||
current_joint_pos_ = ri_ptr_->GetJointPosition();
|
||||
current_joint_vel_ = ri_ptr_->GetJointVelocity();
|
||||
run_time_ = ri_ptr_->GetInterfaceTimeStamp();
|
||||
}
|
||||
|
||||
void RecordJointData(){
|
||||
init_joint_pos_ = current_joint_pos_;
|
||||
init_joint_vel_ = current_joint_vel_;
|
||||
time_stamp_record_ = run_time_;
|
||||
}
|
||||
|
||||
float GetHipYPosByHeight(float h){
|
||||
float l1 = cp_ptr_->thigh_len_;
|
||||
float l2 = cp_ptr_->shank_len_;
|
||||
float default_pos = (cp_ptr_->fl_joint_lower_(1)+cp_ptr_->fl_joint_upper_(1)) / 2.;
|
||||
if(fabs(h) >= l1 + l2) {
|
||||
std::cerr << "error height input" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
float theta = -acos((l1*l1+h*h-l2*l2)/(2.*h*l1));
|
||||
LimitNumber(theta, cp_ptr_->fl_joint_lower_(1), cp_ptr_->fl_joint_upper_(1));
|
||||
return theta;
|
||||
}
|
||||
|
||||
float GetKneePosByHeight(float h){
|
||||
float l1 = cp_ptr_->thigh_len_;
|
||||
float l2 = cp_ptr_->shank_len_;
|
||||
float default_pos = (cp_ptr_->fl_joint_lower_(2)+cp_ptr_->fl_joint_upper_(2)) / 2.;
|
||||
if(fabs(h) >= l1 + l2) {
|
||||
std::cerr << "error height input" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
float theta = M_PI-acos((l1*l1+l2*l2-h*h)/(2*l1*l2));
|
||||
LimitNumber(theta, cp_ptr_->fl_joint_lower_(2), cp_ptr_->fl_joint_upper_(2));
|
||||
return theta;
|
||||
}
|
||||
|
||||
public:
|
||||
LieDownState(const std::string& state_name, std::shared_ptr<ControllerData> data_ptr)
|
||||
: StateBase(state_name, data_ptr) {
|
||||
init_joint_pos_ = VecXf::Zero(16);
|
||||
init_joint_vel_ = VecXf::Zero(16);
|
||||
current_joint_pos_ = VecXf::Zero(16);
|
||||
current_joint_vel_ = VecXf::Zero(16);
|
||||
|
||||
goal_joint_pos_ = Vec4f(init_hipx_pos_, GetHipYPosByHeight(0.03), GetKneePosByHeight(0.03), 0).replicate(4, 1);
|
||||
goal_joint_pos_(4) = -init_hipx_pos_; goal_joint_pos_(12) = -init_hipx_pos_;
|
||||
|
||||
goal_joint_pos_(9) = -goal_joint_pos_(9);
|
||||
goal_joint_pos_(10) = -goal_joint_pos_(10);
|
||||
goal_joint_pos_(13) = -goal_joint_pos_(13);
|
||||
goal_joint_pos_(14) = -goal_joint_pos_(14);
|
||||
|
||||
Vec4f one_leg_kp, one_leg_kd;
|
||||
|
||||
one_leg_kp << 300, 300, 300, 0;
|
||||
one_leg_kd << 4.5, 4.5, 4.5, 3; //2; //0;
|
||||
kp_ = one_leg_kp.replicate(4, 1);
|
||||
kd_ = one_leg_kd.replicate(4, 1);
|
||||
liedown_duration_ = cp_ptr_->liedown_duration_;
|
||||
}
|
||||
~LieDownState(){}
|
||||
|
||||
virtual void OnEnter() {
|
||||
joint_cmd_ = MatXf::Zero(16, 5);
|
||||
joint_cmd_.col(0) = kp_;
|
||||
joint_cmd_.col(2) = kd_;
|
||||
GetRobotJointValue();
|
||||
RecordJointData();
|
||||
StateBase::msfb_.UpdateCurrentState(RobotMotionState::LieDown);
|
||||
};
|
||||
|
||||
virtual void OnExit() {
|
||||
}
|
||||
|
||||
virtual void Run() {
|
||||
GetRobotJointValue();
|
||||
VecXf planning_joint_pos(current_joint_pos_.rows());
|
||||
VecXf planning_joint_vel(current_joint_pos_.rows());
|
||||
if(run_time_ - time_stamp_record_ <= liedown_duration_){
|
||||
for(int i=0;i<current_joint_pos_.rows();++i){
|
||||
planning_joint_pos(i) = GetCubicSplinePos(init_joint_pos_(i), init_joint_vel_(i), goal_joint_pos_(i), 0,
|
||||
run_time_ - time_stamp_record_, liedown_duration_);
|
||||
planning_joint_vel(i) = GetCubicSplineVel(init_joint_pos_(i), init_joint_vel_(i), goal_joint_pos_(i), 0,
|
||||
run_time_ - time_stamp_record_, liedown_duration_);
|
||||
if(i%4==3){
|
||||
planning_joint_vel(i) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
joint_cmd_.col(1) = planning_joint_pos;
|
||||
joint_cmd_.col(3) = planning_joint_vel;
|
||||
joint_cmd_.col(2) = kd_;
|
||||
ri_ptr_->SetJointCommand(joint_cmd_);
|
||||
} else if (run_time_ - time_stamp_record_ <= 2.0 * liedown_duration_){
|
||||
joint_cmd_ = MatXf::Zero(16, 5);
|
||||
joint_cmd_.col(2) = kd_;
|
||||
|
||||
ri_ptr_->SetJointCommand(joint_cmd_);
|
||||
} else {
|
||||
joint_cmd_ = MatXf::Zero(16, 5);
|
||||
ri_ptr_->SetJointCommand(joint_cmd_);
|
||||
}
|
||||
}
|
||||
virtual bool LoseControlJudge() {
|
||||
if (uc_ptr_->GetUserCommand()->target_mode == uint8_t(RobotMotionState::JointDamping)) return true;
|
||||
return false;
|
||||
}
|
||||
virtual StateName GetNextStateName() {
|
||||
if(uc_ptr_->GetUserCommand()->safe_control_mode!=0){
|
||||
return StateName::kJointDamping;
|
||||
}
|
||||
|
||||
if(run_time_ - time_stamp_record_ <= 2.*liedown_duration_){
|
||||
return StateName::kLieDown;
|
||||
}else{
|
||||
if(uc_ptr_->GetUserCommand()->target_mode == uint8_t(RobotMotionState::StandingUp)){
|
||||
return StateName::kStandUp;
|
||||
}
|
||||
}
|
||||
return StateName::kLieDown;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace invicta
|
||||
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* @file rl_control_state.hpp
|
||||
* @brief RL 控制状态:200 Hz 采样观测,50 Hz 跑一次策略(decimation=4)
|
||||
*
|
||||
* 步态 = 模型:启动时把 `gait/policy_map` 里**提供了模型路径**的步态都预加载好
|
||||
* (空路径表示"未提供模型",对应的步态在 RosCommandInterface 里就会被拒绝);
|
||||
* 运行中在当前步态对应模型间切换,切换时清空该模型的 last_action,避免跨模型残留。
|
||||
*
|
||||
* 观测用双缓冲传递,避免策略线程和控制线程同时读写同一份 RobotBasicState。
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "basic_function.hpp"
|
||||
#include "invicta_msgs/motion_defs.h"
|
||||
#include "invicta_policy_runner.hpp"
|
||||
#include "policy_runner_base.hpp"
|
||||
#include "robot_interface.h"
|
||||
#include "state_base.h"
|
||||
#include "user_command_interface.h"
|
||||
|
||||
namespace invicta {
|
||||
|
||||
class RLControlState : public StateBase {
|
||||
private:
|
||||
RobotBasicState rbs_[2];
|
||||
std::atomic<int> rbs_write_index_{0};
|
||||
int getrbsReadIndex() const { return 1 - rbs_write_index_.load(std::memory_order_acquire); }
|
||||
|
||||
int state_run_cnt_ = 0;
|
||||
|
||||
// ---- 模型:默认模型 + 按步态预加载的模型 ----
|
||||
std::shared_ptr<PolicyRunnerBase> default_policy_;
|
||||
std::shared_ptr<PolicyRunnerBase> active_policy_;
|
||||
std::map<int, std::shared_ptr<PolicyRunnerBase>> gait_runners_; ///< 步态 → 已加载模型
|
||||
std::map<int, std::string> gait_paths_; ///< 步态 → 模型路径(空 = 未提供)
|
||||
int active_gait_ = -1;
|
||||
std::string loaded_policy_path_;
|
||||
int default_gait_ = invicta_msgs::kGaitBasic;
|
||||
std::shared_ptr<std::set<int>> loaded_gaits_;
|
||||
|
||||
std::thread run_policy_thread_;
|
||||
bool start_flag_ = true;
|
||||
std::atomic<bool> policy_output_bad_{false}; ///< 推理输出异常(NaN/Inf)
|
||||
|
||||
Eigen::MatrixXf acc_rot = Eigen::MatrixXf::Zero(20, 3);
|
||||
int acc_rot_count = 0;
|
||||
|
||||
void UpdateRobotObservation() {
|
||||
int write_idx = rbs_write_index_.load(std::memory_order_relaxed);
|
||||
RobotBasicState& buffer = rbs_[write_idx];
|
||||
|
||||
buffer.base_rpy = ri_ptr_->GetImuRpy();
|
||||
buffer.base_rot_mat = RpyToRm(buffer.base_rpy);
|
||||
buffer.base_omega = ri_ptr_->GetImuOmega();
|
||||
buffer.base_acc = ri_ptr_->GetImuAcc();
|
||||
buffer.joint_pos = ri_ptr_->GetJointPosition();
|
||||
buffer.joint_vel = ri_ptr_->GetJointVelocity();
|
||||
buffer.joint_tau = ri_ptr_->GetJointTorque();
|
||||
|
||||
buffer.flt_base_acc_mat.row(acc_rot_count) = buffer.base_acc.transpose();
|
||||
acc_rot_count = (acc_rot_count + 1) % 20;
|
||||
|
||||
rbs_write_index_.store(1 - write_idx, std::memory_order_release);
|
||||
}
|
||||
|
||||
/// 当前步态对应的模型;未注册则回退默认模型(正常情况下 RosCommandInterface 已拦掉未注册步态)
|
||||
std::shared_ptr<PolicyRunnerBase> PolicyForGait(uint32_t gait, bool* switched) {
|
||||
*switched = false;
|
||||
auto it = gait_runners_.find(int(gait));
|
||||
std::shared_ptr<PolicyRunnerBase> next = (it != gait_runners_.end()) ? it->second : default_policy_;
|
||||
if (next != active_policy_) *switched = true;
|
||||
return next;
|
||||
}
|
||||
|
||||
void PolicyRunner() {
|
||||
int run_cnt_record = -1;
|
||||
while (start_flag_) {
|
||||
const uint32_t gait = StateBase::msfb_.GetCurrentGait();
|
||||
if (int(gait) != active_gait_) {
|
||||
bool switched = false;
|
||||
auto next = PolicyForGait(gait, &switched);
|
||||
if (switched) {
|
||||
next->OnEnter(); // 清 last_action / run_cnt,避免跨模型残留
|
||||
std::cout << "[GAIT] 切换模型 -> " << invicta_msgs::GaitName(gait)
|
||||
<< (gait_runners_.count(int(gait)) ? "(已注册模型)" : "(默认模型)") << std::endl;
|
||||
}
|
||||
active_policy_ = next;
|
||||
active_gait_ = int(gait);
|
||||
run_cnt_record = -1;
|
||||
}
|
||||
|
||||
if (state_run_cnt_ % active_policy_->decimation_ == 0 && state_run_cnt_ != run_cnt_record) {
|
||||
auto ra = active_policy_->getRobotAction(rbs_[getrbsReadIndex()], *(uc_ptr_->GetUserCommand()));
|
||||
MatXf res = ra.ConvertToMat();
|
||||
if (!res.allFinite()) {
|
||||
policy_output_bad_ = true;
|
||||
std::cout << "[RL] 推理输出含 NaN/Inf,停止下发并转入关节阻尼" << std::endl;
|
||||
} else {
|
||||
ri_ptr_->SetJointCommand(res);
|
||||
}
|
||||
run_cnt_record = state_run_cnt_;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(100));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
RLControlState(const std::string& state_name, std::shared_ptr<ControllerData> data_ptr,
|
||||
const std::string& policy_path, const std::map<std::string, std::string>& gait_policy_map,
|
||||
int default_gait, std::shared_ptr<std::set<int>> loaded_gaits)
|
||||
: StateBase(state_name, data_ptr),
|
||||
loaded_policy_path_(policy_path),
|
||||
default_gait_(default_gait),
|
||||
loaded_gaits_(std::move(loaded_gaits)) {
|
||||
for (const auto& kv : gait_policy_map) {
|
||||
try {
|
||||
gait_paths_[std::stoi(kv.first)] = kv.second;
|
||||
} catch (const std::exception&) {
|
||||
ROS_WARN("[RLControlState] 步态表键 '%s' 不是整数,已忽略", kv.first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
default_policy_ = std::make_shared<InvictaPolicyRunner>("invicta_policy", policy_path);
|
||||
active_policy_ = default_policy_;
|
||||
std::cout << "[GAIT] 默认模型: " << policy_path << std::endl;
|
||||
|
||||
// 默认步态 = 默认模型
|
||||
if (loaded_gaits_) loaded_gaits_->insert(default_gait_);
|
||||
|
||||
// 预加载所有提供了模型路径的步态(空路径 = 未提供模型,不加载、不可切换)
|
||||
for (const auto& kv : gait_paths_) {
|
||||
if (kv.first == default_gait_) continue; // 默认步态已在上面处理
|
||||
if (kv.second.empty()) {
|
||||
std::cout << "[GAIT] 步态 " << invicta_msgs::GaitName(uint32_t(kv.first))
|
||||
<< " 未提供模型路径,该步态不可用" << std::endl;
|
||||
continue;
|
||||
}
|
||||
if (kv.second == policy_path) {
|
||||
gait_runners_[kv.first] = default_policy_;
|
||||
if (loaded_gaits_) loaded_gaits_->insert(kv.first);
|
||||
std::cout << "[GAIT] 步态 " << invicta_msgs::GaitName(uint32_t(kv.first)) << " 复用默认模型"
|
||||
<< std::endl;
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
gait_runners_[kv.first] = std::make_shared<InvictaPolicyRunner>("gait_" + std::to_string(kv.first),
|
||||
kv.second);
|
||||
if (loaded_gaits_) loaded_gaits_->insert(kv.first);
|
||||
std::cout << "[GAIT] 预加载步态 " << invicta_msgs::GaitName(uint32_t(kv.first)) << " 模型 "
|
||||
<< kv.second << std::endl;
|
||||
} catch (const std::exception& e) {
|
||||
std::cout << "[GAIT] 步态 " << invicta_msgs::GaitName(uint32_t(kv.first))
|
||||
<< " 模型加载失败(该步态将不可用):" << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
policy_output_bad_ = false;
|
||||
active_policy_->DisplayPolicyInfo();
|
||||
}
|
||||
|
||||
~RLControlState() {}
|
||||
|
||||
virtual void OnEnter() {
|
||||
policy_output_bad_ = false;
|
||||
active_gait_ = -1; // 强制按当前步态重选模型
|
||||
state_run_cnt_ = -1;
|
||||
start_flag_ = true;
|
||||
run_policy_thread_ = std::thread(std::bind(&RLControlState::PolicyRunner, this));
|
||||
active_policy_->OnEnter();
|
||||
StateBase::msfb_.UpdateCurrentState(RobotMotionState::RLControlMode);
|
||||
}
|
||||
|
||||
virtual void OnExit() {
|
||||
start_flag_ = false;
|
||||
run_policy_thread_.join();
|
||||
state_run_cnt_ = -1;
|
||||
}
|
||||
|
||||
virtual void Run() {
|
||||
UpdateRobotObservation();
|
||||
state_run_cnt_++;
|
||||
}
|
||||
|
||||
virtual bool LoseControlJudge() {
|
||||
if (policy_output_bad_) return true;
|
||||
if (uc_ptr_->GetUserCommand()->target_mode == uint8_t(RobotMotionState::JointDamping)) return true;
|
||||
return PostureUnsafeCheck();
|
||||
}
|
||||
|
||||
/// 姿态安全门限。上游 M20 里这段是注释掉的(阈值待标定),此处同样保留为空实现。
|
||||
bool PostureUnsafeCheck() { return false; }
|
||||
|
||||
virtual StateName GetNextStateName() {
|
||||
if (uc_ptr_->GetUserCommand()->safe_control_mode != 0) return StateName::kJointDamping;
|
||||
if (uc_ptr_->GetUserCommand()->target_mode == uint8_t(RobotMotionState::LieDown))
|
||||
return StateName::kLieDown;
|
||||
return StateName::kRLControl;
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace invicta
|
||||
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* @file standup_state.hpp
|
||||
* @brief from sit state to stand state
|
||||
* @author DeepRobotics
|
||||
* @version 1.0
|
||||
* @date 2025-11-07
|
||||
*
|
||||
* @copyright Copyright (c) 2025 DeepRobotics
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "state_base.h"
|
||||
|
||||
namespace invicta {
|
||||
class StandUpState : public StateBase{
|
||||
private:
|
||||
VecXf init_joint_pos_, init_joint_vel_, current_joint_pos_, current_joint_vel_;
|
||||
double time_stamp_record_, run_time_;
|
||||
VecXf goal_joint_pos_, kp_, kd_;
|
||||
MatXf joint_cmd_;
|
||||
double stand_duration_ = 2.;
|
||||
VecXf stand_pose_; ///< 站立终点位姿(用于自检)
|
||||
double last_ready_log_ = -1e9; ///< 自检未通过日志节流
|
||||
bool rl_enter_logged_ = false;
|
||||
|
||||
const float init_hipx_pos_ = Deg2Rad(0.);
|
||||
const float set_wheel_kd_ = 1.;
|
||||
|
||||
void GetRobotJointValue(){
|
||||
current_joint_pos_ = ri_ptr_->GetJointPosition();
|
||||
current_joint_vel_ = ri_ptr_->GetJointVelocity();
|
||||
run_time_ = ri_ptr_->GetInterfaceTimeStamp();
|
||||
}
|
||||
|
||||
void RecordJointData(){
|
||||
init_joint_pos_ = current_joint_pos_;
|
||||
init_joint_vel_ = current_joint_vel_;
|
||||
time_stamp_record_ = run_time_;
|
||||
}
|
||||
|
||||
float GetHipYPosByHeight(float h){
|
||||
float l1 = cp_ptr_->thigh_len_;
|
||||
float l2 = cp_ptr_->shank_len_;
|
||||
float default_pos = (cp_ptr_->fl_joint_lower_(1)+cp_ptr_->fl_joint_upper_(1)) / 2.;
|
||||
if(fabs(h) >= l1 + l2) {
|
||||
std::cerr << "error height input" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
float theta = -acos((l1*l1+h*h-l2*l2)/(2.*h*l1));
|
||||
theta = LimitNumber(theta, cp_ptr_->fl_joint_lower_(1), cp_ptr_->fl_joint_upper_(1));
|
||||
return theta;
|
||||
}
|
||||
|
||||
float GetKneePosByHeight(float h){
|
||||
float l1 = cp_ptr_->thigh_len_;
|
||||
float l2 = cp_ptr_->shank_len_;
|
||||
float default_pos = (cp_ptr_->fl_joint_lower_(2)+cp_ptr_->fl_joint_upper_(2)) / 2.;
|
||||
if(fabs(h) >= l1 + l2) {
|
||||
std::cerr << "error height input" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
float theta = M_PI-acos((l1*l1+l2*l2-h*h)/(2*l1*l2));
|
||||
theta = LimitNumber(theta, cp_ptr_->fl_joint_lower_(2), cp_ptr_->fl_joint_upper_(2));
|
||||
return theta;
|
||||
}
|
||||
|
||||
public:
|
||||
StandUpState(const std::string& state_name, std::shared_ptr<ControllerData> data_ptr)
|
||||
: StateBase(state_name, data_ptr) {
|
||||
goal_joint_pos_ = Vec4f(init_hipx_pos_, GetHipYPosByHeight(cp_ptr_->pre_height_), GetKneePosByHeight(cp_ptr_->pre_height_), 0).replicate(4, 1);
|
||||
goal_joint_pos_(4) = -init_hipx_pos_; goal_joint_pos_(12) = -init_hipx_pos_;
|
||||
// 后髋膝取反
|
||||
goal_joint_pos_(9) = -goal_joint_pos_(9);
|
||||
goal_joint_pos_(10) = -goal_joint_pos_(10);
|
||||
goal_joint_pos_(13) = -goal_joint_pos_(13);
|
||||
goal_joint_pos_(14) = -goal_joint_pos_(14);
|
||||
|
||||
Vec4f one_leg_kp, one_leg_kd;
|
||||
one_leg_kp << cp_ptr_->swing_leg_kp_, 0;
|
||||
one_leg_kd << cp_ptr_->swing_leg_kd_, 0;
|
||||
kp_ = one_leg_kp.replicate(4, 1);
|
||||
kd_ = one_leg_kd.replicate(4, 1);
|
||||
joint_cmd_ = MatXf::Zero(16, 5);
|
||||
joint_cmd_.col(0) = kp_;
|
||||
joint_cmd_.col(2) = kd_;
|
||||
stand_duration_ = cp_ptr_->stand_duration_;
|
||||
|
||||
// 站立终点位姿:与 Run() 里 else 分支的目标一致
|
||||
stand_pose_ = Vec4f(init_hipx_pos_, GetHipYPosByHeight(cp_ptr_->stand_height_),
|
||||
GetKneePosByHeight(cp_ptr_->stand_height_), 0).replicate(4, 1);
|
||||
stand_pose_(4) = -init_hipx_pos_;
|
||||
stand_pose_(12) = -init_hipx_pos_;
|
||||
stand_pose_(9) = -stand_pose_(9);
|
||||
stand_pose_(10) = -stand_pose_(10);
|
||||
stand_pose_(13) = -stand_pose_(13);
|
||||
stand_pose_(14) = -stand_pose_(14);
|
||||
}
|
||||
~StandUpState(){}
|
||||
|
||||
virtual void OnEnter() {
|
||||
GetRobotJointValue();
|
||||
RecordJointData();
|
||||
StateBase::msfb_.UpdateCurrentState(RobotMotionState::StandingUp);
|
||||
};
|
||||
virtual void OnExit() {
|
||||
}
|
||||
virtual void Run() {
|
||||
GetRobotJointValue();
|
||||
VecXf planning_joint_pos(current_joint_pos_.rows());
|
||||
VecXf planning_joint_vel(current_joint_pos_.rows());
|
||||
if(run_time_ - time_stamp_record_ <= stand_duration_){
|
||||
for(int i=0;i<current_joint_pos_.rows();++i){
|
||||
planning_joint_pos(i) = GetCubicSplinePos(init_joint_pos_(i), init_joint_vel_(i), goal_joint_pos_(i), 0,
|
||||
run_time_ - time_stamp_record_, stand_duration_);
|
||||
planning_joint_vel(i) = GetCubicSplineVel(init_joint_pos_(i), init_joint_vel_(i), goal_joint_pos_(i), 0,
|
||||
run_time_ - time_stamp_record_, stand_duration_);
|
||||
if(i%4==3){
|
||||
kd_(i) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
double new_time = run_time_ - time_stamp_record_ - stand_duration_;
|
||||
float dt = 0.001;
|
||||
float plan_height = GetCubicSplinePos(cp_ptr_->pre_height_, 0, cp_ptr_->stand_height_, 0,
|
||||
new_time, stand_duration_);
|
||||
float plan_height_next = GetCubicSplinePos(cp_ptr_->pre_height_, 0, cp_ptr_->stand_height_, 0,
|
||||
new_time+dt, stand_duration_);
|
||||
float hipy_pos = GetHipYPosByHeight(plan_height);
|
||||
float hipy_vel = (GetHipYPosByHeight(plan_height_next) - hipy_pos) / dt;
|
||||
float knee_pos = GetKneePosByHeight(plan_height);
|
||||
float knee_vel = (GetKneePosByHeight(plan_height_next) - knee_pos) / dt;
|
||||
planning_joint_pos = Vec4f(init_hipx_pos_, hipy_pos, knee_pos, 0).replicate(4, 1);
|
||||
planning_joint_pos(4) = -init_hipx_pos_; planning_joint_pos(12) = -init_hipx_pos_;
|
||||
|
||||
planning_joint_vel = Vec4f(0, hipy_vel, knee_vel, 0).replicate(4, 1);
|
||||
|
||||
// 后髋膝取反
|
||||
planning_joint_pos(9) = -planning_joint_pos(9);
|
||||
planning_joint_pos(10) = -planning_joint_pos(10);
|
||||
planning_joint_pos(13) = -planning_joint_pos(13);
|
||||
planning_joint_pos(14) = -planning_joint_pos(14);
|
||||
planning_joint_vel(9) = -planning_joint_vel(9);
|
||||
planning_joint_vel(10) = -planning_joint_vel(10);
|
||||
planning_joint_vel(13) = -planning_joint_vel(13);
|
||||
planning_joint_vel(14) = -planning_joint_vel(14);
|
||||
|
||||
for(int i=3;i<16;i+=4){
|
||||
kd_(i) = set_wheel_kd_;
|
||||
}
|
||||
}
|
||||
|
||||
joint_cmd_.col(1) = planning_joint_pos;
|
||||
joint_cmd_.col(3) = planning_joint_vel;
|
||||
joint_cmd_.col(2) = kd_;
|
||||
ri_ptr_->SetJointCommand(joint_cmd_);
|
||||
}
|
||||
/// 进入 RL 前的自检(原厂机制:站立完成后检查通过即自动进 RL,不等指令)
|
||||
bool ReadyForRl() {
|
||||
if (uc_ptr_->GetUserCommand()->safe_control_mode != 0) {
|
||||
LogNotReady("安全标志非 0");
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (std::isnan(current_joint_pos_(i)) || std::isnan(current_joint_vel_(i))) {
|
||||
LogNotReady("关节数据含 NaN");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (cp_ptr_->rl_require_pose_) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (i % 4 == 3) continue; // 轮关节不要求位姿
|
||||
if (std::fabs(current_joint_pos_(i) - stand_pose_(i)) > cp_ptr_->rl_joint_tolerance_) {
|
||||
LogNotReady("关节 " + std::to_string(i) + " 未到站立位姿");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (i % 4 == 3) continue;
|
||||
if (std::fabs(current_joint_vel_(i)) > cp_ptr_->rl_velocity_tolerance_) {
|
||||
LogNotReady("关节速度过大");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cp_ptr_->rl_require_imu_) {
|
||||
const Vec3f rpy = ri_ptr_->GetImuRpy();
|
||||
const Vec3f acc = ri_ptr_->GetImuAcc();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (std::isnan(rpy(i)) || std::isnan(acc(i))) {
|
||||
LogNotReady("IMU 数据含 NaN");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (acc.norm() < 0.1f * gravity || acc.norm() > 3.0f * gravity) {
|
||||
LogNotReady("IMU 加速度异常");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogNotReady(const std::string& why) {
|
||||
if (run_time_ - last_ready_log_ < 1.0) return;
|
||||
last_ready_log_ = run_time_;
|
||||
std::cout << "[RL] 暂不进入 RL:" << why << std::endl;
|
||||
}
|
||||
|
||||
virtual bool LoseControlJudge() {
|
||||
if(uc_ptr_->GetUserCommand()->target_mode == uint8_t(RobotMotionState::JointDamping)) return true;
|
||||
return false;
|
||||
}
|
||||
virtual StateName GetNextStateName() {
|
||||
if(uc_ptr_->GetUserCommand()->safe_control_mode!=0) return StateName::kJointDamping;
|
||||
if(run_time_ - time_stamp_record_ <= 2.*stand_duration_){
|
||||
return StateName::kStandUp;
|
||||
}else{
|
||||
if(uc_ptr_->GetUserCommand()->target_mode == uint8_t(RobotMotionState::LieDown)){
|
||||
return StateName::kLieDown;
|
||||
}
|
||||
const bool user_request = (uc_ptr_->GetUserCommand()->target_mode ==
|
||||
uint8_t(RobotMotionState::RLControlMode));
|
||||
if (cp_ptr_->rl_auto_enter_ || user_request) {
|
||||
if (run_time_ - time_stamp_record_ >= 2. * stand_duration_ + cp_ptr_->rl_enter_delay_ &&
|
||||
ReadyForRl()) {
|
||||
if (!rl_enter_logged_) {
|
||||
rl_enter_logged_ = true;
|
||||
std::cout << "[RL] 站立完成且自检通过,进入 RL 控制" << std::endl;
|
||||
}
|
||||
return StateName::kRLControl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return StateName::kStandUp;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace invicta
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file state_base.h
|
||||
* @brief 状态基类:所有状态共享同一份控制数据指针
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "basic_function.hpp"
|
||||
#include "common_types.h"
|
||||
#include "custom_types.h"
|
||||
#include "motion_state_feedback.hpp"
|
||||
#include "parameters/control_parameters.h"
|
||||
#include "robot_interface.h"
|
||||
#include "user_command_interface.h"
|
||||
|
||||
using namespace types;
|
||||
using namespace interface;
|
||||
|
||||
struct ControllerData {
|
||||
std::shared_ptr<RobotInterface> ri_ptr;
|
||||
std::shared_ptr<UserCommandInterface> uc_ptr;
|
||||
std::shared_ptr<ControlParameters> cp_ptr;
|
||||
};
|
||||
|
||||
class StateBase {
|
||||
public:
|
||||
StateBase(const std::string& state_name, std::shared_ptr<ControllerData> data_ptr)
|
||||
: state_name_(state_name), data_ptr_(data_ptr) {
|
||||
ri_ptr_ = data_ptr_->ri_ptr;
|
||||
uc_ptr_ = data_ptr_->uc_ptr;
|
||||
cp_ptr_ = data_ptr_->cp_ptr;
|
||||
std::memset(&msfb_, 0, sizeof(msfb_));
|
||||
}
|
||||
|
||||
~StateBase() {}
|
||||
|
||||
/// 进入该状态时执行一次
|
||||
virtual void OnEnter() = 0;
|
||||
|
||||
/// 离开该状态时执行一次
|
||||
virtual void OnExit() = 0;
|
||||
|
||||
/// 该状态每个控制周期执行
|
||||
virtual void Run() = 0;
|
||||
|
||||
/// 失控判断,返回 true 则切到关节阻尼
|
||||
virtual bool LoseControlJudge() = 0;
|
||||
|
||||
/// 返回希望切换到的下一个状态
|
||||
virtual StateName GetNextStateName() = 0;
|
||||
|
||||
std::string state_name_;
|
||||
|
||||
std::shared_ptr<ControllerData> data_ptr_;
|
||||
std::shared_ptr<RobotInterface> ri_ptr_;
|
||||
std::shared_ptr<UserCommandInterface> uc_ptr_;
|
||||
std::shared_ptr<ControlParameters> cp_ptr_;
|
||||
|
||||
static MotionStateFeedback msfb_;
|
||||
};
|
||||
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* @file state_machine_base.h
|
||||
* @brief 状态机框架:控制线程按固定周期跑状态,主线程跑 ROS 回调
|
||||
*
|
||||
* 与上游 M20(ROS2)的差异:
|
||||
* - rclcpp::spin / rclcpp::ok → ros::spin / ros::ok
|
||||
* - 控制周期改为参数(默认 5 ms = 200 Hz)
|
||||
* - 上游曾把 spin_some 放在 200 Hz 控制循环里,导致消息积压和时延(上游 commit 093e384),
|
||||
* 这里保持「回调由独立线程 spin、控制线程只读」的结构
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ros/ros.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "safe_controller.hpp"
|
||||
#include "state_base.h"
|
||||
|
||||
class TimeTool {
|
||||
private:
|
||||
int tfd;
|
||||
int efd;
|
||||
int fds, ret;
|
||||
uint64_t value;
|
||||
struct epoll_event ev, *evptr;
|
||||
struct itimerspec time_intv;
|
||||
|
||||
public:
|
||||
timespec system_time;
|
||||
|
||||
/// @brief 初始化定时器,周期单位 ms
|
||||
void time_init(int ms) {
|
||||
tfd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
if (tfd == -1) {
|
||||
printf("create timer fd fail \r\n");
|
||||
}
|
||||
time_intv.it_value.tv_sec = 0;
|
||||
time_intv.it_value.tv_nsec = 1000 * 1000 * ms;
|
||||
time_intv.it_interval.tv_sec = time_intv.it_value.tv_sec;
|
||||
time_intv.it_interval.tv_nsec = time_intv.it_value.tv_nsec;
|
||||
|
||||
printf("timer start, period %d ms ...\n", ms);
|
||||
timerfd_settime(tfd, 0, &time_intv, NULL);
|
||||
|
||||
efd = epoll_create1(0);
|
||||
if (efd == -1) {
|
||||
printf("create epoll fail \r\n");
|
||||
close(tfd);
|
||||
}
|
||||
|
||||
evptr = (struct epoll_event*)calloc(1, sizeof(struct epoll_event));
|
||||
if (evptr == NULL) {
|
||||
printf("epoll event calloc fail \r\n");
|
||||
close(tfd);
|
||||
close(efd);
|
||||
}
|
||||
|
||||
ev.data.fd = tfd;
|
||||
ev.events = EPOLLIN;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, tfd, &ev);
|
||||
}
|
||||
|
||||
/// @brief 等待定时中断,1 表示本周起已到
|
||||
int time_interrupt() {
|
||||
fds = epoll_wait(efd, evptr, 1, 10);
|
||||
if (evptr[0].events & EPOLLIN) {
|
||||
ret = read(evptr->data.fd, &value, sizeof(uint64_t));
|
||||
if (ret == -1) {
|
||||
printf("read return 1 -1, errno :%d \r\n", errno);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double getCurrentTime(double start_time) {
|
||||
clock_gettime(1, &system_time);
|
||||
return system_time.tv_sec + system_time.tv_nsec / 1e9 - start_time;
|
||||
}
|
||||
|
||||
double get_start_time() {
|
||||
clock_gettime(1, &system_time);
|
||||
return system_time.tv_sec + system_time.tv_nsec / 1e9;
|
||||
}
|
||||
};
|
||||
|
||||
class StateMachineBase {
|
||||
public:
|
||||
StateMachineBase() {}
|
||||
virtual ~StateMachineBase() {}
|
||||
|
||||
virtual void Start() = 0;
|
||||
|
||||
virtual void Run() {
|
||||
run_thread_ = std::thread(&StateMachineBase::RunThread, this);
|
||||
ros::spin();
|
||||
|
||||
if (run_thread_.joinable()) run_thread_.join();
|
||||
}
|
||||
|
||||
virtual void RunThread() {
|
||||
set_timer.time_init(control_period_ms_);
|
||||
startTime = set_timer.get_start_time();
|
||||
|
||||
while (ros::ok()) {
|
||||
if (set_timer.time_interrupt()) {
|
||||
ri_ptr_->RefreshRobotData();
|
||||
|
||||
current_controller_->Run();
|
||||
|
||||
if (current_controller_->LoseControlJudge()) {
|
||||
next_state_name_ = StateName::kJointDamping;
|
||||
} else {
|
||||
next_state_name_ = current_controller_->GetNextStateName();
|
||||
}
|
||||
|
||||
if (next_state_name_ != current_state_name_) {
|
||||
current_controller_->OnExit();
|
||||
std::cout << current_controller_->state_name_ << " ------------> ";
|
||||
current_controller_ = GetStateControllerPtr(next_state_name_);
|
||||
std::cout << current_controller_->state_name_ << std::endl;
|
||||
current_controller_->OnEnter();
|
||||
current_state_name_ = next_state_name_;
|
||||
}
|
||||
++run_cnt_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Stop() = 0;
|
||||
|
||||
virtual std::shared_ptr<StateBase> GetStateControllerPtr(StateName state_name) = 0;
|
||||
|
||||
int run_cnt_ = 0;
|
||||
double startTime = 0.;
|
||||
/// 控制周期 [ms],默认 5 ms = 200 Hz,与 policy 的 decimation=4(50 Hz)配套
|
||||
int control_period_ms_ = 5;
|
||||
TimeTool set_timer{};
|
||||
|
||||
std::shared_ptr<UserCommandInterface> uc_ptr_;
|
||||
std::shared_ptr<RobotInterface> ri_ptr_;
|
||||
std::shared_ptr<ControlParameters> cp_ptr_;
|
||||
std::shared_ptr<SafeController> sc_ptr_;
|
||||
|
||||
std::shared_ptr<StateBase> current_controller_;
|
||||
StateName current_state_name_, next_state_name_;
|
||||
|
||||
std::thread run_thread_;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 120
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 120
|
||||
StatementMacros:
|
||||
- EIGEN_STATIC_ASSERT
|
||||
- EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED
|
||||
- EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN
|
||||
SortIncludes: false
|
||||
AttributeMacros:
|
||||
- EIGEN_STRONG_INLINE
|
||||
- EIGEN_ALWAYS_INLINE
|
||||
- EIGEN_DEVICE_FUNC
|
||||
- EIGEN_DONT_INLINE
|
||||
- EIGEN_DEPRECATED
|
||||
- EIGEN_UNUSED
|
||||
@@ -0,0 +1,4 @@
|
||||
# First major clang-format MR (https://gitlab.com/libeigen/eigen/-/merge_requests/1429).
|
||||
f38e16c193d489c278c189bc06b448a94adb45fb
|
||||
# Formatting of tests, examples, benchmarks, et cetera (https://gitlab.com/libeigen/eigen/-/merge_requests/1432).
|
||||
46e9cdb7fea25d7f7aef4332b9c3ead3857e213d
|
||||
@@ -0,0 +1,3 @@
|
||||
*.sh eol=lf
|
||||
debug/msvc/*.dat eol=crlf
|
||||
debug/msvc/*.natvis eol=crlf
|
||||
@@ -0,0 +1,41 @@
|
||||
qrc_*cxx
|
||||
*.orig
|
||||
*.pyc
|
||||
*.diff
|
||||
diff
|
||||
*.save
|
||||
save
|
||||
*.old
|
||||
*.gmo
|
||||
*.qm
|
||||
core
|
||||
core.*
|
||||
*.bak
|
||||
*~
|
||||
*.build*
|
||||
*.moc.*
|
||||
*.moc
|
||||
ui_*
|
||||
CMakeCache.txt
|
||||
tags
|
||||
.*.swp
|
||||
activity.png
|
||||
*.out
|
||||
*.php*
|
||||
*.log
|
||||
*.orig
|
||||
*.rej
|
||||
log
|
||||
patch
|
||||
*.patch
|
||||
a
|
||||
a.*
|
||||
lapack/testing
|
||||
lapack/reference
|
||||
.*project
|
||||
.settings
|
||||
Makefile
|
||||
!ci/build.gitlab-ci.yml
|
||||
!scripts/buildtests.in
|
||||
!Eigen/Core
|
||||
!Eigen/src/Core
|
||||
@@ -0,0 +1,34 @@
|
||||
# This file is part of Eigen, a lightweight C++ template library
|
||||
# for linear algebra.
|
||||
#
|
||||
# Copyright (C) 2023, The Eigen Authors
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla
|
||||
# Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
# with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
stages:
|
||||
- checkformat
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
# CMake build directory.
|
||||
EIGEN_CI_BUILDDIR: .build
|
||||
# Specify the CMake build target.
|
||||
EIGEN_CI_BUILD_TARGET: ""
|
||||
# If a test regex is specified, that will be selected.
|
||||
# Otherwise, we will try a label if specified.
|
||||
EIGEN_CI_CTEST_REGEX: ""
|
||||
EIGEN_CI_CTEST_LABEL: ""
|
||||
EIGEN_CI_CTEST_ARGS: ""
|
||||
|
||||
include:
|
||||
- "/ci/checkformat.gitlab-ci.yml"
|
||||
- "/ci/common.gitlab-ci.yml"
|
||||
- "/ci/build.linux.gitlab-ci.yml"
|
||||
- "/ci/build.windows.gitlab-ci.yml"
|
||||
- "/ci/test.linux.gitlab-ci.yml"
|
||||
- "/ci/test.windows.gitlab-ci.yml"
|
||||
- "/ci/deploy.gitlab-ci.yml"
|
||||
@@ -0,0 +1,69 @@
|
||||
<!--
|
||||
Please read this!
|
||||
|
||||
Before opening a new issue, make sure to search for keywords in the issues
|
||||
filtered by "bug::confirmed" or "bug::unconfirmed" and "bugzilla" label:
|
||||
|
||||
- https://gitlab.com/libeigen/eigen/-/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=bug%3A%3Aconfirmed
|
||||
- https://gitlab.com/libeigen/eigen/-/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=bug%3A%3Aunconfirmed
|
||||
- https://gitlab.com/libeigen/eigen/-/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=bugzilla
|
||||
|
||||
and verify the issue you're about to submit isn't a duplicate. -->
|
||||
|
||||
### Summary
|
||||
<!-- Summarize the bug encountered concisely. -->
|
||||
|
||||
### Environment
|
||||
<!-- Please provide your development environment here -->
|
||||
- **Operating System** : Windows/Linux
|
||||
- **Architecture** : x64/Arm64/PowerPC ...
|
||||
- **Eigen Version** : 3.3.9
|
||||
- **Compiler Version** : Gcc7.0
|
||||
- **Compile Flags** : -O3 -march=native
|
||||
- **Vector Extension** : SSE/AVX/NEON ...
|
||||
|
||||
### Minimal Example
|
||||
<!-- If possible, please create a minimal example here that exhibits the problematic behavior.
|
||||
You can also link to [godbolt](https://godbolt.org). But please note that you need to click
|
||||
the "Share" button in the top right-hand corner of the godbolt page where you reproduce the sample
|
||||
code to get the share link instead of in your browser address bar.
|
||||
|
||||
You can read [the guidelines on stackoverflow](https://stackoverflow.com/help/minimal-reproducible-example)
|
||||
on how to create a good minimal example. -->
|
||||
|
||||
```cpp
|
||||
//show your code here
|
||||
```
|
||||
|
||||
### Steps to reproduce
|
||||
<!-- Describe how one can reproduce the issue - this is very important. Please use an ordered list. -->
|
||||
|
||||
1. first step
|
||||
2. second step
|
||||
3. ...
|
||||
|
||||
### What is the current *bug* behavior?
|
||||
<!-- Describe what actually happens. -->
|
||||
|
||||
### What is the expected *correct* behavior?
|
||||
<!-- Describe what you should see instead. -->
|
||||
|
||||
### Relevant logs
|
||||
<!-- Add relevant code snippets or program output within blocks marked by " ``` " -->
|
||||
|
||||
<!-- OPTIONAL: remove this section if you are not reporting a compilation warning issue.-->
|
||||
### Warning Messages
|
||||
<!-- Show us the warning messages you got! -->
|
||||
|
||||
<!-- OPTIONAL: remove this section if you are not reporting a performance issue. -->
|
||||
### Benchmark scripts and results
|
||||
<!-- Please share any benchmark scripts - either standalone, or using [Google Benchmark](https://github.com/google/benchmark). -->
|
||||
|
||||
### Anything else that might help
|
||||
<!-- It will be better to provide us more information to help narrow down the cause.
|
||||
Including but not limited to the following:
|
||||
- lines of code that might help us diagnose the problem.
|
||||
- potential ways to address the issue.
|
||||
- last known working/first broken version (release number or commit hash). -->
|
||||
|
||||
- [ ] Have a plan to fix this issue.
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
### Describe the feature you would like to be implemented.
|
||||
|
||||
### Would such a feature be useful for other users? Why?
|
||||
|
||||
### Any hints on how to implement the requested feature?
|
||||
|
||||
### Additional resources
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Thanks for contributing a merge request! Please name and fully describe your MR as you would for a commit message.
|
||||
If the MR fixes an issue, please include "Fixes #issue" in the commit message and the MR description.
|
||||
|
||||
In addition, we recommend that first-time contributors read our [contribution guidelines](https://eigen.tuxfamily.org/index.php?title=Contributing_to_Eigen) and [git page](https://eigen.tuxfamily.org/index.php?title=Git), which will help you submit a more standardized MR.
|
||||
|
||||
Before submitting the MR, you also need to complete the following checks:
|
||||
- Make one PR per feature/bugfix (don't mix multiple changes into one PR). Avoid committing unrelated changes.
|
||||
- Rebase before committing
|
||||
- For code changes, run the test suite (at least the tests that are likely affected by the change).
|
||||
See our [test guidelines](https://eigen.tuxfamily.org/index.php?title=Tests).
|
||||
- If possible, add a test (both for bug-fixes as well as new features)
|
||||
- Make sure new features are documented
|
||||
|
||||
Note that we are a team of volunteers; we appreciate your patience during the review process.
|
||||
|
||||
Again, thanks for contributing! -->
|
||||
|
||||
### Reference issue
|
||||
<!-- You can link to a specific issue using the gitlab syntax #<issue number> -->
|
||||
|
||||
### What does this implement/fix?
|
||||
<!--Please explain your changes.-->
|
||||
|
||||
### Additional information
|
||||
<!--Any additional information you think is important.-->
|
||||
+1905
File diff suppressed because it is too large
Load Diff
+806
@@ -0,0 +1,806 @@
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
|
||||
#==============================================================================
|
||||
# CMake Policy issues.
|
||||
#==============================================================================
|
||||
# Allow overriding options in a parent project via `set` before including Eigen.
|
||||
if (POLICY CMP0077)
|
||||
cmake_policy (SET CMP0077 NEW)
|
||||
endif (POLICY CMP0077)
|
||||
|
||||
# NOTE Remove setting the policy once the minimum required CMake version is
|
||||
# increased to at least 3.15. Retain enabling the export to package registry.
|
||||
if (POLICY CMP0090)
|
||||
# The export command does not populate package registry by default
|
||||
cmake_policy (SET CMP0090 NEW)
|
||||
# Unless otherwise specified, always export to package registry to ensure
|
||||
# backwards compatibility.
|
||||
if (NOT DEFINED CMAKE_EXPORT_PACKAGE_REGISTRY)
|
||||
set (CMAKE_EXPORT_PACKAGE_REGISTRY ON)
|
||||
endif (NOT DEFINED CMAKE_EXPORT_PACKAGE_REGISTRY)
|
||||
endif (POLICY CMP0090)
|
||||
|
||||
# Disable warning about find_package(CUDA).
|
||||
# CUDA language support is lacking for clang as the CUDA compiler
|
||||
# until at least cmake version 3.18. Even then, there seems to be
|
||||
# issues on Windows+Ninja in passing build flags. Continue using
|
||||
# the "old" way for now.
|
||||
if (POLICY CMP0146)
|
||||
cmake_policy(SET CMP0146 OLD)
|
||||
endif ()
|
||||
|
||||
# Normalize DESTINATION paths
|
||||
if (POLICY CMP0177)
|
||||
cmake_policy(SET CMP0177 NEW)
|
||||
endif ()
|
||||
|
||||
#==============================================================================
|
||||
# CMake Project.
|
||||
#==============================================================================
|
||||
|
||||
project(Eigen3)
|
||||
|
||||
# Remove this block after bumping CMake to v3.21.0
|
||||
# PROJECT_IS_TOP_LEVEL is defined then by default
|
||||
if(CMAKE_VERSION VERSION_LESS 3.21.0)
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
set(PROJECT_IS_TOP_LEVEL ON)
|
||||
else()
|
||||
set(PROJECT_IS_TOP_LEVEL OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#==============================================================================
|
||||
# Build ON/OFF Settings.
|
||||
#==============================================================================
|
||||
# Determine if we should build tests.
|
||||
include(CMakeDependentOption)
|
||||
cmake_dependent_option(BUILD_TESTING "Enable creation of tests." ON "PROJECT_IS_TOP_LEVEL" OFF)
|
||||
option(EIGEN_BUILD_TESTING "Enable creation of Eigen tests." ${BUILD_TESTING})
|
||||
option(EIGEN_LEAVE_TEST_IN_ALL_TARGET "Leaves tests in the all target, needed by ctest for automatic building." OFF)
|
||||
|
||||
# Determine if we should build BLAS/LAPACK implementations.
|
||||
option(EIGEN_BUILD_BLAS "Toggles the building of the Eigen Blas library" ${PROJECT_IS_TOP_LEVEL})
|
||||
option(EIGEN_BUILD_LAPACK "Toggles the building of the included Eigen LAPACK library" ${PROJECT_IS_TOP_LEVEL})
|
||||
if (EIGEN_BUILD_BLAS OR EIGEN_BUILD_LAPACK)
|
||||
# BLAS and LAPACK currently need a fortran compiler.
|
||||
include(CMakeDetermineFortranCompiler)
|
||||
if (NOT CMAKE_Fortran_COMPILER)
|
||||
set(EIGEN_BUILD_BLAS OFF)
|
||||
set(EIGEN_BUILD_LAPACK OFF)
|
||||
else()
|
||||
# Determine if we should build shared libraries for BLAS/LAPACK on this platform.
|
||||
get_cmake_property(EIGEN_BUILD_SHARED_LIBS TARGET_SUPPORTS_SHARED_LIBS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(EIGEN_BUILD_BTL "Build benchmark suite" OFF)
|
||||
option(EIGEN_BUILD_SPBENCH "Build sparse benchmark suite" OFF)
|
||||
# Avoid building docs if included from another project.
|
||||
# Building documentation requires creating and running executables on the host
|
||||
# platform. We shouldn't do this if cross-compiling.
|
||||
if (PROJECT_IS_TOP_LEVEL AND NOT CMAKE_CROSSCOMPILING)
|
||||
set(EIGEN_BUILD_DOC_DEFAULT ON)
|
||||
endif()
|
||||
option(EIGEN_BUILD_DOC "Enable creation of Eigen documentation" ${EIGEN_BUILD_DOC_DEFAULT})
|
||||
|
||||
option(EIGEN_BUILD_DEMOS "Toggles the building of the Eigen demos" ${PROJECT_IS_TOP_LEVEL})
|
||||
|
||||
# Disable pkgconfig only for native Windows builds
|
||||
if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
option(EIGEN_BUILD_PKGCONFIG "Build pkg-config .pc file for Eigen" ${PROJECT_IS_TOP_LEVEL})
|
||||
endif()
|
||||
option(EIGEN_BUILD_CMAKE_PACKAGE "Enables the creation of EigenConfig.cmake and related files" ${PROJECT_IS_TOP_LEVEL})
|
||||
|
||||
if (EIGEN_BUILD_TESTING OR EIGEN_BUILD_BLAS OR EIGEN_BUILD_LAPACK OR EIGEN_BUILT_BTL OR EIGEN_BUILD_BTL OR EIGEN_BUILD_SPBENCH OR EIGEN_BUILD_DOC OR EIGEN_BUILD_DEMOS)
|
||||
set(EIGEN_IS_BUILDING_ ON)
|
||||
endif()
|
||||
|
||||
#==============================================================================
|
||||
# Version Info.
|
||||
#==============================================================================
|
||||
|
||||
# If version information is not provided, automatically parse the version number
|
||||
# from header files.
|
||||
file(READ "${PROJECT_SOURCE_DIR}/Eigen/Version" _eigen_version_header)
|
||||
if (NOT DEFINED EIGEN_WORLD_VERSION)
|
||||
string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen_world_version_match "${_eigen_version_header}")
|
||||
set(EIGEN_WORLD_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
if (NOT DEFINED EIGEN_MAJOR_VERSION)
|
||||
string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen_major_version_match "${_eigen_version_header}")
|
||||
set(EIGEN_MAJOR_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
if (NOT DEFINED EIGEN_MINOR_VERSION)
|
||||
string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen_minor_version_match "${_eigen_version_header}")
|
||||
set(EIGEN_MINOR_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
if (NOT DEFINED EIGEN_PATCH_VERSION)
|
||||
string(REGEX MATCH "define[ \t]+EIGEN_PATCH_VERSION[ \t]+([0-9]+)" _eigen_patch_version_match "${_eigen_version_header}")
|
||||
set(EIGEN_PATCH_VERSION "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
if (NOT DEFINED EIGEN_PRERELEASE_VERSION)
|
||||
set(EIGEN_PRERELEASE_VERSION "dev")
|
||||
endif()
|
||||
|
||||
# If we are in a git repo, extract a changeset.
|
||||
if(IS_DIRECTORY ${CMAKE_SOURCE_DIR}/.git)
|
||||
# if the git program is absent or this will leave the EIGEN_GIT_REVNUM string empty,
|
||||
# but won't stop CMake.
|
||||
execute_process(COMMAND git ls-remote -q ${CMAKE_SOURCE_DIR} HEAD OUTPUT_VARIABLE EIGEN_GIT_OUTPUT)
|
||||
endif()
|
||||
|
||||
# extract the git rev number from the git output...
|
||||
if(EIGEN_GIT_OUTPUT)
|
||||
string(REGEX MATCH "^([0-9;a-f]+).*" EIGEN_GIT_CHANGESET_MATCH "${EIGEN_GIT_OUTPUT}")
|
||||
set(EIGEN_GIT_REVNUM "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED EIGEN_BUILD_VERSION AND DEFINED EIGEN_GIT_REVNUM)
|
||||
string(SUBSTRING "${EIGEN_GIT_REVNUM}" 0 8 EIGEN_BUILD_VERSION)
|
||||
else()
|
||||
set(EIGEN_BUILD_VERSION "")
|
||||
endif()
|
||||
|
||||
# The EIGEN_VERSION_NUMBER must be of the form <major.minor.patch>.
|
||||
# The EIGEN_VERSION_STRING can contain the preprelease/build strings.
|
||||
set(EIGEN_VERSION_NUMBER "${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION}.${EIGEN_PATCH_VERSION}")
|
||||
set(EIGEN_VERSION_STRING "${EIGEN_VERSION_NUMBER}")
|
||||
if (NOT "x${EIGEN_PRERELEASE_VERSION}" STREQUAL "x")
|
||||
set(EIGEN_VERSION_STRING "${EIGEN_VERSION_STRING}-${EIGEN_PRERELEASE_VERSION}")
|
||||
endif()
|
||||
if (NOT "x${EIGEN_BUILD_VERSION}" STREQUAL "x")
|
||||
set(EIGEN_VERSION_STRING "${EIGEN_VERSION_STRING}+${EIGEN_BUILD_VERSION}")
|
||||
endif()
|
||||
|
||||
|
||||
# Generate version file.
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/Version.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include/Eigen/Version")
|
||||
|
||||
#==============================================================================
|
||||
# Install Path Configuration.
|
||||
#==============================================================================
|
||||
|
||||
# Unconditionally allow install of targets to support nested dependency
|
||||
# installations.
|
||||
#
|
||||
# Note: projects that depend on Eigen should _probably_ exclude installing
|
||||
# Eigen by default (e.g. by using EXCLUDE_FROM_ALL when using
|
||||
# FetchContent_Declare or add_subdirectory) to avoid overwriting a previous
|
||||
# installation.
|
||||
|
||||
include(GNUInstallDirs)
|
||||
# Backward compatibility support for EIGEN_INCLUDE_INSTALL_DIR
|
||||
if(EIGEN_INCLUDE_INSTALL_DIR)
|
||||
message(WARNING "EIGEN_INCLUDE_INSTALL_DIR is deprecated. Use INCLUDE_INSTALL_DIR instead.")
|
||||
endif()
|
||||
|
||||
if(EIGEN_INCLUDE_INSTALL_DIR AND NOT INCLUDE_INSTALL_DIR)
|
||||
set(INCLUDE_INSTALL_DIR ${EIGEN_INCLUDE_INSTALL_DIR}
|
||||
CACHE PATH "The directory relative to CMAKE_INSTALL_PREFIX where Eigen header files are installed")
|
||||
else()
|
||||
set(INCLUDE_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_INCLUDEDIR}/eigen3"
|
||||
CACHE PATH "The directory relative to CMAKE_INSTALL_PREFIX where Eigen header files are installed"
|
||||
)
|
||||
endif()
|
||||
set(CMAKEPACKAGE_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_DATADIR}/eigen3/cmake"
|
||||
CACHE PATH "The directory relative to CMAKE_INSTALL_PREFIX where Eigen3Config.cmake is installed"
|
||||
)
|
||||
set(PKGCONFIG_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_DATADIR}/pkgconfig"
|
||||
CACHE PATH "The directory relative to CMAKE_INSTALL_PREFIX where eigen3.pc is installed"
|
||||
)
|
||||
|
||||
foreach(var INCLUDE_INSTALL_DIR CMAKEPACKAGE_INSTALL_DIR PKGCONFIG_INSTALL_DIR)
|
||||
# If an absolute path is specified, make it relative to "{CMAKE_INSTALL_PREFIX}".
|
||||
if(IS_ABSOLUTE "${${var}}")
|
||||
file(RELATIVE_PATH "${var}" "${CMAKE_INSTALL_PREFIX}" "${${var}}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
#==============================================================================
|
||||
# Eigen Library.
|
||||
#==============================================================================
|
||||
|
||||
# Alias Eigen_*_DIR to Eigen3_*_DIR:
|
||||
set(Eigen_SOURCE_DIR ${Eigen3_SOURCE_DIR})
|
||||
set(Eigen_BINARY_DIR ${Eigen3_BINARY_DIR})
|
||||
|
||||
# Imported target support
|
||||
add_library (eigen INTERFACE)
|
||||
add_library (Eigen3::Eigen ALIAS eigen)
|
||||
target_include_directories (eigen INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>
|
||||
)
|
||||
|
||||
# Eigen requires at least C++14
|
||||
target_compile_features (eigen INTERFACE cxx_std_14)
|
||||
|
||||
# Export as title case Eigen
|
||||
set_target_properties (eigen PROPERTIES EXPORT_NAME Eigen)
|
||||
|
||||
#==============================================================================
|
||||
# Install Rule Configuration.
|
||||
#==============================================================================
|
||||
|
||||
install(FILES
|
||||
signature_of_eigen3_matrix_library
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel
|
||||
)
|
||||
|
||||
if(EIGEN_BUILD_PKGCONFIG)
|
||||
configure_file(eigen3.pc.in eigen3.pc @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/eigen3.pc
|
||||
DESTINATION ${PKGCONFIG_INSTALL_DIR})
|
||||
endif()
|
||||
|
||||
install(DIRECTORY Eigen DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel)
|
||||
# Replace the "Version" header file with the generated one.
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/Eigen/Version
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/ COMPONENT Devel)
|
||||
|
||||
install(TARGETS eigen EXPORT Eigen3Targets)
|
||||
|
||||
if(EIGEN_BUILD_CMAKE_PACKAGE)
|
||||
include (CMakePackageConfigHelpers)
|
||||
configure_package_config_file (
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Eigen3Config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake
|
||||
INSTALL_DESTINATION ${CMAKEPACKAGE_INSTALL_DIR}
|
||||
NO_SET_AND_CHECK_MACRO # Eigen does not provide legacy style defines
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO # Eigen does not provide components
|
||||
)
|
||||
|
||||
set(CVF_VERSION "${EIGEN_VERSION_NUMBER}")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/Eigen3ConfigVersion.cmake.in"
|
||||
"Eigen3ConfigVersion.cmake"
|
||||
@ONLY)
|
||||
|
||||
# The Eigen target will be located in the Eigen3 namespace. Other CMake
|
||||
# targets can refer to it using Eigen3::Eigen.
|
||||
export (TARGETS eigen NAMESPACE Eigen3:: FILE Eigen3Targets.cmake)
|
||||
# Export Eigen3 package to CMake registry such that it can be easily found by
|
||||
# CMake even if it has not been installed to a standard directory.
|
||||
export (PACKAGE Eigen3)
|
||||
|
||||
install (EXPORT Eigen3Targets NAMESPACE Eigen3:: DESTINATION ${CMAKEPACKAGE_INSTALL_DIR})
|
||||
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Eigen3ConfigVersion.cmake
|
||||
DESTINATION ${CMAKEPACKAGE_INSTALL_DIR})
|
||||
|
||||
# Add uninstall target
|
||||
if(NOT TARGET uninstall AND PROJECT_IS_TOP_LEVEL)
|
||||
add_custom_target ( uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/EigenUninstall.cmake)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#==============================================================================
|
||||
# General Build Configuration.
|
||||
#==============================================================================
|
||||
|
||||
# Avoid setting the standard in a parent if unset.
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
set(CMAKE_CXX_STANDARD 14 CACHE STRING "Default C++ standard")
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "Require C++ standard")
|
||||
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Allow C++ extensions")
|
||||
endif()
|
||||
|
||||
# Guard against in-source builds
|
||||
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ")
|
||||
endif()
|
||||
|
||||
# Guard against bad build-type strings
|
||||
if (PROJECT_IS_TOP_LEVEL AND NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
|
||||
# Only try to figure out how to link the math library if we are building something.
|
||||
# Otherwise, let the parent project deal with dependencies.
|
||||
if (EIGEN_IS_BUILDING_)
|
||||
# Use Eigen's cmake files.
|
||||
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR OFF)
|
||||
|
||||
find_package(StandardMathLibrary)
|
||||
set(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO "")
|
||||
if(NOT STANDARD_MATH_LIBRARY_FOUND)
|
||||
message(FATAL_ERROR
|
||||
"Can't link to the standard math library. Please report to the Eigen developers, telling them about your platform.")
|
||||
else()
|
||||
if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
|
||||
set(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO "${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO} ${STANDARD_MATH_LIBRARY}")
|
||||
else()
|
||||
set(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO "${STANDARD_MATH_LIBRARY}")
|
||||
endif()
|
||||
endif()
|
||||
if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO)
|
||||
message(STATUS "Standard libraries to link to explicitly: ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO}")
|
||||
else()
|
||||
message(STATUS "Standard libraries to link to explicitly: none")
|
||||
endif()
|
||||
|
||||
# Default tests/examples/libraries to row-major.
|
||||
option(EIGEN_DEFAULT_TO_ROW_MAJOR "Use row-major as default matrix storage order" OFF)
|
||||
if(EIGEN_DEFAULT_TO_ROW_MAJOR)
|
||||
add_definitions("-DEIGEN_DEFAULT_TO_ROW_MAJOR")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#==============================================================================
|
||||
# Test Configuration.
|
||||
#==============================================================================
|
||||
|
||||
if (EIGEN_BUILD_TESTING)
|
||||
function(ei_maybe_separate_arguments variable mode args)
|
||||
# Use separate_arguments if the input is a single string containing a space.
|
||||
# Otherwise, if it is already a list or doesn't have a space, just propagate
|
||||
# the original value. This is to better support multi-argument lists.
|
||||
list(LENGTH args list_length)
|
||||
if (${list_length} EQUAL 1)
|
||||
string(FIND "${args}" " " has_space)
|
||||
if (${has_space} GREATER -1)
|
||||
separate_arguments(args ${mode} "${args}")
|
||||
endif()
|
||||
endif()
|
||||
set(${variable} ${args} PARENT_SCOPE)
|
||||
endfunction(ei_maybe_separate_arguments)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
macro(ei_add_cxx_compiler_flag FLAG)
|
||||
string(REGEX REPLACE "-" "" SFLAG1 ${FLAG})
|
||||
string(REGEX REPLACE "\\+" "p" SFLAG ${SFLAG1})
|
||||
check_cxx_compiler_flag(${FLAG} COMPILER_SUPPORT_${SFLAG})
|
||||
if(COMPILER_SUPPORT_${SFLAG})
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
set(EIGEN_TEST_CUSTOM_LINKER_FLAGS "" CACHE STRING "Additional linker flags when linking unit tests.")
|
||||
set(EIGEN_TEST_CUSTOM_CXX_FLAGS "" CACHE STRING "Additional compiler flags when compiling unit tests.")
|
||||
# Convert space-separated arguments into CMake lists for downstream consumption.
|
||||
ei_maybe_separate_arguments(EIGEN_TEST_CUSTOM_LINKER_FLAGS NATIVE_COMMAND "${EIGEN_TEST_CUSTOM_LINKER_FLAGS}")
|
||||
ei_maybe_separate_arguments(EIGEN_TEST_CUSTOM_CXX_FLAGS NATIVE_COMMAND "${EIGEN_TEST_CUSTOM_CXX_FLAGS}")
|
||||
|
||||
option(EIGEN_SPLIT_LARGE_TESTS "Split large tests into smaller executables" ON)
|
||||
set(EIGEN_TEST_MAX_SIZE "320" CACHE STRING "Maximal matrix/vector size, default is 320")
|
||||
|
||||
# Flags for tests.
|
||||
if(NOT MSVC)
|
||||
# We assume that other compilers are partly compatible with GNUCC
|
||||
|
||||
# clang outputs some warnings for unknown flags that are not caught by check_cxx_compiler_flag
|
||||
# adding -Werror turns such warnings into errors
|
||||
check_cxx_compiler_flag("-Werror" COMPILER_SUPPORT_WERROR)
|
||||
if(COMPILER_SUPPORT_WERROR)
|
||||
set(CMAKE_REQUIRED_FLAGS "-Werror")
|
||||
endif()
|
||||
ei_add_cxx_compiler_flag("-pedantic")
|
||||
ei_add_cxx_compiler_flag("-Wall")
|
||||
ei_add_cxx_compiler_flag("-Wextra")
|
||||
# ei_add_cxx_compiler_flag("-Weverything") # clang
|
||||
ei_add_cxx_compiler_flag("-Wundef")
|
||||
ei_add_cxx_compiler_flag("-Wcast-align")
|
||||
ei_add_cxx_compiler_flag("-Wchar-subscripts")
|
||||
ei_add_cxx_compiler_flag("-Wnon-virtual-dtor")
|
||||
ei_add_cxx_compiler_flag("-Wunused-local-typedefs")
|
||||
ei_add_cxx_compiler_flag("-Wpointer-arith")
|
||||
ei_add_cxx_compiler_flag("-Wwrite-strings")
|
||||
ei_add_cxx_compiler_flag("-Wformat-security")
|
||||
ei_add_cxx_compiler_flag("-Wshorten-64-to-32")
|
||||
ei_add_cxx_compiler_flag("-Wlogical-op")
|
||||
ei_add_cxx_compiler_flag("-Wenum-conversion")
|
||||
ei_add_cxx_compiler_flag("-Wc++11-extensions")
|
||||
ei_add_cxx_compiler_flag("-Wdouble-promotion")
|
||||
# ei_add_cxx_compiler_flag("-Wconversion")
|
||||
ei_add_cxx_compiler_flag("-Wshadow")
|
||||
ei_add_cxx_compiler_flag("-Wno-psabi")
|
||||
ei_add_cxx_compiler_flag("-Wno-variadic-macros")
|
||||
ei_add_cxx_compiler_flag("-Wno-long-long")
|
||||
ei_add_cxx_compiler_flag("-fno-common")
|
||||
ei_add_cxx_compiler_flag("-fstrict-aliasing")
|
||||
ei_add_cxx_compiler_flag("-wd981") # disable ICC's "operands are evaluated in unspecified order" remark
|
||||
ei_add_cxx_compiler_flag("-wd2304") # disable ICC's "warning #2304: non-explicit constructor with single argument may cause implicit type conversion" produced by -Wnon-virtual-dtor
|
||||
|
||||
# Clang emits warnings about unused flag.
|
||||
if (NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
ei_add_cxx_compiler_flag("-fno-check-new")
|
||||
endif()
|
||||
|
||||
|
||||
if(ANDROID_NDK)
|
||||
ei_add_cxx_compiler_flag("-pie")
|
||||
ei_add_cxx_compiler_flag("-fPIE")
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "")
|
||||
|
||||
option(EIGEN_TEST_SSE2 "Enable/Disable SSE2 in tests/examples" OFF)
|
||||
if(EIGEN_TEST_SSE2)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2")
|
||||
message(STATUS "Enabling SSE2 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_SSE3 "Enable/Disable SSE3 in tests/examples" OFF)
|
||||
if(EIGEN_TEST_SSE3)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse3")
|
||||
message(STATUS "Enabling SSE3 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_SSSE3 "Enable/Disable SSSE3 in tests/examples" OFF)
|
||||
if(EIGEN_TEST_SSSE3)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mssse3")
|
||||
message(STATUS "Enabling SSSE3 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_SSE4_1 "Enable/Disable SSE4.1 in tests/examples" OFF)
|
||||
if(EIGEN_TEST_SSE4_1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1")
|
||||
message(STATUS "Enabling SSE4.1 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_SSE4_2 "Enable/Disable SSE4.2 in tests/examples" OFF)
|
||||
if(EIGEN_TEST_SSE4_2)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2")
|
||||
message(STATUS "Enabling SSE4.2 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_AVX "Enable/Disable AVX in tests/examples" OFF)
|
||||
if(EIGEN_TEST_AVX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx")
|
||||
message(STATUS "Enabling AVX in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_FMA "Enable/Disable FMA in tests/examples" OFF)
|
||||
if(EIGEN_TEST_FMA AND NOT EIGEN_TEST_NEON)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfma")
|
||||
message(STATUS "Enabling FMA in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_AVX2 "Enable/Disable AVX2 in tests/examples" OFF)
|
||||
if(EIGEN_TEST_AVX2)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx2 -mfma")
|
||||
message(STATUS "Enabling AVX2 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_AVX512 "Enable/Disable AVX512 in tests/examples" OFF)
|
||||
if(EIGEN_TEST_AVX512)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -mfma")
|
||||
message(STATUS "Enabling AVX512 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_AVX512DQ "Enable/Disable AVX512DQ in tests/examples" OFF)
|
||||
if(EIGEN_TEST_AVX512DQ)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512dq -mfma")
|
||||
message(STATUS "Enabling AVX512DQ in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_AVX512FP16 "Enable/Disable AVX512-FP16 in tests/examples" OFF)
|
||||
if(EIGEN_TEST_AVX512FP16)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -mfma -mavx512vl -mavx512fp16")
|
||||
message(STATUS "Enabling AVX512-FP16 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_F16C "Enable/Disable F16C in tests/examples" OFF)
|
||||
if(EIGEN_TEST_F16C)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mf16c")
|
||||
message(STATUS "Enabling F16C in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_ALTIVEC "Enable/Disable AltiVec in tests/examples" OFF)
|
||||
if(EIGEN_TEST_ALTIVEC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maltivec -mabi=altivec")
|
||||
message(STATUS "Enabling AltiVec in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_VSX "Enable/Disable VSX in tests/examples" OFF)
|
||||
if(EIGEN_TEST_VSX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -mvsx")
|
||||
message(STATUS "Enabling VSX in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_MSA "Enable/Disable MSA in tests/examples" OFF)
|
||||
if(EIGEN_TEST_MSA)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmsa")
|
||||
message(STATUS "Enabling MSA in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_LSX "Enable/Disable LSX in tests/examples" OFF)
|
||||
if(EIGEN_TEST_LSX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlsx")
|
||||
message(STATUS "Enabling LSX in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_NEON "Enable/Disable Neon in tests/examples" OFF)
|
||||
if(EIGEN_TEST_NEON)
|
||||
if(EIGEN_TEST_FMA)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon-vfpv4")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard")
|
||||
message(STATUS "Enabling NEON in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_NEON64 "Enable/Disable Neon in tests/examples" OFF)
|
||||
if(EIGEN_TEST_NEON64)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
message(STATUS "Enabling NEON in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_Z13 "Enable/Disable S390X(zEC13) ZVECTOR in tests/examples" OFF)
|
||||
if(EIGEN_TEST_Z13)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=z13 -mzvector")
|
||||
message(STATUS "Enabling S390X(zEC13) ZVECTOR in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_Z14 "Enable/Disable S390X(zEC14) ZVECTOR in tests/examples" OFF)
|
||||
if(EIGEN_TEST_Z14)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=z14 -mzvector")
|
||||
message(STATUS "Enabling S390X(zEC13) ZVECTOR in tests/examples")
|
||||
endif()
|
||||
|
||||
check_cxx_compiler_flag("-fopenmp" COMPILER_SUPPORT_OPENMP)
|
||||
if(COMPILER_SUPPORT_OPENMP)
|
||||
option(EIGEN_TEST_OPENMP "Enable/Disable OpenMP in tests/examples" OFF)
|
||||
if(EIGEN_TEST_OPENMP)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
|
||||
message(STATUS "Enabling OpenMP in tests/examples")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
else()
|
||||
# C4127 - conditional expression is constant
|
||||
# C4714 - marked as __forceinline not inlined (I failed to deactivate it selectively)
|
||||
# We can disable this warning in the unit tests since it is clear that it occurs
|
||||
# because we are oftentimes returning objects that have a destructor or may
|
||||
# throw exceptions - in particular in the unit tests we are throwing extra many
|
||||
# exceptions to cover indexing errors.
|
||||
# C4505 - unreferenced local function has been removed (impossible to deactivate selectively)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /wd4127 /wd4505 /wd4714")
|
||||
|
||||
# replace all /Wx by /W4
|
||||
string(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
check_cxx_compiler_flag("/openmp" COMPILER_SUPPORT_OPENMP)
|
||||
if(COMPILER_SUPPORT_OPENMP)
|
||||
option(EIGEN_TEST_OPENMP "Enable/Disable OpenMP in tests/examples" OFF)
|
||||
if(EIGEN_TEST_OPENMP)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /openmp")
|
||||
message(STATUS "Enabling OpenMP in tests/examples")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_SSE2 "Enable/Disable SSE2 in tests/examples" OFF)
|
||||
if(EIGEN_TEST_SSE2)
|
||||
if(NOT CMAKE_CL_64)
|
||||
# arch is not supported on 64 bit systems, SSE is enabled automatically.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2")
|
||||
endif()
|
||||
message(STATUS "Enabling SSE2 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_AVX "Enable/Disable AVX in tests/examples" OFF)
|
||||
if(EIGEN_TEST_AVX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX")
|
||||
message(STATUS "Enabling AVX in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_FMA "Enable/Disable FMA/AVX2 in tests/examples" OFF)
|
||||
option(EIGEN_TEST_AVX2 "Enable/Disable FMA/AVX2 in tests/examples" OFF)
|
||||
if((EIGEN_TEST_FMA AND NOT EIGEN_TEST_NEON) OR EIGEN_TEST_AVX2)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX2")
|
||||
message(STATUS "Enabling FMA/AVX2 in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_AVX512 "Enable/Disable AVX512 in tests/examples" OFF)
|
||||
option(EIGEN_TEST_AVX512DQ "Enable/Disable AVX512DQ in tests/examples" OFF)
|
||||
if(EIGEN_TEST_AVX512 OR EIGEN_TEST_AVX512DQ)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX512")
|
||||
message(STATUS "Enabling AVX512 in tests/examples")
|
||||
endif()
|
||||
|
||||
endif(NOT MSVC)
|
||||
|
||||
option(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION "Disable explicit vectorization in tests/examples" OFF)
|
||||
option(EIGEN_TEST_X87 "Force using X87 instructions. Implies no vectorization." OFF)
|
||||
option(EIGEN_TEST_32BIT "Force generating 32bit code." OFF)
|
||||
|
||||
if(EIGEN_TEST_X87)
|
||||
set(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION ON)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=387")
|
||||
message(STATUS "Forcing use of x87 instructions in tests/examples")
|
||||
else()
|
||||
message(STATUS "EIGEN_TEST_X87 ignored on your compiler")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(EIGEN_TEST_32BIT)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
|
||||
message(STATUS "Forcing generation of 32-bit code in tests/examples")
|
||||
else()
|
||||
message(STATUS "EIGEN_TEST_32BIT ignored on your compiler")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION)
|
||||
add_definitions(-DEIGEN_DONT_VECTORIZE=1)
|
||||
message(STATUS "Disabling vectorization in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_NO_EXPLICIT_ALIGNMENT "Disable explicit alignment (hence vectorization) in tests/examples" OFF)
|
||||
if(EIGEN_TEST_NO_EXPLICIT_ALIGNMENT)
|
||||
add_definitions(-DEIGEN_DONT_ALIGN=1)
|
||||
message(STATUS "Disabling alignment in tests/examples")
|
||||
endif()
|
||||
|
||||
option(EIGEN_TEST_NO_EXCEPTIONS "Disables C++ exceptions" OFF)
|
||||
if(EIGEN_TEST_NO_EXCEPTIONS)
|
||||
ei_add_cxx_compiler_flag("-fno-exceptions")
|
||||
message(STATUS "Disabling exceptions in tests/examples")
|
||||
endif()
|
||||
|
||||
set(EIGEN_CUDA_CXX_FLAGS "" CACHE STRING "Additional flags to pass to the cuda compiler.")
|
||||
set(EIGEN_CUDA_COMPUTE_ARCH 30 CACHE STRING "The CUDA compute architecture(s) to target when compiling CUDA code")
|
||||
|
||||
option(EIGEN_TEST_SYCL "Add Sycl support." OFF)
|
||||
if(EIGEN_TEST_SYCL)
|
||||
option(EIGEN_SYCL_DPCPP "Use the DPCPP Sycl implementation (DPCPP is default SYCL-Compiler)." ON)
|
||||
option(EIGEN_SYCL_TRISYCL "Use the triSYCL Sycl implementation." OFF)
|
||||
option(EIGEN_SYCL_ComputeCpp "Use the ComputeCPP Sycl implementation." OFF)
|
||||
|
||||
# Building options
|
||||
# https://developer.codeplay.com/products/computecpp/ce/2.11.0/guides/eigen-overview/options-for-building-eigen-sycl
|
||||
option(EIGEN_SYCL_USE_DEFAULT_SELECTOR "Use sycl default selector to select the preferred device." OFF)
|
||||
option(EIGEN_SYCL_NO_LOCAL_MEM "Build for devices without dedicated shared memory." OFF)
|
||||
option(EIGEN_SYCL_LOCAL_MEM "Allow the use of local memory (enabled by default)." ON)
|
||||
option(EIGEN_SYCL_LOCAL_THREAD_DIM0 "Set work group size for dimension 0." 16)
|
||||
option(EIGEN_SYCL_LOCAL_THREAD_DIM1 "Set work group size for dimension 1." 16)
|
||||
option(EIGEN_SYCL_ASYNC_EXECUTION "Allow asynchronous execution (enabled by default)." ON)
|
||||
option(EIGEN_SYCL_DISABLE_SKINNY "Disable optimization for tall/skinny matrices." OFF)
|
||||
option(EIGEN_SYCL_DISABLE_DOUBLE_BUFFER "Disable double buffer." OFF)
|
||||
option(EIGEN_SYCL_DISABLE_SCALAR "Disable scalar contraction." OFF)
|
||||
option(EIGEN_SYCL_DISABLE_GEMV "Disable GEMV and create a single kernel to calculate contraction instead." OFF)
|
||||
|
||||
set(EIGEN_SYCL ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations -Wno-shorten-64-to-32 -Wno-cast-align")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-copy-with-user-provided-copy -Wno-unused-variable")
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules" "cmake/Modules/" "${CMAKE_MODULE_PATH}")
|
||||
find_package(Threads REQUIRED)
|
||||
if(EIGEN_SYCL_TRISYCL)
|
||||
message(STATUS "Using triSYCL")
|
||||
include(FindTriSYCL)
|
||||
elseif(EIGEN_SYCL_ComputeCpp)
|
||||
message(STATUS "Using ComputeCPP SYCL")
|
||||
include(FindComputeCpp)
|
||||
set(COMPUTECPP_DRIVER_DEFAULT_VALUE OFF)
|
||||
if (NOT MSVC)
|
||||
set(COMPUTECPP_DRIVER_DEFAULT_VALUE ON)
|
||||
endif()
|
||||
option(COMPUTECPP_USE_COMPILER_DRIVER
|
||||
"Use ComputeCpp driver instead of a 2 steps compilation"
|
||||
${COMPUTECPP_DRIVER_DEFAULT_VALUE}
|
||||
)
|
||||
else() #Default SYCL compiler is DPCPP (EIGEN_SYCL_DPCPP)
|
||||
set(DPCPP_SYCL_TARGET "spir64" CACHE STRING "Default target for Intel CPU/GPU")
|
||||
message(STATUS "Using DPCPP")
|
||||
find_package(DPCPP)
|
||||
add_definitions(-DSYCL_COMPILER_IS_DPCPP)
|
||||
endif(EIGEN_SYCL_TRISYCL)
|
||||
if(EIGEN_DONT_VECTORIZE_SYCL)
|
||||
message(STATUS "Disabling SYCL vectorization in tests/examples")
|
||||
# When disabling SYCL vectorization, also disable Eigen default vectorization
|
||||
add_definitions(-DEIGEN_DONT_VECTORIZE=1)
|
||||
add_definitions(-DEIGEN_DONT_VECTORIZE_SYCL=1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(EigenConfigureTesting)
|
||||
|
||||
if(EIGEN_LEAVE_TEST_IN_ALL_TARGET)
|
||||
# CTest automatic test building relies on the "all" target.
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(failtest)
|
||||
else()
|
||||
add_subdirectory(test EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(failtest EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
ei_testing_print_summary()
|
||||
|
||||
if (EIGEN_SPLIT_TESTSUITE)
|
||||
ei_split_testsuite("${EIGEN_SPLIT_TESTSUITE}")
|
||||
endif()
|
||||
endif(EIGEN_BUILD_TESTING)
|
||||
|
||||
#==============================================================================
|
||||
# Other Build Configurations.
|
||||
#==============================================================================
|
||||
add_subdirectory(unsupported)
|
||||
|
||||
if(EIGEN_BUILD_BLAS)
|
||||
add_subdirectory(blas)
|
||||
endif()
|
||||
|
||||
if (EIGEN_BUILD_LAPACK)
|
||||
add_subdirectory(lapack)
|
||||
endif()
|
||||
|
||||
if(EIGEN_BUILD_DOC)
|
||||
add_subdirectory(doc EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# TODO: consider also replacing EIGEN_BUILD_BTL by a custom target "make btl"?
|
||||
if(EIGEN_BUILD_BTL)
|
||||
add_subdirectory(bench/btl EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 AND EIGEN_BUILD_SPBENCH)
|
||||
add_subdirectory(bench/spbench EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
if (EIGEN_BUILD_DEMOS)
|
||||
add_subdirectory(demos EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
if (PROJECT_IS_TOP_LEVEL)
|
||||
# must be after test and unsupported, for configuring buildtests.in
|
||||
add_subdirectory(scripts EXCLUDE_FROM_ALL)
|
||||
configure_file(scripts/cdashtesting.cmake.in cdashtesting.cmake @ONLY)
|
||||
endif()
|
||||
|
||||
#==============================================================================
|
||||
# Summary.
|
||||
#==============================================================================
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
string(TOLOWER "${CMAKE_GENERATOR}" cmake_generator_tolower)
|
||||
if(cmake_generator_tolower MATCHES "makefile")
|
||||
message(STATUS "Available targets (use: make TARGET):")
|
||||
else()
|
||||
message(STATUS "Available targets (use: cmake --build . --target TARGET):")
|
||||
endif()
|
||||
message(STATUS "------------+--------------------------------------------------------------")
|
||||
message(STATUS "Target | Description")
|
||||
message(STATUS "------------+--------------------------------------------------------------")
|
||||
message(STATUS "install | Install Eigen. Headers will be installed to:")
|
||||
message(STATUS " | <CMAKE_INSTALL_PREFIX>/<INCLUDE_INSTALL_DIR>")
|
||||
message(STATUS " | Using the following values:")
|
||||
message(STATUS " | CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
|
||||
message(STATUS " | INCLUDE_INSTALL_DIR: ${INCLUDE_INSTALL_DIR}")
|
||||
message(STATUS " | Change the install location of Eigen headers using:")
|
||||
message(STATUS " | cmake . -DCMAKE_INSTALL_PREFIX=yourprefix")
|
||||
message(STATUS " | Or:")
|
||||
message(STATUS " | cmake . -DINCLUDE_INSTALL_DIR=yourdir")
|
||||
message(STATUS "uninstall | Remove files installed by the install target")
|
||||
if (EIGEN_BUILD_DOC)
|
||||
message(STATUS "doc | Generate the API documentation, requires Doxygen & LaTeX")
|
||||
message(STATUS "install-doc | Install the API documentation")
|
||||
endif()
|
||||
if(EIGEN_BUILD_TESTING)
|
||||
message(STATUS "check | Build and run the unit-tests. Read this page:")
|
||||
message(STATUS " | http://eigen.tuxfamily.org/index.php?title=Tests")
|
||||
endif()
|
||||
if (EIGEN_BUILD_BLAS)
|
||||
message(STATUS "blas | Build BLAS library (not the same thing as Eigen)")
|
||||
endif()
|
||||
if (EIGEN_BUILD_LAPACK)
|
||||
message(STATUS "lapack | Build LAPACK subset library (not the same thing as Eigen)")
|
||||
endif()
|
||||
message(STATUS "------------+--------------------------------------------------------------")
|
||||
message(STATUS "")
|
||||
endif()
|
||||
|
||||
message(STATUS "")
|
||||
message(STATUS "Configured Eigen ${EIGEN_VERSION_STRING}")
|
||||
message(STATUS "")
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright (c) 2011, Intel Corporation. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
@@ -0,0 +1,51 @@
|
||||
Minpack Copyright Notice (1999) University of Chicago. All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
3. The end-user documentation included with the
|
||||
redistribution, if any, must include the following
|
||||
acknowledgment:
|
||||
|
||||
"This product includes software developed by the
|
||||
University of Chicago, as Operator of Argonne National
|
||||
Laboratory.
|
||||
|
||||
Alternately, this acknowledgment may appear in the software
|
||||
itself, if and wherever such third-party acknowledgments
|
||||
normally appear.
|
||||
|
||||
4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS"
|
||||
WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE
|
||||
UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND
|
||||
THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE
|
||||
OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY
|
||||
OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR
|
||||
USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF
|
||||
THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4)
|
||||
DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION
|
||||
UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL
|
||||
BE CORRECTED.
|
||||
|
||||
5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT
|
||||
HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF
|
||||
ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF
|
||||
ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER
|
||||
SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT
|
||||
(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE,
|
||||
EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE
|
||||
POSSIBILITY OF SUCH LOSS OR DAMAGES.
|
||||
+373
@@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
@@ -0,0 +1,6 @@
|
||||
Eigen is primarily MPL2 licensed. See COPYING.MPL2 and these links:
|
||||
http://www.mozilla.org/MPL/2.0/
|
||||
http://www.mozilla.org/MPL/2.0/FAQ.html
|
||||
|
||||
Some files contain third-party code under BSD or other MPL2-compatible licenses,
|
||||
whence the other COPYING.* files here.
|
||||
@@ -0,0 +1,17 @@
|
||||
## This file should be placed in the root directory of your project.
|
||||
## Then modify the CMakeLists.txt file in the root directory of your
|
||||
## project to incorporate the testing dashboard.
|
||||
## # The following are required to uses Dart and the Cdash dashboard
|
||||
## enable_testing()
|
||||
## include(CTest)
|
||||
set(CTEST_PROJECT_NAME "Eigen")
|
||||
set(CTEST_NIGHTLY_START_TIME "00:00:00 UTC")
|
||||
|
||||
set(CTEST_DROP_METHOD "http")
|
||||
set(CTEST_DROP_SITE "my.cdash.org")
|
||||
set(CTEST_DROP_LOCATION "/submit.php?project=Eigen")
|
||||
set(CTEST_DROP_SITE_CDASH TRUE)
|
||||
#set(CTEST_PROJECT_SUBPROJECTS
|
||||
#Official
|
||||
#Unsupported
|
||||
#)
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS "2000")
|
||||
set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS "2000")
|
||||
list(APPEND CTEST_CUSTOM_ERROR_EXCEPTION @EIGEN_CTEST_ERROR_EXCEPTION@)
|
||||
@@ -0,0 +1,52 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_ACCELERATESUPPORT_MODULE_H
|
||||
#define EIGEN_ACCELERATESUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup AccelerateSupport_Module AccelerateSupport module
|
||||
*
|
||||
* This module provides an interface to the Apple Accelerate library.
|
||||
* It provides the seven following main factorization classes:
|
||||
* - class AccelerateLLT: a Cholesky (LL^T) factorization.
|
||||
* - class AccelerateLDLT: the default LDL^T factorization.
|
||||
* - class AccelerateLDLTUnpivoted: a Cholesky-like LDL^T factorization with only 1x1 pivots and no pivoting
|
||||
* - class AccelerateLDLTSBK: an LDL^T factorization with Supernode Bunch-Kaufman and static pivoting
|
||||
* - class AccelerateLDLTTPP: an LDL^T factorization with full threshold partial pivoting
|
||||
* - class AccelerateQR: a QR factorization
|
||||
* - class AccelerateCholeskyAtA: a QR factorization without storing Q (equivalent to A^TA = R^T R)
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/AccelerateSupport>
|
||||
* \endcode
|
||||
*
|
||||
* In order to use this module, the Accelerate headers must be accessible from
|
||||
* the include paths, and your binary must be linked to the Accelerate framework.
|
||||
* The Accelerate library is only available on Apple hardware.
|
||||
*
|
||||
* Note that many of the algorithms can be influenced by the UpLo template
|
||||
* argument. All matrices are assumed to be symmetric. For example, the following
|
||||
* creates an LDLT factorization where your matrix is symmetric (implicit) and
|
||||
* uses the lower triangle:
|
||||
*
|
||||
* \code
|
||||
* AccelerateLDLT<SparseMatrix<float>, Lower> ldlt;
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/AccelerateSupport/AccelerateSupport.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_ACCELERATESUPPORT_MODULE_H
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CHOLESKY_MODULE_H
|
||||
#define EIGEN_CHOLESKY_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
#include "Jacobi"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup Cholesky_Module Cholesky module
|
||||
*
|
||||
*
|
||||
*
|
||||
* This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices.
|
||||
* Those decompositions are also accessible via the following methods:
|
||||
* - MatrixBase::llt()
|
||||
* - MatrixBase::ldlt()
|
||||
* - SelfAdjointView::llt()
|
||||
* - SelfAdjointView::ldlt()
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/Cholesky>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/Cholesky/LLT.h"
|
||||
#include "src/Cholesky/LDLT.h"
|
||||
#ifdef EIGEN_USE_LAPACKE
|
||||
#include "src/misc/lapacke_helpers.h"
|
||||
#include "src/Cholesky/LLT_LAPACKE.h"
|
||||
#endif
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_CHOLESKY_MODULE_H
|
||||
@@ -0,0 +1,48 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CHOLMODSUPPORT_MODULE_H
|
||||
#define EIGEN_CHOLMODSUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
#include <cholmod.h>
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup CholmodSupport_Module CholmodSupport module
|
||||
*
|
||||
* This module provides an interface to the Cholmod library which is part of the <a
|
||||
* href="http://www.suitesparse.com">suitesparse</a> package. It provides the two following main factorization classes:
|
||||
* - class CholmodSupernodalLLT: a supernodal LLT Cholesky factorization.
|
||||
* - class CholmodDecomposition: a general L(D)LT Cholesky factorization with automatic or explicit runtime selection of
|
||||
* the underlying factorization method (supernodal or simplicial).
|
||||
*
|
||||
* For the sake of completeness, this module also propose the two following classes:
|
||||
* - class CholmodSimplicialLLT
|
||||
* - class CholmodSimplicialLDLT
|
||||
* Note that these classes does not bring any particular advantage compared to the built-in
|
||||
* SimplicialLLT and SimplicialLDLT factorization classes.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/CholmodSupport>
|
||||
* \endcode
|
||||
*
|
||||
* In order to use this module, the cholmod headers must be accessible from the include paths, and your binary must be
|
||||
* linked to the cholmod library and its dependencies. The dependencies depend on how cholmod has been compiled. For a
|
||||
* cmake based project, you can use our FindCholmod.cmake module to help you in this task.
|
||||
*
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/CholmodSupport/CholmodSupport.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_CHOLMODSUPPORT_MODULE_H
|
||||
+446
@@ -0,0 +1,446 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2007-2011 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CORE_MODULE_H
|
||||
#define EIGEN_CORE_MODULE_H
|
||||
|
||||
// Eigen version information.
|
||||
#include "Version"
|
||||
|
||||
// first thing Eigen does: stop the compiler from reporting useless warnings.
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
// then include this file where all our macros are defined. It's really important to do it first because
|
||||
// it's where we do all the compiler/OS/arch detections and define most defaults.
|
||||
#include "src/Core/util/Macros.h"
|
||||
|
||||
// This detects SSE/AVX/NEON/etc. and configure alignment settings
|
||||
#include "src/Core/util/ConfigureVectorization.h"
|
||||
|
||||
// We need cuda_runtime.h/hip_runtime.h to ensure that
|
||||
// the EIGEN_USING_STD macro works properly on the device side
|
||||
#if defined(EIGEN_CUDACC)
|
||||
#include <cuda_runtime.h>
|
||||
#elif defined(EIGEN_HIPCC)
|
||||
#include <hip/hip_runtime.h>
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_EXCEPTIONS
|
||||
#include <new>
|
||||
#endif
|
||||
|
||||
// Disable the ipa-cp-clone optimization flag with MinGW 6.x or older (enabled by default with -O3)
|
||||
// See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details.
|
||||
#if EIGEN_COMP_MINGW && EIGEN_GNUC_STRICT_LESS_THAN(6, 0, 0)
|
||||
#pragma GCC optimize("-fno-ipa-cp-clone")
|
||||
#endif
|
||||
|
||||
// Prevent ICC from specializing std::complex operators that silently fail
|
||||
// on device. This allows us to use our own device-compatible specializations
|
||||
// instead.
|
||||
#if EIGEN_COMP_ICC && defined(EIGEN_GPU_COMPILE_PHASE) && !defined(_OVERRIDE_COMPLEX_SPECIALIZATION_)
|
||||
#define _OVERRIDE_COMPLEX_SPECIALIZATION_ 1
|
||||
#endif
|
||||
#include <complex>
|
||||
|
||||
// this include file manages BLAS and MKL related macros
|
||||
// and inclusion of their respective header files
|
||||
#include "src/Core/util/MKL_support.h"
|
||||
|
||||
#if defined(EIGEN_HAS_CUDA_FP16) || defined(EIGEN_HAS_HIP_FP16)
|
||||
#define EIGEN_HAS_GPU_FP16
|
||||
#endif
|
||||
|
||||
#if defined(EIGEN_HAS_CUDA_BF16) || defined(EIGEN_HAS_HIP_BF16)
|
||||
#define EIGEN_HAS_GPU_BF16
|
||||
#endif
|
||||
|
||||
#if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE)
|
||||
#define EIGEN_HAS_OPENMP
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_HAS_OPENMP
|
||||
#include <atomic>
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
// MSVC for windows mobile does not have the errno.h file
|
||||
#if !(EIGEN_COMP_MSVC && EIGEN_OS_WINCE) && !EIGEN_COMP_ARM
|
||||
#define EIGEN_HAS_ERRNO
|
||||
#endif
|
||||
|
||||
#ifdef EIGEN_HAS_ERRNO
|
||||
#include <cerrno>
|
||||
#endif
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#ifndef EIGEN_NO_IO
|
||||
#include <sstream>
|
||||
#include <iosfwd>
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
#include <climits> // for CHAR_BIT
|
||||
// for min/max:
|
||||
#include <algorithm>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// for std::is_nothrow_move_assignable
|
||||
#include <type_traits>
|
||||
|
||||
// for std::this_thread::yield().
|
||||
#if !defined(EIGEN_USE_BLAS) && (defined(EIGEN_HAS_OPENMP) || defined(EIGEN_GEMM_THREADPOOL))
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
// for std::bit_cast()
|
||||
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||
#include <bit>
|
||||
#endif
|
||||
|
||||
// for outputting debug info
|
||||
#ifdef EIGEN_DEBUG_ASSIGN
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
// required for __cpuid, needs to be included after cmath
|
||||
// also required for _BitScanReverse on Windows on ARM
|
||||
#if EIGEN_COMP_MSVC && (EIGEN_ARCH_i386_OR_x86_64 || EIGEN_ARCH_ARM64) && !EIGEN_OS_WINCE
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(EIGEN_USE_SYCL)
|
||||
#undef min
|
||||
#undef max
|
||||
#undef isnan
|
||||
#undef isinf
|
||||
#undef isfinite
|
||||
#include <CL/sycl.hpp>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#ifndef EIGEN_SYCL_LOCAL_THREAD_DIM0
|
||||
#define EIGEN_SYCL_LOCAL_THREAD_DIM0 16
|
||||
#endif
|
||||
#ifndef EIGEN_SYCL_LOCAL_THREAD_DIM1
|
||||
#define EIGEN_SYCL_LOCAL_THREAD_DIM1 16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS || defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API || \
|
||||
defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS || defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API || \
|
||||
defined EIGEN2_SUPPORT
|
||||
// This will generate an error message:
|
||||
#error Eigen2-support is only available up to version 3.2. Please go to "http://eigen.tuxfamily.org/index.php?title=Eigen2" for further information
|
||||
#endif
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
// we use size_t frequently and we'll never remember to prepend it with std:: every time just to
|
||||
// ensure QNX/QCC support
|
||||
using std::size_t;
|
||||
// gcc 4.6.0 wants std:: for ptrdiff_t
|
||||
using std::ptrdiff_t;
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
/** \defgroup Core_Module Core module
|
||||
* This is the main module of Eigen providing dense matrix and vector support
|
||||
* (both fixed and dynamic size) with all the features corresponding to a BLAS library
|
||||
* and much more...
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/Core>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
#ifdef EIGEN_USE_LAPACKE
|
||||
#ifdef EIGEN_USE_MKL
|
||||
#include "mkl_lapacke.h"
|
||||
#else
|
||||
#include "src/misc/lapacke.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/Core/util/Constants.h"
|
||||
#include "src/Core/util/Meta.h"
|
||||
#include "src/Core/util/Assert.h"
|
||||
#include "src/Core/util/ForwardDeclarations.h"
|
||||
#include "src/Core/util/StaticAssert.h"
|
||||
#include "src/Core/util/XprHelper.h"
|
||||
#include "src/Core/util/Memory.h"
|
||||
#include "src/Core/util/IntegralConstant.h"
|
||||
#include "src/Core/util/Serializer.h"
|
||||
#include "src/Core/util/SymbolicIndex.h"
|
||||
#include "src/Core/util/EmulateArray.h"
|
||||
#include "src/Core/util/MoreMeta.h"
|
||||
|
||||
#include "src/Core/NumTraits.h"
|
||||
#include "src/Core/MathFunctions.h"
|
||||
#include "src/Core/RandomImpl.h"
|
||||
#include "src/Core/GenericPacketMath.h"
|
||||
#include "src/Core/MathFunctionsImpl.h"
|
||||
#include "src/Core/arch/Default/ConjHelper.h"
|
||||
// Generic half float support
|
||||
#include "src/Core/arch/Default/Half.h"
|
||||
#include "src/Core/arch/Default/BFloat16.h"
|
||||
#include "src/Core/arch/Default/GenericPacketMathFunctionsFwd.h"
|
||||
|
||||
#if defined EIGEN_VECTORIZE_AVX512
|
||||
#include "src/Core/arch/SSE/PacketMath.h"
|
||||
#include "src/Core/arch/SSE/Reductions.h"
|
||||
#include "src/Core/arch/AVX/PacketMath.h"
|
||||
#include "src/Core/arch/AVX/Reductions.h"
|
||||
#include "src/Core/arch/AVX512/PacketMath.h"
|
||||
#include "src/Core/arch/AVX512/Reductions.h"
|
||||
#if defined EIGEN_VECTORIZE_AVX512FP16
|
||||
#include "src/Core/arch/AVX512/PacketMathFP16.h"
|
||||
#endif
|
||||
#include "src/Core/arch/SSE/TypeCasting.h"
|
||||
#include "src/Core/arch/AVX/TypeCasting.h"
|
||||
#include "src/Core/arch/AVX512/TypeCasting.h"
|
||||
#if defined EIGEN_VECTORIZE_AVX512FP16
|
||||
#include "src/Core/arch/AVX512/TypeCastingFP16.h"
|
||||
#endif
|
||||
#include "src/Core/arch/SSE/Complex.h"
|
||||
#include "src/Core/arch/AVX/Complex.h"
|
||||
#include "src/Core/arch/AVX512/Complex.h"
|
||||
#include "src/Core/arch/SSE/MathFunctions.h"
|
||||
#include "src/Core/arch/AVX/MathFunctions.h"
|
||||
#include "src/Core/arch/AVX512/MathFunctions.h"
|
||||
#if defined EIGEN_VECTORIZE_AVX512FP16
|
||||
#include "src/Core/arch/AVX512/MathFunctionsFP16.h"
|
||||
#endif
|
||||
#include "src/Core/arch/AVX512/TrsmKernel.h"
|
||||
#elif defined EIGEN_VECTORIZE_AVX
|
||||
// Use AVX for floats and doubles, SSE for integers
|
||||
#include "src/Core/arch/SSE/PacketMath.h"
|
||||
#include "src/Core/arch/SSE/Reductions.h"
|
||||
#include "src/Core/arch/SSE/TypeCasting.h"
|
||||
#include "src/Core/arch/SSE/Complex.h"
|
||||
#include "src/Core/arch/AVX/PacketMath.h"
|
||||
#include "src/Core/arch/AVX/Reductions.h"
|
||||
#include "src/Core/arch/AVX/TypeCasting.h"
|
||||
#include "src/Core/arch/AVX/Complex.h"
|
||||
#include "src/Core/arch/SSE/MathFunctions.h"
|
||||
#include "src/Core/arch/AVX/MathFunctions.h"
|
||||
#elif defined EIGEN_VECTORIZE_SSE
|
||||
#include "src/Core/arch/SSE/PacketMath.h"
|
||||
#include "src/Core/arch/SSE/Reductions.h"
|
||||
#include "src/Core/arch/SSE/TypeCasting.h"
|
||||
#include "src/Core/arch/SSE/MathFunctions.h"
|
||||
#include "src/Core/arch/SSE/Complex.h"
|
||||
#endif
|
||||
|
||||
#if defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX)
|
||||
#include "src/Core/arch/AltiVec/PacketMath.h"
|
||||
#include "src/Core/arch/AltiVec/TypeCasting.h"
|
||||
#include "src/Core/arch/AltiVec/MathFunctions.h"
|
||||
#include "src/Core/arch/AltiVec/Complex.h"
|
||||
#elif defined EIGEN_VECTORIZE_NEON
|
||||
#include "src/Core/arch/NEON/PacketMath.h"
|
||||
#include "src/Core/arch/NEON/TypeCasting.h"
|
||||
#include "src/Core/arch/NEON/MathFunctions.h"
|
||||
#include "src/Core/arch/NEON/Complex.h"
|
||||
#elif defined EIGEN_VECTORIZE_LSX
|
||||
#include "src/Core/arch/LSX/PacketMath.h"
|
||||
#include "src/Core/arch/LSX/TypeCasting.h"
|
||||
#include "src/Core/arch/LSX/MathFunctions.h"
|
||||
#include "src/Core/arch/LSX/Complex.h"
|
||||
#elif defined EIGEN_VECTORIZE_SVE
|
||||
#include "src/Core/arch/SVE/PacketMath.h"
|
||||
#include "src/Core/arch/SVE/TypeCasting.h"
|
||||
#include "src/Core/arch/SVE/MathFunctions.h"
|
||||
#elif defined EIGEN_VECTORIZE_ZVECTOR
|
||||
#include "src/Core/arch/ZVector/PacketMath.h"
|
||||
#include "src/Core/arch/ZVector/MathFunctions.h"
|
||||
#include "src/Core/arch/ZVector/Complex.h"
|
||||
#elif defined EIGEN_VECTORIZE_MSA
|
||||
#include "src/Core/arch/MSA/PacketMath.h"
|
||||
#include "src/Core/arch/MSA/MathFunctions.h"
|
||||
#include "src/Core/arch/MSA/Complex.h"
|
||||
#elif defined EIGEN_VECTORIZE_HVX
|
||||
#include "src/Core/arch/HVX/PacketMath.h"
|
||||
#endif
|
||||
|
||||
#if defined EIGEN_VECTORIZE_GPU
|
||||
#include "src/Core/arch/GPU/PacketMath.h"
|
||||
#include "src/Core/arch/GPU/MathFunctions.h"
|
||||
#include "src/Core/arch/GPU/TypeCasting.h"
|
||||
#endif
|
||||
|
||||
#if defined(EIGEN_USE_SYCL)
|
||||
#include "src/Core/arch/SYCL/InteropHeaders.h"
|
||||
#if !defined(EIGEN_DONT_VECTORIZE_SYCL)
|
||||
#include "src/Core/arch/SYCL/PacketMath.h"
|
||||
#include "src/Core/arch/SYCL/MathFunctions.h"
|
||||
#include "src/Core/arch/SYCL/TypeCasting.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "src/Core/arch/Default/Settings.h"
|
||||
// This file provides generic implementations valid for scalar as well
|
||||
#include "src/Core/arch/Default/GenericPacketMathFunctions.h"
|
||||
|
||||
#include "src/Core/functors/TernaryFunctors.h"
|
||||
#include "src/Core/functors/BinaryFunctors.h"
|
||||
#include "src/Core/functors/UnaryFunctors.h"
|
||||
#include "src/Core/functors/NullaryFunctors.h"
|
||||
#include "src/Core/functors/StlFunctors.h"
|
||||
#include "src/Core/functors/AssignmentFunctors.h"
|
||||
|
||||
// Specialized functors for GPU.
|
||||
#ifdef EIGEN_GPUCC
|
||||
#include "src/Core/arch/GPU/Complex.h"
|
||||
#endif
|
||||
|
||||
// Specializations of vectorized activation functions for NEON.
|
||||
#ifdef EIGEN_VECTORIZE_NEON
|
||||
#include "src/Core/arch/NEON/UnaryFunctors.h"
|
||||
#endif
|
||||
|
||||
#include "src/Core/util/IndexedViewHelper.h"
|
||||
#include "src/Core/util/ReshapedHelper.h"
|
||||
#include "src/Core/ArithmeticSequence.h"
|
||||
#ifndef EIGEN_NO_IO
|
||||
#include "src/Core/IO.h"
|
||||
#endif
|
||||
#include "src/Core/DenseCoeffsBase.h"
|
||||
#include "src/Core/DenseBase.h"
|
||||
#include "src/Core/MatrixBase.h"
|
||||
#include "src/Core/EigenBase.h"
|
||||
|
||||
#include "src/Core/Product.h"
|
||||
#include "src/Core/CoreEvaluators.h"
|
||||
#include "src/Core/AssignEvaluator.h"
|
||||
#include "src/Core/RealView.h"
|
||||
#include "src/Core/Assign.h"
|
||||
|
||||
#include "src/Core/ArrayBase.h"
|
||||
#include "src/Core/util/BlasUtil.h"
|
||||
#include "src/Core/DenseStorage.h"
|
||||
#include "src/Core/NestByValue.h"
|
||||
|
||||
// #include "src/Core/ForceAlignedAccess.h"
|
||||
|
||||
#include "src/Core/ReturnByValue.h"
|
||||
#include "src/Core/NoAlias.h"
|
||||
#include "src/Core/PlainObjectBase.h"
|
||||
#include "src/Core/Matrix.h"
|
||||
#include "src/Core/Array.h"
|
||||
#include "src/Core/Fill.h"
|
||||
#include "src/Core/CwiseTernaryOp.h"
|
||||
#include "src/Core/CwiseBinaryOp.h"
|
||||
#include "src/Core/CwiseUnaryOp.h"
|
||||
#include "src/Core/CwiseNullaryOp.h"
|
||||
#include "src/Core/CwiseUnaryView.h"
|
||||
#include "src/Core/SelfCwiseBinaryOp.h"
|
||||
#include "src/Core/InnerProduct.h"
|
||||
#include "src/Core/Dot.h"
|
||||
#include "src/Core/StableNorm.h"
|
||||
#include "src/Core/Stride.h"
|
||||
#include "src/Core/MapBase.h"
|
||||
#include "src/Core/Map.h"
|
||||
#include "src/Core/Ref.h"
|
||||
#include "src/Core/Block.h"
|
||||
#include "src/Core/VectorBlock.h"
|
||||
#include "src/Core/IndexedView.h"
|
||||
#include "src/Core/Reshaped.h"
|
||||
#include "src/Core/Transpose.h"
|
||||
#include "src/Core/DiagonalMatrix.h"
|
||||
#include "src/Core/Diagonal.h"
|
||||
#include "src/Core/DiagonalProduct.h"
|
||||
#include "src/Core/SkewSymmetricMatrix3.h"
|
||||
#include "src/Core/Redux.h"
|
||||
#include "src/Core/Visitor.h"
|
||||
#include "src/Core/FindCoeff.h"
|
||||
#include "src/Core/Fuzzy.h"
|
||||
#include "src/Core/Swap.h"
|
||||
#include "src/Core/CommaInitializer.h"
|
||||
#include "src/Core/GeneralProduct.h"
|
||||
#include "src/Core/Solve.h"
|
||||
#include "src/Core/Inverse.h"
|
||||
#include "src/Core/SolverBase.h"
|
||||
#include "src/Core/PermutationMatrix.h"
|
||||
#include "src/Core/Transpositions.h"
|
||||
#include "src/Core/TriangularMatrix.h"
|
||||
#include "src/Core/SelfAdjointView.h"
|
||||
#include "src/Core/products/GeneralBlockPanelKernel.h"
|
||||
#include "src/Core/DeviceWrapper.h"
|
||||
#ifdef EIGEN_GEMM_THREADPOOL
|
||||
#include "ThreadPool"
|
||||
#endif
|
||||
#include "src/Core/products/Parallelizer.h"
|
||||
#include "src/Core/ProductEvaluators.h"
|
||||
#include "src/Core/products/GeneralMatrixVector.h"
|
||||
#include "src/Core/products/GeneralMatrixMatrix.h"
|
||||
#include "src/Core/SolveTriangular.h"
|
||||
#include "src/Core/products/GeneralMatrixMatrixTriangular.h"
|
||||
#include "src/Core/products/SelfadjointMatrixVector.h"
|
||||
#include "src/Core/products/SelfadjointMatrixMatrix.h"
|
||||
#include "src/Core/products/SelfadjointProduct.h"
|
||||
#include "src/Core/products/SelfadjointRank2Update.h"
|
||||
#include "src/Core/products/TriangularMatrixVector.h"
|
||||
#include "src/Core/products/TriangularMatrixMatrix.h"
|
||||
#include "src/Core/products/TriangularSolverMatrix.h"
|
||||
#include "src/Core/products/TriangularSolverVector.h"
|
||||
#include "src/Core/BandMatrix.h"
|
||||
#include "src/Core/CoreIterators.h"
|
||||
#include "src/Core/ConditionEstimator.h"
|
||||
|
||||
#if defined(EIGEN_VECTORIZE_VSX)
|
||||
#include "src/Core/arch/AltiVec/MatrixProduct.h"
|
||||
#elif defined EIGEN_VECTORIZE_NEON
|
||||
#include "src/Core/arch/NEON/GeneralBlockPanelKernel.h"
|
||||
#elif defined EIGEN_VECTORIZE_LSX
|
||||
#include "src/Core/arch/LSX/GeneralBlockPanelKernel.h"
|
||||
#endif
|
||||
|
||||
#if defined(EIGEN_VECTORIZE_AVX512)
|
||||
#include "src/Core/arch/AVX512/GemmKernel.h"
|
||||
#endif
|
||||
|
||||
#include "src/Core/Select.h"
|
||||
#include "src/Core/VectorwiseOp.h"
|
||||
#include "src/Core/PartialReduxEvaluator.h"
|
||||
#include "src/Core/Random.h"
|
||||
#include "src/Core/Replicate.h"
|
||||
#include "src/Core/Reverse.h"
|
||||
#include "src/Core/ArrayWrapper.h"
|
||||
#include "src/Core/StlIterators.h"
|
||||
|
||||
#ifdef EIGEN_USE_BLAS
|
||||
#include "src/Core/products/GeneralMatrixMatrix_BLAS.h"
|
||||
#include "src/Core/products/GeneralMatrixVector_BLAS.h"
|
||||
#include "src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h"
|
||||
#include "src/Core/products/SelfadjointMatrixMatrix_BLAS.h"
|
||||
#include "src/Core/products/SelfadjointMatrixVector_BLAS.h"
|
||||
#include "src/Core/products/TriangularMatrixMatrix_BLAS.h"
|
||||
#include "src/Core/products/TriangularMatrixVector_BLAS.h"
|
||||
#include "src/Core/products/TriangularSolverMatrix_BLAS.h"
|
||||
#endif // EIGEN_USE_BLAS
|
||||
|
||||
#ifdef EIGEN_USE_MKL_VML
|
||||
#include "src/Core/Assign_MKL.h"
|
||||
#endif
|
||||
|
||||
#include "src/Core/GlobalFunctions.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_CORE_MODULE_H
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "Core"
|
||||
#include "LU"
|
||||
#include "Cholesky"
|
||||
#include "QR"
|
||||
#include "SVD"
|
||||
#include "Geometry"
|
||||
#include "Eigenvalues"
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "Dense"
|
||||
#include "Sparse"
|
||||
@@ -0,0 +1,63 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_EIGENVALUES_MODULE_H
|
||||
#define EIGEN_EIGENVALUES_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#include "Cholesky"
|
||||
#include "Jacobi"
|
||||
#include "Householder"
|
||||
#include "LU"
|
||||
#include "Geometry"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup Eigenvalues_Module Eigenvalues module
|
||||
*
|
||||
*
|
||||
*
|
||||
* This module mainly provides various eigenvalue solvers.
|
||||
* This module also provides some MatrixBase methods, including:
|
||||
* - MatrixBase::eigenvalues(),
|
||||
* - MatrixBase::operatorNorm()
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/Eigenvalues>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
#include "src/misc/RealSvd2x2.h"
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/Eigenvalues/Tridiagonalization.h"
|
||||
#include "src/Eigenvalues/RealSchur.h"
|
||||
#include "src/Eigenvalues/EigenSolver.h"
|
||||
#include "src/Eigenvalues/SelfAdjointEigenSolver.h"
|
||||
#include "src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h"
|
||||
#include "src/Eigenvalues/HessenbergDecomposition.h"
|
||||
#include "src/Eigenvalues/ComplexSchur.h"
|
||||
#include "src/Eigenvalues/ComplexEigenSolver.h"
|
||||
#include "src/Eigenvalues/RealQZ.h"
|
||||
#include "src/Eigenvalues/GeneralizedEigenSolver.h"
|
||||
#include "src/Eigenvalues/MatrixBaseEigenvalues.h"
|
||||
#ifdef EIGEN_USE_LAPACKE
|
||||
#ifdef EIGEN_USE_MKL
|
||||
#include "mkl_lapacke.h"
|
||||
#else
|
||||
#include "src/misc/lapacke.h"
|
||||
#endif
|
||||
#include "src/Eigenvalues/RealSchur_LAPACKE.h"
|
||||
#include "src/Eigenvalues/ComplexSchur_LAPACKE.h"
|
||||
#include "src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h"
|
||||
#endif
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_EIGENVALUES_MODULE_H
|
||||
@@ -0,0 +1,59 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_GEOMETRY_MODULE_H
|
||||
#define EIGEN_GEOMETRY_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#include "SVD"
|
||||
#include "LU"
|
||||
#include <limits>
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup Geometry_Module Geometry module
|
||||
*
|
||||
* This module provides support for:
|
||||
* - fixed-size homogeneous transformations
|
||||
* - translation, scaling, 2D and 3D rotations
|
||||
* - \link Quaternion quaternions \endlink
|
||||
* - cross products (\ref MatrixBase::cross(), \ref MatrixBase::cross3())
|
||||
* - orthogonal vector generation (MatrixBase::unitOrthogonal)
|
||||
* - some linear components: \link ParametrizedLine parametrized-lines \endlink and \link Hyperplane hyperplanes \endlink
|
||||
* - \link AlignedBox axis aligned bounding boxes \endlink
|
||||
* - \link umeyama() least-square transformation fitting \endlink
|
||||
* \code
|
||||
* #include <Eigen/Geometry>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/Geometry/OrthoMethods.h"
|
||||
#include "src/Geometry/EulerAngles.h"
|
||||
#include "src/Geometry/Homogeneous.h"
|
||||
#include "src/Geometry/RotationBase.h"
|
||||
#include "src/Geometry/Rotation2D.h"
|
||||
#include "src/Geometry/Quaternion.h"
|
||||
#include "src/Geometry/AngleAxis.h"
|
||||
#include "src/Geometry/Transform.h"
|
||||
#include "src/Geometry/Translation.h"
|
||||
#include "src/Geometry/Scaling.h"
|
||||
#include "src/Geometry/Hyperplane.h"
|
||||
#include "src/Geometry/ParametrizedLine.h"
|
||||
#include "src/Geometry/AlignedBox.h"
|
||||
#include "src/Geometry/Umeyama.h"
|
||||
|
||||
// Use the SSE optimized version whenever possible.
|
||||
#if (defined EIGEN_VECTORIZE_SSE) || (defined EIGEN_VECTORIZE_NEON)
|
||||
#include "src/Geometry/arch/Geometry_SIMD.h"
|
||||
#endif
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_GEOMETRY_MODULE_H
|
||||
@@ -0,0 +1,31 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_HOUSEHOLDER_MODULE_H
|
||||
#define EIGEN_HOUSEHOLDER_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup Householder_Module Householder module
|
||||
* This module provides Householder transformations.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/Householder>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/Householder/Householder.h"
|
||||
#include "src/Householder/HouseholderSequence.h"
|
||||
#include "src/Householder/BlockHouseholder.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_HOUSEHOLDER_MODULE_H
|
||||
@@ -0,0 +1,52 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
|
||||
#define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
#include "OrderingMethods"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/**
|
||||
* \defgroup IterativeLinearSolvers_Module IterativeLinearSolvers module
|
||||
*
|
||||
* This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a
|
||||
squared matrix, usually very large and sparse.
|
||||
* Those solvers are accessible via the following classes:
|
||||
* - ConjugateGradient for selfadjoint (hermitian) matrices,
|
||||
* - LeastSquaresConjugateGradient for rectangular least-square problems,
|
||||
* - BiCGSTAB for general square matrices.
|
||||
*
|
||||
* These iterative solvers are associated with some preconditioners:
|
||||
* - IdentityPreconditioner - not really useful
|
||||
* - DiagonalPreconditioner - also called Jacobi preconditioner, work very well on diagonal dominant matrices.
|
||||
* - IncompleteLUT - incomplete LU factorization with dual thresholding
|
||||
*
|
||||
* Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport,
|
||||
UmfPackSupport, SuperLUSupport, AccelerateSupport.
|
||||
*
|
||||
\code
|
||||
#include <Eigen/IterativeLinearSolvers>
|
||||
\endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/IterativeLinearSolvers/SolveWithGuess.h"
|
||||
#include "src/IterativeLinearSolvers/IterativeSolverBase.h"
|
||||
#include "src/IterativeLinearSolvers/BasicPreconditioners.h"
|
||||
#include "src/IterativeLinearSolvers/ConjugateGradient.h"
|
||||
#include "src/IterativeLinearSolvers/LeastSquareConjugateGradient.h"
|
||||
#include "src/IterativeLinearSolvers/BiCGSTAB.h"
|
||||
#include "src/IterativeLinearSolvers/IncompleteLUT.h"
|
||||
#include "src/IterativeLinearSolvers/IncompleteCholesky.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
|
||||
@@ -0,0 +1,33 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_JACOBI_MODULE_H
|
||||
#define EIGEN_JACOBI_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup Jacobi_Module Jacobi module
|
||||
* This module provides Jacobi and Givens rotations.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/Jacobi>
|
||||
* \endcode
|
||||
*
|
||||
* In addition to listed classes, it defines the two following MatrixBase methods to apply a Jacobi or Givens rotation:
|
||||
* - MatrixBase::applyOnTheLeft()
|
||||
* - MatrixBase::applyOnTheRight().
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/Jacobi/Jacobi.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_JACOBI_MODULE_H
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_KLUSUPPORT_MODULE_H
|
||||
#define EIGEN_KLUSUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
extern "C" {
|
||||
#include <btf.h>
|
||||
#include <klu.h>
|
||||
}
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup KLUSupport_Module KLUSupport module
|
||||
*
|
||||
* This module provides an interface to the KLU library which is part of the <a
|
||||
* href="http://www.suitesparse.com">suitesparse</a> package. It provides the following factorization class:
|
||||
* - class KLU: a sparse LU factorization, well-suited for circuit simulation.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/KLUSupport>
|
||||
* \endcode
|
||||
*
|
||||
* In order to use this module, the klu and btf headers must be accessible from the include paths, and your binary must
|
||||
* be linked to the klu library and its dependencies. The dependencies depend on how umfpack has been compiled. For a
|
||||
* cmake based project, you can use our FindKLU.cmake module to help you in this task.
|
||||
*
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/KLUSupport/KLUSupport.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_KLUSUPPORT_MODULE_H
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_LU_MODULE_H
|
||||
#define EIGEN_LU_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup LU_Module LU module
|
||||
* This module includes %LU decomposition and related notions such as matrix inversion and determinant.
|
||||
* This module defines the following MatrixBase methods:
|
||||
* - MatrixBase::inverse()
|
||||
* - MatrixBase::determinant()
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/LU>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
#include "src/misc/Kernel.h"
|
||||
#include "src/misc/Image.h"
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/LU/FullPivLU.h"
|
||||
#include "src/LU/PartialPivLU.h"
|
||||
#ifdef EIGEN_USE_LAPACKE
|
||||
#include "src/misc/lapacke_helpers.h"
|
||||
#include "src/LU/PartialPivLU_LAPACKE.h"
|
||||
#endif
|
||||
#include "src/LU/Determinant.h"
|
||||
#include "src/LU/InverseImpl.h"
|
||||
|
||||
#if defined EIGEN_VECTORIZE_SSE || defined EIGEN_VECTORIZE_NEON
|
||||
#include "src/LU/arch/InverseSize4.h"
|
||||
#endif
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_LU_MODULE_H
|
||||
@@ -0,0 +1,35 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_METISSUPPORT_MODULE_H
|
||||
#define EIGEN_METISSUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
extern "C" {
|
||||
#include <metis.h>
|
||||
}
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup MetisSupport_Module MetisSupport module
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/MetisSupport>
|
||||
* \endcode
|
||||
* This module defines an interface to the METIS reordering package (http://glaros.dtc.umn.edu/gkhome/views/metis).
|
||||
* It can be used just as any other built-in method as explained in \link OrderingMethods_Module here. \endlink
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/MetisSupport/MetisSupport.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_METISSUPPORT_MODULE_H
|
||||
@@ -0,0 +1,73 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_ORDERINGMETHODS_MODULE_H
|
||||
#define EIGEN_ORDERINGMETHODS_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/**
|
||||
* \defgroup OrderingMethods_Module OrderingMethods module
|
||||
*
|
||||
* This module is currently for internal use only
|
||||
*
|
||||
* It defines various built-in and external ordering methods for sparse matrices.
|
||||
* They are typically used to reduce the number of elements during
|
||||
* the sparse matrix decomposition (LLT, LU, QR).
|
||||
* Precisely, in a preprocessing step, a permutation matrix P is computed using
|
||||
* those ordering methods and applied to the columns of the matrix.
|
||||
* Using for instance the sparse Cholesky decomposition, it is expected that
|
||||
* the nonzeros elements in LLT(A*P) will be much smaller than that in LLT(A).
|
||||
*
|
||||
*
|
||||
* Usage :
|
||||
* \code
|
||||
* #include <Eigen/OrderingMethods>
|
||||
* \endcode
|
||||
*
|
||||
* A simple usage is as a template parameter in the sparse decomposition classes :
|
||||
*
|
||||
* \code
|
||||
* SparseLU<MatrixType, COLAMDOrdering<int> > solver;
|
||||
* \endcode
|
||||
*
|
||||
* \code
|
||||
* SparseQR<MatrixType, COLAMDOrdering<int> > solver;
|
||||
* \endcode
|
||||
*
|
||||
* It is possible as well to call directly a particular ordering method for your own purpose,
|
||||
* \code
|
||||
* AMDOrdering<int> ordering;
|
||||
* PermutationMatrix<Dynamic, Dynamic, int> perm;
|
||||
* SparseMatrix<double> A;
|
||||
* //Fill the matrix ...
|
||||
*
|
||||
* ordering(A, perm); // Call AMD
|
||||
* \endcode
|
||||
*
|
||||
* \note Some of these methods (like AMD or METIS), need the sparsity pattern
|
||||
* of the input matrix to be symmetric. When the matrix is structurally unsymmetric,
|
||||
* Eigen computes internally the pattern of \f$A^T*A\f$ before calling the method.
|
||||
* If your matrix is already symmetric (at least in structure), you can avoid that
|
||||
* by calling the method with a SelfAdjointView type.
|
||||
*
|
||||
* \code
|
||||
* // Call the ordering on the pattern of the lower triangular matrix A
|
||||
* ordering(A.selfadjointView<Lower>(), perm);
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/OrderingMethods/Amd.h"
|
||||
#include "src/OrderingMethods/Ordering.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_ORDERINGMETHODS_MODULE_H
|
||||
@@ -0,0 +1,51 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_PASTIXSUPPORT_MODULE_H
|
||||
#define EIGEN_PASTIXSUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
extern "C" {
|
||||
#include <pastix_nompi.h>
|
||||
#include <pastix.h>
|
||||
}
|
||||
|
||||
#ifdef complex
|
||||
#undef complex
|
||||
#endif
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup PaStiXSupport_Module PaStiXSupport module
|
||||
*
|
||||
* This module provides an interface to the <a href="http://pastix.gforge.inria.fr/">PaSTiX</a> library.
|
||||
* PaSTiX is a general \b supernodal, \b parallel and \b opensource sparse solver.
|
||||
* It provides the two following main factorization classes:
|
||||
* - class PastixLLT : a supernodal, parallel LLt Cholesky factorization.
|
||||
* - class PastixLDLT: a supernodal, parallel LDLt Cholesky factorization.
|
||||
* - class PastixLU : a supernodal, parallel LU factorization (optimized for a symmetric pattern).
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/PaStiXSupport>
|
||||
* \endcode
|
||||
*
|
||||
* In order to use this module, the PaSTiX headers must be accessible from the include paths, and your binary must be
|
||||
* linked to the PaSTiX library and its dependencies. This wrapper resuires PaStiX version 5.x compiled without MPI
|
||||
* support. The dependencies depend on how PaSTiX has been compiled. For a cmake based project, you can use our
|
||||
* FindPaSTiX.cmake module to help you in this task.
|
||||
*
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/PaStiXSupport/PaStiXSupport.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_PASTIXSUPPORT_MODULE_H
|
||||
@@ -0,0 +1,38 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_PARDISOSUPPORT_MODULE_H
|
||||
#define EIGEN_PARDISOSUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
#include <mkl_pardiso.h>
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup PardisoSupport_Module PardisoSupport module
|
||||
*
|
||||
* This module brings support for the Intel(R) MKL PARDISO direct sparse solvers.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/PardisoSupport>
|
||||
* \endcode
|
||||
*
|
||||
* In order to use this module, the MKL headers must be accessible from the include paths, and your binary must be
|
||||
* linked to the MKL library and its dependencies. See this \ref TopicUsingIntelMKL "page" for more information on
|
||||
* MKL-Eigen integration.
|
||||
*
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/PardisoSupport/PardisoSupport.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_PARDISOSUPPORT_MODULE_H
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_QR_MODULE_H
|
||||
#define EIGEN_QR_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#include "Cholesky"
|
||||
#include "Jacobi"
|
||||
#include "Householder"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup QR_Module QR module
|
||||
*
|
||||
*
|
||||
*
|
||||
* This module provides various QR decompositions
|
||||
* This module also provides some MatrixBase methods, including:
|
||||
* - MatrixBase::householderQr()
|
||||
* - MatrixBase::colPivHouseholderQr()
|
||||
* - MatrixBase::fullPivHouseholderQr()
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/QR>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/QR/HouseholderQR.h"
|
||||
#include "src/QR/FullPivHouseholderQR.h"
|
||||
#include "src/QR/ColPivHouseholderQR.h"
|
||||
#include "src/QR/CompleteOrthogonalDecomposition.h"
|
||||
#ifdef EIGEN_USE_LAPACKE
|
||||
#include "src/misc/lapacke_helpers.h"
|
||||
#include "src/QR/HouseholderQR_LAPACKE.h"
|
||||
#include "src/QR/ColPivHouseholderQR_LAPACKE.h"
|
||||
#endif
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_QR_MODULE_H
|
||||
@@ -0,0 +1,32 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_QTMALLOC_MODULE_H
|
||||
#define EIGEN_QTMALLOC_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#if (!EIGEN_MALLOC_ALREADY_ALIGNED)
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
void *qMalloc(std::size_t size) { return Eigen::internal::aligned_malloc(size); }
|
||||
|
||||
void qFree(void *ptr) { Eigen::internal::aligned_free(ptr); }
|
||||
|
||||
void *qRealloc(void *ptr, std::size_t size) {
|
||||
void *newPtr = Eigen::internal::aligned_malloc(size);
|
||||
std::memcpy(newPtr, ptr, size);
|
||||
Eigen::internal::aligned_free(ptr);
|
||||
return newPtr;
|
||||
}
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_QTMALLOC_MODULE_H
|
||||
@@ -0,0 +1,41 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SPQRSUPPORT_MODULE_H
|
||||
#define EIGEN_SPQRSUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
#include "SuiteSparseQR.hpp"
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup SPQRSupport_Module SuiteSparseQR module
|
||||
*
|
||||
* This module provides an interface to the SPQR library, which is part of the <a
|
||||
* href="http://www.suitesparse.com">suitesparse</a> package.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/SPQRSupport>
|
||||
* \endcode
|
||||
*
|
||||
* In order to use this module, the SPQR headers must be accessible from the include paths, and your binary must be
|
||||
* linked to the SPQR library and its dependencies (Cholmod, AMD, COLAMD,...). For a cmake based project, you can use
|
||||
* our FindSPQR.cmake and FindCholmod.Cmake modules
|
||||
*
|
||||
*/
|
||||
|
||||
#include "CholmodSupport"
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/SPQRSupport/SuiteSparseQRSupport.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SVD_MODULE_H
|
||||
#define EIGEN_SVD_MODULE_H
|
||||
|
||||
#include "QR"
|
||||
#include "Householder"
|
||||
#include "Jacobi"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup SVD_Module SVD module
|
||||
*
|
||||
*
|
||||
*
|
||||
* This module provides SVD decomposition for matrices (both real and complex).
|
||||
* Two decomposition algorithms are provided:
|
||||
* - JacobiSVD implementing two-sided Jacobi iterations is numerically very accurate, fast for small matrices, but very
|
||||
* slow for larger ones.
|
||||
* - BDCSVD implementing a recursive divide & conquer strategy on top of an upper-bidiagonalization which remains fast
|
||||
* for large problems. These decompositions are accessible via the respective classes and following MatrixBase methods:
|
||||
* - MatrixBase::jacobiSvd()
|
||||
* - MatrixBase::bdcSvd()
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/SVD>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/misc/RealSvd2x2.h"
|
||||
#include "src/SVD/UpperBidiagonalization.h"
|
||||
#include "src/SVD/SVDBase.h"
|
||||
#include "src/SVD/JacobiSVD.h"
|
||||
#include "src/SVD/BDCSVD.h"
|
||||
#ifdef EIGEN_USE_LAPACKE
|
||||
#ifdef EIGEN_USE_MKL
|
||||
#include "mkl_lapacke.h"
|
||||
#else
|
||||
#include "src/misc/lapacke.h"
|
||||
#endif
|
||||
#ifndef EIGEN_USE_LAPACKE_STRICT
|
||||
#include "src/SVD/JacobiSVD_LAPACKE.h"
|
||||
#endif
|
||||
#include "src/SVD/BDCSVD_LAPACKE.h"
|
||||
#endif
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_SVD_MODULE_H
|
||||
@@ -0,0 +1,33 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SPARSE_MODULE_H
|
||||
#define EIGEN_SPARSE_MODULE_H
|
||||
|
||||
/** \defgroup Sparse_Module Sparse meta-module
|
||||
*
|
||||
* Meta-module including all related modules:
|
||||
* - \ref SparseCore_Module
|
||||
* - \ref OrderingMethods_Module
|
||||
* - \ref SparseCholesky_Module
|
||||
* - \ref SparseLU_Module
|
||||
* - \ref SparseQR_Module
|
||||
* - \ref IterativeLinearSolvers_Module
|
||||
*
|
||||
\code
|
||||
#include <Eigen/Sparse>
|
||||
\endcode
|
||||
*/
|
||||
|
||||
#include "SparseCore"
|
||||
#include "OrderingMethods"
|
||||
#include "SparseCholesky"
|
||||
#include "SparseLU"
|
||||
#include "SparseQR"
|
||||
#include "IterativeLinearSolvers"
|
||||
|
||||
#endif // EIGEN_SPARSE_MODULE_H
|
||||
@@ -0,0 +1,40 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008-2013 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SPARSECHOLESKY_MODULE_H
|
||||
#define EIGEN_SPARSECHOLESKY_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
#include "OrderingMethods"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/**
|
||||
* \defgroup SparseCholesky_Module SparseCholesky module
|
||||
*
|
||||
* This module currently provides two variants of the direct sparse Cholesky decomposition for selfadjoint (hermitian)
|
||||
* matrices. Those decompositions are accessible via the following classes:
|
||||
* - SimplicialLLt,
|
||||
* - SimplicialLDLt
|
||||
*
|
||||
* Such problems can also be solved using the ConjugateGradient solver from the IterativeLinearSolvers module.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/SparseCholesky>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/SparseCholesky/SimplicialCholesky.h"
|
||||
#include "src/SparseCholesky/SimplicialCholesky_impl.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_SPARSECHOLESKY_MODULE_H
|
||||
@@ -0,0 +1,70 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SPARSECORE_MODULE_H
|
||||
#define EIGEN_SPARSECORE_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
/**
|
||||
* \defgroup SparseCore_Module SparseCore module
|
||||
*
|
||||
* This module provides a sparse matrix representation, and basic associated matrix manipulations
|
||||
* and operations.
|
||||
*
|
||||
* See the \ref TutorialSparse "Sparse tutorial"
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/SparseCore>
|
||||
* \endcode
|
||||
*
|
||||
* This module depends on: Core.
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/SparseCore/SparseUtil.h"
|
||||
#include "src/SparseCore/SparseMatrixBase.h"
|
||||
#include "src/SparseCore/SparseAssign.h"
|
||||
#include "src/SparseCore/CompressedStorage.h"
|
||||
#include "src/SparseCore/AmbiVector.h"
|
||||
#include "src/SparseCore/SparseCompressedBase.h"
|
||||
#include "src/SparseCore/SparseMatrix.h"
|
||||
#include "src/SparseCore/SparseMap.h"
|
||||
#include "src/SparseCore/SparseVector.h"
|
||||
#include "src/SparseCore/SparseRef.h"
|
||||
#include "src/SparseCore/SparseCwiseUnaryOp.h"
|
||||
#include "src/SparseCore/SparseCwiseBinaryOp.h"
|
||||
#include "src/SparseCore/SparseTranspose.h"
|
||||
#include "src/SparseCore/SparseBlock.h"
|
||||
#include "src/SparseCore/SparseDot.h"
|
||||
#include "src/SparseCore/SparseRedux.h"
|
||||
#include "src/SparseCore/SparseView.h"
|
||||
#include "src/SparseCore/SparseDiagonalProduct.h"
|
||||
#include "src/SparseCore/ConservativeSparseSparseProduct.h"
|
||||
#include "src/SparseCore/SparseSparseProductWithPruning.h"
|
||||
#include "src/SparseCore/SparseProduct.h"
|
||||
#include "src/SparseCore/SparseDenseProduct.h"
|
||||
#include "src/SparseCore/SparseSelfAdjointView.h"
|
||||
#include "src/SparseCore/SparseTriangularView.h"
|
||||
#include "src/SparseCore/TriangularSolver.h"
|
||||
#include "src/SparseCore/SparsePermutation.h"
|
||||
#include "src/SparseCore/SparseFuzzy.h"
|
||||
#include "src/SparseCore/SparseSolverBase.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_SPARSECORE_MODULE_H
|
||||
@@ -0,0 +1,50 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
|
||||
// Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SPARSELU_MODULE_H
|
||||
#define EIGEN_SPARSELU_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
/**
|
||||
* \defgroup SparseLU_Module SparseLU module
|
||||
* This module defines a supernodal factorization of general sparse matrices.
|
||||
* The code is fully optimized for supernode-panel updates with specialized kernels.
|
||||
* Please, see the documentation of the SparseLU class for more details.
|
||||
*/
|
||||
|
||||
// Ordering interface
|
||||
#include "OrderingMethods"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/SparseLU/SparseLU_Structs.h"
|
||||
#include "src/SparseLU/SparseLU_SupernodalMatrix.h"
|
||||
#include "src/SparseLU/SparseLUImpl.h"
|
||||
#include "src/SparseCore/SparseColEtree.h"
|
||||
#include "src/SparseLU/SparseLU_Memory.h"
|
||||
#include "src/SparseLU/SparseLU_heap_relax_snode.h"
|
||||
#include "src/SparseLU/SparseLU_relax_snode.h"
|
||||
#include "src/SparseLU/SparseLU_pivotL.h"
|
||||
#include "src/SparseLU/SparseLU_panel_dfs.h"
|
||||
#include "src/SparseLU/SparseLU_kernel_bmod.h"
|
||||
#include "src/SparseLU/SparseLU_panel_bmod.h"
|
||||
#include "src/SparseLU/SparseLU_column_dfs.h"
|
||||
#include "src/SparseLU/SparseLU_column_bmod.h"
|
||||
#include "src/SparseLU/SparseLU_copy_to_ucol.h"
|
||||
#include "src/SparseLU/SparseLU_pruneL.h"
|
||||
#include "src/SparseLU/SparseLU_Utils.h"
|
||||
#include "src/SparseLU/SparseLU.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_SPARSELU_MODULE_H
|
||||
@@ -0,0 +1,38 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SPARSEQR_MODULE_H
|
||||
#define EIGEN_SPARSEQR_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
#include "OrderingMethods"
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup SparseQR_Module SparseQR module
|
||||
* \brief Provides QR decomposition for sparse matrices
|
||||
*
|
||||
* This module provides a simplicial version of the left-looking Sparse QR decomposition.
|
||||
* The columns of the input matrix should be reordered to limit the fill-in during the
|
||||
* decomposition. Built-in methods (COLAMD, AMD) or external methods (METIS) can be used to this end.
|
||||
* See the \link OrderingMethods_Module OrderingMethods\endlink module for the list
|
||||
* of built-in and external ordering methods.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/SparseQR>
|
||||
* \endcode
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/SparseCore/SparseColEtree.h"
|
||||
#include "src/SparseQR/SparseQR.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2009 Hauke Heibel <hauke.heibel@googlemail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_STDDEQUE_MODULE_H
|
||||
#define EIGEN_STDDEQUE_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
#include <deque>
|
||||
|
||||
#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && \
|
||||
(EIGEN_MAX_STATIC_ALIGN_BYTES <= 16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */
|
||||
|
||||
#define EIGEN_DEFINE_STL_DEQUE_SPECIALIZATION(...)
|
||||
|
||||
#else
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/StlSupport/StdDeque.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_STDDEQUE_MODULE_H
|
||||
@@ -0,0 +1,29 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Hauke Heibel <hauke.heibel@googlemail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_STDLIST_MODULE_H
|
||||
#define EIGEN_STDLIST_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
#include <list>
|
||||
|
||||
#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && \
|
||||
(EIGEN_MAX_STATIC_ALIGN_BYTES <= 16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */
|
||||
|
||||
#define EIGEN_DEFINE_STL_LIST_SPECIALIZATION(...)
|
||||
|
||||
#else
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/StlSupport/StdList.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_STDLIST_MODULE_H
|
||||
@@ -0,0 +1,30 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2009 Hauke Heibel <hauke.heibel@googlemail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_STDVECTOR_MODULE_H
|
||||
#define EIGEN_STDVECTOR_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
#include <vector>
|
||||
|
||||
#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && \
|
||||
(EIGEN_MAX_STATIC_ALIGN_BYTES <= 16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */
|
||||
|
||||
#define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...)
|
||||
|
||||
#else
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/StlSupport/StdVector.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_STDVECTOR_MODULE_H
|
||||
@@ -0,0 +1,70 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SUPERLUSUPPORT_MODULE_H
|
||||
#define EIGEN_SUPERLUSUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
#ifdef EMPTY
|
||||
#define EIGEN_EMPTY_WAS_ALREADY_DEFINED
|
||||
#endif
|
||||
|
||||
typedef int int_t;
|
||||
#include <slu_Cnames.h>
|
||||
#include <supermatrix.h>
|
||||
#include <slu_util.h>
|
||||
|
||||
// slu_util.h defines a preprocessor token named EMPTY which is really polluting,
|
||||
// so we remove it in favor of a SUPERLU_EMPTY token.
|
||||
// If EMPTY was already defined then we don't undef it.
|
||||
|
||||
#if defined(EIGEN_EMPTY_WAS_ALREADY_DEFINED)
|
||||
#undef EIGEN_EMPTY_WAS_ALREADY_DEFINED
|
||||
#elif defined(EMPTY)
|
||||
#undef EMPTY
|
||||
#endif
|
||||
|
||||
#define SUPERLU_EMPTY (-1)
|
||||
|
||||
namespace Eigen {
|
||||
struct SluMatrix;
|
||||
}
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup SuperLUSupport_Module SuperLUSupport module
|
||||
*
|
||||
* This module provides an interface to the <a href="http://crd-legacy.lbl.gov/~xiaoye/SuperLU/">SuperLU</a> library.
|
||||
* It provides the following factorization class:
|
||||
* - class SuperLU: a supernodal sequential LU factorization.
|
||||
* - class SuperILU: a supernodal sequential incomplete LU factorization (to be used as a preconditioner for iterative
|
||||
* methods).
|
||||
*
|
||||
* \warning This wrapper requires at least versions 4.0 of SuperLU. The 3.x versions are not supported.
|
||||
*
|
||||
* \warning When including this module, you have to use SUPERLU_EMPTY instead of EMPTY which is no longer defined
|
||||
* because it is too polluting.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/SuperLUSupport>
|
||||
* \endcode
|
||||
*
|
||||
* In order to use this module, the superlu headers must be accessible from the include paths, and your binary must be
|
||||
* linked to the superlu library and its dependencies. The dependencies depend on how superlu has been compiled. For a
|
||||
* cmake based project, you can use our FindSuperLU.cmake module to help you in this task.
|
||||
*
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/SuperLUSupport/SuperLUSupport.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_SUPERLUSUPPORT_MODULE_H
|
||||
@@ -0,0 +1,80 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_THREADPOOL_MODULE_H
|
||||
#define EIGEN_THREADPOOL_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup ThreadPool_Module ThreadPool Module
|
||||
*
|
||||
* This module provides 2 threadpool implementations
|
||||
* - a simple reference implementation
|
||||
* - a faster non blocking implementation
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/ThreadPool>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <time.h>
|
||||
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
// There are non-parenthesized calls to "max" in the <unordered_map> header,
|
||||
// which trigger a check in test/main.h causing compilation to fail.
|
||||
// We work around the check here by removing the check for max in
|
||||
// the case where we have to emulate thread_local.
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
|
||||
#include "src/Core/util/Meta.h"
|
||||
#include "src/Core/util/MaxSizeVector.h"
|
||||
|
||||
#ifndef EIGEN_MUTEX
|
||||
#define EIGEN_MUTEX std::mutex
|
||||
#endif
|
||||
#ifndef EIGEN_MUTEX_LOCK
|
||||
#define EIGEN_MUTEX_LOCK std::unique_lock<std::mutex>
|
||||
#endif
|
||||
#ifndef EIGEN_CONDVAR
|
||||
#define EIGEN_CONDVAR std::condition_variable
|
||||
#endif
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/ThreadPool/ThreadLocal.h"
|
||||
#include "src/ThreadPool/ThreadYield.h"
|
||||
#include "src/ThreadPool/ThreadCancel.h"
|
||||
#include "src/ThreadPool/EventCount.h"
|
||||
#include "src/ThreadPool/RunQueue.h"
|
||||
#include "src/ThreadPool/ThreadPoolInterface.h"
|
||||
#include "src/ThreadPool/ThreadEnvironment.h"
|
||||
#include "src/ThreadPool/Barrier.h"
|
||||
#include "src/ThreadPool/NonBlockingThreadPool.h"
|
||||
#include "src/ThreadPool/CoreThreadPoolDevice.h"
|
||||
#include "src/ThreadPool/ForkJoin.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_MODULE_H
|
||||
@@ -0,0 +1,42 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_UMFPACKSUPPORT_MODULE_H
|
||||
#define EIGEN_UMFPACKSUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
extern "C" {
|
||||
#include <umfpack.h>
|
||||
}
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup UmfPackSupport_Module UmfPackSupport module
|
||||
*
|
||||
* This module provides an interface to the UmfPack library which is part of the <a
|
||||
* href="http://www.suitesparse.com">suitesparse</a> package. It provides the following factorization class:
|
||||
* - class UmfPackLU: a multifrontal sequential LU factorization.
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/UmfPackSupport>
|
||||
* \endcode
|
||||
*
|
||||
* In order to use this module, the umfpack headers must be accessible from the include paths, and your binary must be
|
||||
* linked to the umfpack library and its dependencies. The dependencies depend on how umfpack has been compiled. For a
|
||||
* cmake based project, you can use our FindUmfPack.cmake module to help you in this task.
|
||||
*
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/UmfPackSupport/UmfPackSupport.h"
|
||||
// IWYU pragma: endexports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_UMFPACKSUPPORT_MODULE_H
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef EIGEN_VERSION_H
|
||||
#define EIGEN_VERSION_H
|
||||
|
||||
// The "WORLD" version will forever remain "3" for the "Eigen3" library.
|
||||
#define EIGEN_WORLD_VERSION 3
|
||||
// As of Eigen3 5.0.0, we have moved to Semantic Versioning (semver.org).
|
||||
#define EIGEN_MAJOR_VERSION 5
|
||||
#define EIGEN_MINOR_VERSION 0
|
||||
#define EIGEN_PATCH_VERSION 0
|
||||
#define EIGEN_PRERELEASE_VERSION ""
|
||||
#define EIGEN_BUILD_VERSION ""
|
||||
#define EIGEN_VERSION_STRING "5.0.0"
|
||||
|
||||
#endif // EIGEN_VERSION_H
|
||||
+423
@@ -0,0 +1,423 @@
|
||||
#ifndef EIGEN_ACCELERATESUPPORT_H
|
||||
#define EIGEN_ACCELERATESUPPORT_H
|
||||
|
||||
#include <Accelerate/Accelerate.h>
|
||||
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
class AccelerateImpl;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLLT
|
||||
* \brief A direct Cholesky (LLT) factorization and solver based on Accelerate
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLLT
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLLT = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationCholesky, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLDLT
|
||||
* \brief The default Cholesky (LDLT) factorization and solver based on Accelerate
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLDLT
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLDLT = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLT, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLDLTUnpivoted
|
||||
* \brief A direct Cholesky-like LDL^T factorization and solver based on Accelerate with only 1x1 pivots and no pivoting
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLDLTUnpivoted
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLDLTUnpivoted = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLTUnpivoted, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLDLTSBK
|
||||
* \brief A direct Cholesky (LDLT) factorization and solver based on Accelerate with Supernode Bunch-Kaufman and static
|
||||
* pivoting
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLDLTSBK
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLDLTSBK = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLTSBK, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLDLTTPP
|
||||
* \brief A direct Cholesky (LDLT) factorization and solver based on Accelerate with full threshold partial pivoting
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLDLTTPP
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLDLTTPP = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLTTPP, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateQR
|
||||
* \brief A QR factorization and solver based on Accelerate
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateQR
|
||||
*/
|
||||
template <typename MatrixType>
|
||||
using AccelerateQR = AccelerateImpl<MatrixType, 0, SparseFactorizationQR, false>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateCholeskyAtA
|
||||
* \brief A QR factorization and solver based on Accelerate without storing Q (equivalent to A^TA = R^T R)
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateCholeskyAtA
|
||||
*/
|
||||
template <typename MatrixType>
|
||||
using AccelerateCholeskyAtA = AccelerateImpl<MatrixType, 0, SparseFactorizationCholeskyAtA, false>;
|
||||
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
struct AccelFactorizationDeleter {
|
||||
void operator()(T* sym) {
|
||||
if (sym) {
|
||||
SparseCleanup(*sym);
|
||||
delete sym;
|
||||
sym = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DenseVecT, typename DenseMatT, typename SparseMatT, typename NumFactT>
|
||||
struct SparseTypesTraitBase {
|
||||
typedef DenseVecT AccelDenseVector;
|
||||
typedef DenseMatT AccelDenseMatrix;
|
||||
typedef SparseMatT AccelSparseMatrix;
|
||||
|
||||
typedef SparseOpaqueSymbolicFactorization SymbolicFactorization;
|
||||
typedef NumFactT NumericFactorization;
|
||||
|
||||
typedef AccelFactorizationDeleter<SymbolicFactorization> SymbolicFactorizationDeleter;
|
||||
typedef AccelFactorizationDeleter<NumericFactorization> NumericFactorizationDeleter;
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct SparseTypesTrait {};
|
||||
|
||||
template <>
|
||||
struct SparseTypesTrait<double> : SparseTypesTraitBase<DenseVector_Double, DenseMatrix_Double, SparseMatrix_Double,
|
||||
SparseOpaqueFactorization_Double> {};
|
||||
|
||||
template <>
|
||||
struct SparseTypesTrait<float>
|
||||
: SparseTypesTraitBase<DenseVector_Float, DenseMatrix_Float, SparseMatrix_Float, SparseOpaqueFactorization_Float> {
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
class AccelerateImpl : public SparseSolverBase<AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_> > {
|
||||
protected:
|
||||
using Base = SparseSolverBase<AccelerateImpl>;
|
||||
using Base::derived;
|
||||
using Base::m_isInitialized;
|
||||
|
||||
public:
|
||||
using Base::_solve_impl;
|
||||
|
||||
typedef MatrixType_ MatrixType;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
enum { ColsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic };
|
||||
enum { UpLo = UpLo_ };
|
||||
|
||||
using AccelDenseVector = typename internal::SparseTypesTrait<Scalar>::AccelDenseVector;
|
||||
using AccelDenseMatrix = typename internal::SparseTypesTrait<Scalar>::AccelDenseMatrix;
|
||||
using AccelSparseMatrix = typename internal::SparseTypesTrait<Scalar>::AccelSparseMatrix;
|
||||
using SymbolicFactorization = typename internal::SparseTypesTrait<Scalar>::SymbolicFactorization;
|
||||
using NumericFactorization = typename internal::SparseTypesTrait<Scalar>::NumericFactorization;
|
||||
using SymbolicFactorizationDeleter = typename internal::SparseTypesTrait<Scalar>::SymbolicFactorizationDeleter;
|
||||
using NumericFactorizationDeleter = typename internal::SparseTypesTrait<Scalar>::NumericFactorizationDeleter;
|
||||
|
||||
AccelerateImpl() {
|
||||
m_isInitialized = false;
|
||||
|
||||
auto check_flag_set = [](int value, int flag) { return ((value & flag) == flag); };
|
||||
|
||||
if (check_flag_set(UpLo_, Symmetric)) {
|
||||
m_sparseKind = SparseSymmetric;
|
||||
m_triType = (UpLo_ & Lower) ? SparseLowerTriangle : SparseUpperTriangle;
|
||||
} else if (check_flag_set(UpLo_, UnitLower)) {
|
||||
m_sparseKind = SparseUnitTriangular;
|
||||
m_triType = SparseLowerTriangle;
|
||||
} else if (check_flag_set(UpLo_, UnitUpper)) {
|
||||
m_sparseKind = SparseUnitTriangular;
|
||||
m_triType = SparseUpperTriangle;
|
||||
} else if (check_flag_set(UpLo_, StrictlyLower)) {
|
||||
m_sparseKind = SparseTriangular;
|
||||
m_triType = SparseLowerTriangle;
|
||||
} else if (check_flag_set(UpLo_, StrictlyUpper)) {
|
||||
m_sparseKind = SparseTriangular;
|
||||
m_triType = SparseUpperTriangle;
|
||||
} else if (check_flag_set(UpLo_, Lower)) {
|
||||
m_sparseKind = SparseTriangular;
|
||||
m_triType = SparseLowerTriangle;
|
||||
} else if (check_flag_set(UpLo_, Upper)) {
|
||||
m_sparseKind = SparseTriangular;
|
||||
m_triType = SparseUpperTriangle;
|
||||
} else {
|
||||
m_sparseKind = SparseOrdinary;
|
||||
m_triType = (UpLo_ & Lower) ? SparseLowerTriangle : SparseUpperTriangle;
|
||||
}
|
||||
|
||||
m_order = SparseOrderDefault;
|
||||
}
|
||||
|
||||
explicit AccelerateImpl(const MatrixType& matrix) : AccelerateImpl() { compute(matrix); }
|
||||
|
||||
~AccelerateImpl() {}
|
||||
|
||||
inline Index cols() const { return m_nCols; }
|
||||
inline Index rows() const { return m_nRows; }
|
||||
|
||||
ComputationInfo info() const {
|
||||
eigen_assert(m_isInitialized && "Decomposition is not initialized.");
|
||||
return m_info;
|
||||
}
|
||||
|
||||
void analyzePattern(const MatrixType& matrix);
|
||||
|
||||
void factorize(const MatrixType& matrix);
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
template <typename Rhs, typename Dest>
|
||||
void _solve_impl(const MatrixBase<Rhs>& b, MatrixBase<Dest>& dest) const;
|
||||
|
||||
/** Sets the ordering algorithm to use. */
|
||||
void setOrder(SparseOrder_t order) { m_order = order; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void buildAccelSparseMatrix(const SparseMatrix<T>& a, AccelSparseMatrix& A, std::vector<long>& columnStarts) {
|
||||
const Index nColumnsStarts = a.cols() + 1;
|
||||
|
||||
columnStarts.resize(nColumnsStarts);
|
||||
|
||||
for (Index i = 0; i < nColumnsStarts; i++) columnStarts[i] = a.outerIndexPtr()[i];
|
||||
|
||||
SparseAttributes_t attributes{};
|
||||
attributes.transpose = false;
|
||||
attributes.triangle = m_triType;
|
||||
attributes.kind = m_sparseKind;
|
||||
|
||||
SparseMatrixStructure structure{};
|
||||
structure.attributes = attributes;
|
||||
structure.rowCount = static_cast<int>(a.rows());
|
||||
structure.columnCount = static_cast<int>(a.cols());
|
||||
structure.blockSize = 1;
|
||||
structure.columnStarts = columnStarts.data();
|
||||
structure.rowIndices = const_cast<int*>(a.innerIndexPtr());
|
||||
|
||||
A.structure = structure;
|
||||
A.data = const_cast<T*>(a.valuePtr());
|
||||
}
|
||||
|
||||
void doAnalysis(AccelSparseMatrix& A) {
|
||||
m_numericFactorization.reset(nullptr);
|
||||
|
||||
SparseSymbolicFactorOptions opts{};
|
||||
opts.control = SparseDefaultControl;
|
||||
opts.orderMethod = m_order;
|
||||
opts.order = nullptr;
|
||||
opts.ignoreRowsAndColumns = nullptr;
|
||||
opts.malloc = malloc;
|
||||
opts.free = free;
|
||||
opts.reportError = nullptr;
|
||||
|
||||
m_symbolicFactorization.reset(new SymbolicFactorization(SparseFactor(Solver_, A.structure, opts)));
|
||||
|
||||
SparseStatus_t status = m_symbolicFactorization->status;
|
||||
|
||||
updateInfoStatus(status);
|
||||
|
||||
if (status != SparseStatusOK) m_symbolicFactorization.reset(nullptr);
|
||||
}
|
||||
|
||||
void doFactorization(AccelSparseMatrix& A) {
|
||||
SparseStatus_t status = SparseStatusReleased;
|
||||
|
||||
if (m_symbolicFactorization) {
|
||||
m_numericFactorization.reset(new NumericFactorization(SparseFactor(*m_symbolicFactorization, A)));
|
||||
|
||||
status = m_numericFactorization->status;
|
||||
|
||||
if (status != SparseStatusOK) m_numericFactorization.reset(nullptr);
|
||||
}
|
||||
|
||||
updateInfoStatus(status);
|
||||
}
|
||||
|
||||
protected:
|
||||
void updateInfoStatus(SparseStatus_t status) const {
|
||||
switch (status) {
|
||||
case SparseStatusOK:
|
||||
m_info = Success;
|
||||
break;
|
||||
case SparseFactorizationFailed:
|
||||
case SparseMatrixIsSingular:
|
||||
m_info = NumericalIssue;
|
||||
break;
|
||||
case SparseInternalError:
|
||||
case SparseParameterError:
|
||||
case SparseStatusReleased:
|
||||
default:
|
||||
m_info = InvalidInput;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutable ComputationInfo m_info;
|
||||
Index m_nRows, m_nCols;
|
||||
std::unique_ptr<SymbolicFactorization, SymbolicFactorizationDeleter> m_symbolicFactorization;
|
||||
std::unique_ptr<NumericFactorization, NumericFactorizationDeleter> m_numericFactorization;
|
||||
SparseKind_t m_sparseKind;
|
||||
SparseTriangle_t m_triType;
|
||||
SparseOrder_t m_order;
|
||||
};
|
||||
|
||||
/** Computes the symbolic and numeric decomposition of matrix \a a */
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::compute(const MatrixType& a) {
|
||||
if (EnforceSquare_) eigen_assert(a.rows() == a.cols());
|
||||
|
||||
m_nRows = a.rows();
|
||||
m_nCols = a.cols();
|
||||
|
||||
AccelSparseMatrix A{};
|
||||
std::vector<long> columnStarts;
|
||||
|
||||
buildAccelSparseMatrix(a, A, columnStarts);
|
||||
|
||||
doAnalysis(A);
|
||||
|
||||
if (m_symbolicFactorization) doFactorization(A);
|
||||
|
||||
m_isInitialized = true;
|
||||
}
|
||||
|
||||
/** Performs a symbolic decomposition on the sparsity pattern of matrix \a a.
|
||||
*
|
||||
* This function is particularly useful when solving for several problems having the same structure.
|
||||
*
|
||||
* \sa factorize()
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::analyzePattern(const MatrixType& a) {
|
||||
if (EnforceSquare_) eigen_assert(a.rows() == a.cols());
|
||||
|
||||
m_nRows = a.rows();
|
||||
m_nCols = a.cols();
|
||||
|
||||
AccelSparseMatrix A{};
|
||||
std::vector<long> columnStarts;
|
||||
|
||||
buildAccelSparseMatrix(a, A, columnStarts);
|
||||
|
||||
doAnalysis(A);
|
||||
|
||||
m_isInitialized = true;
|
||||
}
|
||||
|
||||
/** Performs a numeric decomposition of matrix \a a.
|
||||
*
|
||||
* The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been
|
||||
* performed.
|
||||
*
|
||||
* \sa analyzePattern()
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::factorize(const MatrixType& a) {
|
||||
eigen_assert(m_symbolicFactorization && "You must first call analyzePattern()");
|
||||
eigen_assert(m_nRows == a.rows() && m_nCols == a.cols());
|
||||
|
||||
if (EnforceSquare_) eigen_assert(a.rows() == a.cols());
|
||||
|
||||
AccelSparseMatrix A{};
|
||||
std::vector<long> columnStarts;
|
||||
|
||||
buildAccelSparseMatrix(a, A, columnStarts);
|
||||
|
||||
doFactorization(A);
|
||||
}
|
||||
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
template <typename Rhs, typename Dest>
|
||||
void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::_solve_impl(const MatrixBase<Rhs>& b,
|
||||
MatrixBase<Dest>& x) const {
|
||||
if (!m_numericFactorization) {
|
||||
m_info = InvalidInput;
|
||||
return;
|
||||
}
|
||||
|
||||
eigen_assert(m_nRows == b.rows());
|
||||
eigen_assert(((b.cols() == 1) || b.outerStride() == b.rows()));
|
||||
|
||||
SparseStatus_t status = SparseStatusOK;
|
||||
|
||||
Scalar* b_ptr = const_cast<Scalar*>(b.derived().data());
|
||||
Scalar* x_ptr = const_cast<Scalar*>(x.derived().data());
|
||||
|
||||
AccelDenseMatrix xmat{};
|
||||
xmat.attributes = SparseAttributes_t();
|
||||
xmat.columnCount = static_cast<int>(x.cols());
|
||||
xmat.rowCount = static_cast<int>(x.rows());
|
||||
xmat.columnStride = xmat.rowCount;
|
||||
xmat.data = x_ptr;
|
||||
|
||||
AccelDenseMatrix bmat{};
|
||||
bmat.attributes = SparseAttributes_t();
|
||||
bmat.columnCount = static_cast<int>(b.cols());
|
||||
bmat.rowCount = static_cast<int>(b.rows());
|
||||
bmat.columnStride = bmat.rowCount;
|
||||
bmat.data = b_ptr;
|
||||
|
||||
SparseSolve(*m_numericFactorization, bmat, xmat);
|
||||
|
||||
updateInfoStatus(status);
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_ACCELERATESUPPORT_H
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_ACCELERATESUPPORT_MODULE_H
|
||||
#error "Please include Eigen/AccelerateSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_CHOLESKY_MODULE_H
|
||||
#error "Please include Eigen/Cholesky instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,649 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2009 Keir Mierle <mierle@gmail.com>
|
||||
// Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2011 Timothy E. Holy <tim.holy@gmail.com >
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_LDLT_H
|
||||
#define EIGEN_LDLT_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
template <typename MatrixType_, int UpLo_>
|
||||
struct traits<LDLT<MatrixType_, UpLo_> > : traits<MatrixType_> {
|
||||
typedef MatrixXpr XprKind;
|
||||
typedef SolverStorage StorageKind;
|
||||
typedef int StorageIndex;
|
||||
enum { Flags = 0 };
|
||||
};
|
||||
|
||||
template <typename MatrixType, int UpLo>
|
||||
struct LDLT_Traits;
|
||||
|
||||
// PositiveSemiDef means positive semi-definite and non-zero; same for NegativeSemiDef
|
||||
enum SignMatrix { PositiveSemiDef, NegativeSemiDef, ZeroSign, Indefinite };
|
||||
} // namespace internal
|
||||
|
||||
/** \ingroup Cholesky_Module
|
||||
*
|
||||
* \class LDLT
|
||||
*
|
||||
* \brief Robust Cholesky decomposition of a matrix with pivoting
|
||||
*
|
||||
* \tparam MatrixType_ the type of the matrix of which to compute the LDL^T Cholesky decomposition
|
||||
* \tparam UpLo_ the triangular part that will be used for the decomposition: Lower (default) or Upper.
|
||||
* The other triangular part won't be read.
|
||||
*
|
||||
* Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite
|
||||
* matrix \f$ A \f$ such that \f$ A = P^TLDL^*P \f$, where P is a permutation matrix, L
|
||||
* is lower triangular with a unit diagonal and D is a diagonal matrix.
|
||||
*
|
||||
* The decomposition uses pivoting to ensure stability, so that D will have
|
||||
* zeros in the bottom right rank(A) - n submatrix. Avoiding the square root
|
||||
* on D also stabilizes the computation.
|
||||
*
|
||||
* Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky
|
||||
* decomposition to determine whether a system of equations has a solution.
|
||||
*
|
||||
* This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism.
|
||||
*
|
||||
* \sa MatrixBase::ldlt(), SelfAdjointView::ldlt(), class LLT
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_>
|
||||
class LDLT : public SolverBase<LDLT<MatrixType_, UpLo_> > {
|
||||
public:
|
||||
typedef MatrixType_ MatrixType;
|
||||
typedef SolverBase<LDLT> Base;
|
||||
friend class SolverBase<LDLT>;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(LDLT)
|
||||
enum {
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
|
||||
UpLo = UpLo_
|
||||
};
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, 1, 0, MaxRowsAtCompileTime, 1> TmpMatrixType;
|
||||
|
||||
typedef Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime> TranspositionType;
|
||||
typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationType;
|
||||
|
||||
typedef internal::LDLT_Traits<MatrixType, UpLo> Traits;
|
||||
|
||||
/** \brief Default Constructor.
|
||||
*
|
||||
* The default constructor is useful in cases in which the user intends to
|
||||
* perform decompositions via LDLT::compute(const MatrixType&).
|
||||
*/
|
||||
LDLT() : m_matrix(), m_transpositions(), m_sign(internal::ZeroSign), m_isInitialized(false) {}
|
||||
|
||||
/** \brief Default Constructor with memory preallocation
|
||||
*
|
||||
* Like the default constructor but with preallocation of the internal data
|
||||
* according to the specified problem \a size.
|
||||
* \sa LDLT()
|
||||
*/
|
||||
explicit LDLT(Index size)
|
||||
: m_matrix(size, size),
|
||||
m_transpositions(size),
|
||||
m_temporary(size),
|
||||
m_sign(internal::ZeroSign),
|
||||
m_isInitialized(false) {}
|
||||
|
||||
/** \brief Constructor with decomposition
|
||||
*
|
||||
* This calculates the decomposition for the input \a matrix.
|
||||
*
|
||||
* \sa LDLT(Index size)
|
||||
*/
|
||||
template <typename InputType>
|
||||
explicit LDLT(const EigenBase<InputType>& matrix)
|
||||
: m_matrix(matrix.rows(), matrix.cols()),
|
||||
m_transpositions(matrix.rows()),
|
||||
m_temporary(matrix.rows()),
|
||||
m_sign(internal::ZeroSign),
|
||||
m_isInitialized(false) {
|
||||
compute(matrix.derived());
|
||||
}
|
||||
|
||||
/** \brief Constructs a LDLT factorization from a given matrix
|
||||
*
|
||||
* This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when \c
|
||||
* MatrixType is a Eigen::Ref.
|
||||
*
|
||||
* \sa LDLT(const EigenBase&)
|
||||
*/
|
||||
template <typename InputType>
|
||||
explicit LDLT(EigenBase<InputType>& matrix)
|
||||
: m_matrix(matrix.derived()),
|
||||
m_transpositions(matrix.rows()),
|
||||
m_temporary(matrix.rows()),
|
||||
m_sign(internal::ZeroSign),
|
||||
m_isInitialized(false) {
|
||||
compute(matrix.derived());
|
||||
}
|
||||
|
||||
/** Clear any existing decomposition
|
||||
* \sa rankUpdate(w,sigma)
|
||||
*/
|
||||
void setZero() { m_isInitialized = false; }
|
||||
|
||||
/** \returns a view of the upper triangular matrix U */
|
||||
inline typename Traits::MatrixU matrixU() const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
return Traits::getU(m_matrix);
|
||||
}
|
||||
|
||||
/** \returns a view of the lower triangular matrix L */
|
||||
inline typename Traits::MatrixL matrixL() const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
return Traits::getL(m_matrix);
|
||||
}
|
||||
|
||||
/** \returns the permutation matrix P as a transposition sequence.
|
||||
*/
|
||||
inline const TranspositionType& transpositionsP() const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
return m_transpositions;
|
||||
}
|
||||
|
||||
/** \returns the coefficients of the diagonal matrix D */
|
||||
inline Diagonal<const MatrixType> vectorD() const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
return m_matrix.diagonal();
|
||||
}
|
||||
|
||||
/** \returns true if the matrix is positive (semidefinite) */
|
||||
inline bool isPositive() const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign;
|
||||
}
|
||||
|
||||
/** \returns true if the matrix is negative (semidefinite) */
|
||||
inline bool isNegative(void) const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign;
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A.
|
||||
*
|
||||
* This function also supports in-place solves using the syntax <tt>x = decompositionObject.solve(x)</tt> .
|
||||
*
|
||||
* \note_about_checking_solutions
|
||||
*
|
||||
* More precisely, this method solves \f$ A x = b \f$ using the decomposition \f$ A = P^T L D L^* P \f$
|
||||
* by solving the systems \f$ P^T y_1 = b \f$, \f$ L y_2 = y_1 \f$, \f$ D y_3 = y_2 \f$,
|
||||
* \f$ L^* y_4 = y_3 \f$ and \f$ P x = y_4 \f$ in succession. If the matrix \f$ A \f$ is singular, then
|
||||
* \f$ D \f$ will also be singular (all the other matrices are invertible). In that case, the
|
||||
* least-square solution of \f$ D y_3 = y_2 \f$ is computed. This does not mean that this function
|
||||
* computes the least-square solution of \f$ A x = b \f$ if \f$ A \f$ is singular.
|
||||
*
|
||||
* \sa MatrixBase::ldlt(), SelfAdjointView::ldlt()
|
||||
*/
|
||||
template <typename Rhs>
|
||||
inline const Solve<LDLT, Rhs> solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
template <typename Derived>
|
||||
bool solveInPlace(MatrixBase<Derived>& bAndX) const;
|
||||
|
||||
template <typename InputType>
|
||||
LDLT& compute(const EigenBase<InputType>& matrix);
|
||||
|
||||
/** \returns an estimate of the reciprocal condition number of the matrix of
|
||||
* which \c *this is the LDLT decomposition.
|
||||
*/
|
||||
RealScalar rcond() const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
return internal::rcond_estimate_helper(m_l1_norm, *this);
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
LDLT& rankUpdate(const MatrixBase<Derived>& w, const RealScalar& alpha = 1);
|
||||
|
||||
/** \returns the internal LDLT decomposition matrix
|
||||
*
|
||||
* TODO: document the storage layout
|
||||
*/
|
||||
inline const MatrixType& matrixLDLT() const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
MatrixType reconstructedMatrix() const;
|
||||
|
||||
/** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix
|
||||
* is self-adjoint.
|
||||
*
|
||||
* This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as:
|
||||
* \code x = decomposition.adjoint().solve(b) \endcode
|
||||
*/
|
||||
const LDLT& adjoint() const { return *this; }
|
||||
|
||||
EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return m_matrix.rows(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index cols() const noexcept { return m_matrix.cols(); }
|
||||
|
||||
/** \brief Reports whether previous computation was successful.
|
||||
*
|
||||
* \returns \c Success if computation was successful,
|
||||
* \c NumericalIssue if the factorization failed because of a zero pivot.
|
||||
*/
|
||||
ComputationInfo info() const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
return m_info;
|
||||
}
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template <typename RhsType, typename DstType>
|
||||
void _solve_impl(const RhsType& rhs, DstType& dst) const;
|
||||
|
||||
template <bool Conjugate, typename RhsType, typename DstType>
|
||||
void _solve_impl_transposed(const RhsType& rhs, DstType& dst) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
|
||||
|
||||
/** \internal
|
||||
* Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U.
|
||||
* The strict upper part is used during the decomposition, the strict lower
|
||||
* part correspond to the coefficients of L (its diagonal is equal to 1 and
|
||||
* is not stored), and the diagonal entries correspond to D.
|
||||
*/
|
||||
MatrixType m_matrix;
|
||||
RealScalar m_l1_norm;
|
||||
TranspositionType m_transpositions;
|
||||
TmpMatrixType m_temporary;
|
||||
internal::SignMatrix m_sign;
|
||||
bool m_isInitialized;
|
||||
ComputationInfo m_info;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <int UpLo>
|
||||
struct ldlt_inplace;
|
||||
|
||||
template <>
|
||||
struct ldlt_inplace<Lower> {
|
||||
template <typename MatrixType, typename TranspositionType, typename Workspace>
|
||||
static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, SignMatrix& sign) {
|
||||
using std::abs;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename TranspositionType::StorageIndex IndexType;
|
||||
eigen_assert(mat.rows() == mat.cols());
|
||||
const Index size = mat.rows();
|
||||
bool found_zero_pivot = false;
|
||||
bool ret = true;
|
||||
|
||||
if (size <= 1) {
|
||||
transpositions.setIdentity();
|
||||
if (size == 0)
|
||||
sign = ZeroSign;
|
||||
else if (numext::real(mat.coeff(0, 0)) > static_cast<RealScalar>(0))
|
||||
sign = PositiveSemiDef;
|
||||
else if (numext::real(mat.coeff(0, 0)) < static_cast<RealScalar>(0))
|
||||
sign = NegativeSemiDef;
|
||||
else
|
||||
sign = ZeroSign;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (Index k = 0; k < size; ++k) {
|
||||
// Find largest diagonal element
|
||||
Index index_of_biggest_in_corner;
|
||||
mat.diagonal().tail(size - k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner);
|
||||
index_of_biggest_in_corner += k;
|
||||
|
||||
transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner);
|
||||
if (k != index_of_biggest_in_corner) {
|
||||
// apply the transposition while taking care to consider only
|
||||
// the lower triangular part
|
||||
Index s = size - index_of_biggest_in_corner - 1; // trailing size after the biggest element
|
||||
mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k));
|
||||
mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s));
|
||||
std::swap(mat.coeffRef(k, k), mat.coeffRef(index_of_biggest_in_corner, index_of_biggest_in_corner));
|
||||
for (Index i = k + 1; i < index_of_biggest_in_corner; ++i) {
|
||||
Scalar tmp = mat.coeffRef(i, k);
|
||||
mat.coeffRef(i, k) = numext::conj(mat.coeffRef(index_of_biggest_in_corner, i));
|
||||
mat.coeffRef(index_of_biggest_in_corner, i) = numext::conj(tmp);
|
||||
}
|
||||
if (NumTraits<Scalar>::IsComplex)
|
||||
mat.coeffRef(index_of_biggest_in_corner, k) = numext::conj(mat.coeff(index_of_biggest_in_corner, k));
|
||||
}
|
||||
|
||||
// partition the matrix:
|
||||
// A00 | - | -
|
||||
// lu = A10 | A11 | -
|
||||
// A20 | A21 | A22
|
||||
Index rs = size - k - 1;
|
||||
Block<MatrixType, Dynamic, 1> A21(mat, k + 1, k, rs, 1);
|
||||
Block<MatrixType, 1, Dynamic> A10(mat, k, 0, 1, k);
|
||||
Block<MatrixType, Dynamic, Dynamic> A20(mat, k + 1, 0, rs, k);
|
||||
|
||||
if (k > 0) {
|
||||
temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint();
|
||||
mat.coeffRef(k, k) -= (A10 * temp.head(k)).value();
|
||||
if (rs > 0) A21.noalias() -= A20 * temp.head(k);
|
||||
}
|
||||
|
||||
// In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot
|
||||
// was smaller than the cutoff value. However, since LDLT is not rank-revealing
|
||||
// we should only make sure that we do not introduce INF or NaN values.
|
||||
// Remark that LAPACK also uses 0 as the cutoff value.
|
||||
RealScalar realAkk = numext::real(mat.coeffRef(k, k));
|
||||
bool pivot_is_valid = (abs(realAkk) > RealScalar(0));
|
||||
|
||||
if (k == 0 && !pivot_is_valid) {
|
||||
// The entire diagonal is zero, there is nothing more to do
|
||||
// except filling the transpositions, and checking whether the matrix is zero.
|
||||
sign = ZeroSign;
|
||||
for (Index j = 0; j < size; ++j) {
|
||||
transpositions.coeffRef(j) = IndexType(j);
|
||||
ret = ret && (mat.col(j).tail(size - j - 1).array() == Scalar(0)).all();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((rs > 0) && pivot_is_valid)
|
||||
A21 /= realAkk;
|
||||
else if (rs > 0)
|
||||
ret = ret && (A21.array() == Scalar(0)).all();
|
||||
|
||||
if (found_zero_pivot && pivot_is_valid)
|
||||
ret = false; // factorization failed
|
||||
else if (!pivot_is_valid)
|
||||
found_zero_pivot = true;
|
||||
|
||||
if (sign == PositiveSemiDef) {
|
||||
if (realAkk < static_cast<RealScalar>(0)) sign = Indefinite;
|
||||
} else if (sign == NegativeSemiDef) {
|
||||
if (realAkk > static_cast<RealScalar>(0)) sign = Indefinite;
|
||||
} else if (sign == ZeroSign) {
|
||||
if (realAkk > static_cast<RealScalar>(0))
|
||||
sign = PositiveSemiDef;
|
||||
else if (realAkk < static_cast<RealScalar>(0))
|
||||
sign = NegativeSemiDef;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Reference for the algorithm: Davis and Hager, "Multiple Rank
|
||||
// Modifications of a Sparse Cholesky Factorization" (Algorithm 1)
|
||||
// Trivial rearrangements of their computations (Timothy E. Holy)
|
||||
// allow their algorithm to work for rank-1 updates even if the
|
||||
// original matrix is not of full rank.
|
||||
// Here only rank-1 updates are implemented, to reduce the
|
||||
// requirement for intermediate storage and improve accuracy
|
||||
template <typename MatrixType, typename WDerived>
|
||||
static bool updateInPlace(MatrixType& mat, MatrixBase<WDerived>& w,
|
||||
const typename MatrixType::RealScalar& sigma = 1) {
|
||||
using numext::isfinite;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
|
||||
const Index size = mat.rows();
|
||||
eigen_assert(mat.cols() == size && w.size() == size);
|
||||
|
||||
RealScalar alpha = 1;
|
||||
|
||||
// Apply the update
|
||||
for (Index j = 0; j < size; j++) {
|
||||
// Check for termination due to an original decomposition of low-rank
|
||||
if (!(isfinite)(alpha)) break;
|
||||
|
||||
// Update the diagonal terms
|
||||
RealScalar dj = numext::real(mat.coeff(j, j));
|
||||
Scalar wj = w.coeff(j);
|
||||
RealScalar swj2 = sigma * numext::abs2(wj);
|
||||
RealScalar gamma = dj * alpha + swj2;
|
||||
|
||||
mat.coeffRef(j, j) += swj2 / alpha;
|
||||
alpha += swj2 / dj;
|
||||
|
||||
// Update the terms of L
|
||||
Index rs = size - j - 1;
|
||||
w.tail(rs) -= wj * mat.col(j).tail(rs);
|
||||
if (!numext::is_exactly_zero(gamma)) mat.col(j).tail(rs) += (sigma * numext::conj(wj) / gamma) * w.tail(rs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename MatrixType, typename TranspositionType, typename Workspace, typename WType>
|
||||
static bool update(MatrixType& mat, const TranspositionType& transpositions, Workspace& tmp, const WType& w,
|
||||
const typename MatrixType::RealScalar& sigma = 1) {
|
||||
// Apply the permutation to the input w
|
||||
tmp = transpositions * w;
|
||||
|
||||
return ldlt_inplace<Lower>::updateInPlace(mat, tmp, sigma);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ldlt_inplace<Upper> {
|
||||
template <typename MatrixType, typename TranspositionType, typename Workspace>
|
||||
static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp,
|
||||
SignMatrix& sign) {
|
||||
Transpose<MatrixType> matt(mat);
|
||||
return ldlt_inplace<Lower>::unblocked(matt, transpositions, temp, sign);
|
||||
}
|
||||
|
||||
template <typename MatrixType, typename TranspositionType, typename Workspace, typename WType>
|
||||
static EIGEN_STRONG_INLINE bool update(MatrixType& mat, TranspositionType& transpositions, Workspace& tmp, WType& w,
|
||||
const typename MatrixType::RealScalar& sigma = 1) {
|
||||
Transpose<MatrixType> matt(mat);
|
||||
return ldlt_inplace<Lower>::update(matt, transpositions, tmp, w.conjugate(), sigma);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename MatrixType>
|
||||
struct LDLT_Traits<MatrixType, Lower> {
|
||||
typedef const TriangularView<const MatrixType, UnitLower> MatrixL;
|
||||
typedef const TriangularView<const typename MatrixType::AdjointReturnType, UnitUpper> MatrixU;
|
||||
static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); }
|
||||
static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); }
|
||||
};
|
||||
|
||||
template <typename MatrixType>
|
||||
struct LDLT_Traits<MatrixType, Upper> {
|
||||
typedef const TriangularView<const typename MatrixType::AdjointReturnType, UnitLower> MatrixL;
|
||||
typedef const TriangularView<const MatrixType, UnitUpper> MatrixU;
|
||||
static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); }
|
||||
static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); }
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
/** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix
|
||||
*/
|
||||
template <typename MatrixType, int UpLo_>
|
||||
template <typename InputType>
|
||||
LDLT<MatrixType, UpLo_>& LDLT<MatrixType, UpLo_>::compute(const EigenBase<InputType>& a) {
|
||||
eigen_assert(a.rows() == a.cols());
|
||||
const Index size = a.rows();
|
||||
|
||||
m_matrix = a.derived();
|
||||
|
||||
// Compute matrix L1 norm = max abs column sum.
|
||||
m_l1_norm = RealScalar(0);
|
||||
// TODO move this code to SelfAdjointView
|
||||
for (Index col = 0; col < size; ++col) {
|
||||
RealScalar abs_col_sum;
|
||||
if (UpLo_ == Lower)
|
||||
abs_col_sum =
|
||||
m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>();
|
||||
else
|
||||
abs_col_sum =
|
||||
m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>();
|
||||
if (abs_col_sum > m_l1_norm) m_l1_norm = abs_col_sum;
|
||||
}
|
||||
|
||||
m_transpositions.resize(size);
|
||||
m_isInitialized = false;
|
||||
m_temporary.resize(size);
|
||||
m_sign = internal::ZeroSign;
|
||||
|
||||
m_info = internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign) ? Success
|
||||
: NumericalIssue;
|
||||
|
||||
m_isInitialized = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Update the LDLT decomposition: given A = L D L^T, efficiently compute the decomposition of A + sigma w w^T.
|
||||
* \param w a vector to be incorporated into the decomposition.
|
||||
* \param sigma a scalar, +1 for updates and -1 for "downdates," which correspond to removing previously-added column
|
||||
* vectors. Optional; default value is +1. \sa setZero()
|
||||
*/
|
||||
template <typename MatrixType, int UpLo_>
|
||||
template <typename Derived>
|
||||
LDLT<MatrixType, UpLo_>& LDLT<MatrixType, UpLo_>::rankUpdate(
|
||||
const MatrixBase<Derived>& w, const typename LDLT<MatrixType, UpLo_>::RealScalar& sigma) {
|
||||
typedef typename TranspositionType::StorageIndex IndexType;
|
||||
const Index size = w.rows();
|
||||
if (m_isInitialized) {
|
||||
eigen_assert(m_matrix.rows() == size);
|
||||
} else {
|
||||
m_matrix.resize(size, size);
|
||||
m_matrix.setZero();
|
||||
m_transpositions.resize(size);
|
||||
for (Index i = 0; i < size; i++) m_transpositions.coeffRef(i) = IndexType(i);
|
||||
m_temporary.resize(size);
|
||||
m_sign = sigma >= 0 ? internal::PositiveSemiDef : internal::NegativeSemiDef;
|
||||
m_isInitialized = true;
|
||||
}
|
||||
|
||||
internal::ldlt_inplace<UpLo>::update(m_matrix, m_transpositions, m_temporary, w, sigma);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template <typename MatrixType_, int UpLo_>
|
||||
template <typename RhsType, typename DstType>
|
||||
void LDLT<MatrixType_, UpLo_>::_solve_impl(const RhsType& rhs, DstType& dst) const {
|
||||
_solve_impl_transposed<true>(rhs, dst);
|
||||
}
|
||||
|
||||
template <typename MatrixType_, int UpLo_>
|
||||
template <bool Conjugate, typename RhsType, typename DstType>
|
||||
void LDLT<MatrixType_, UpLo_>::_solve_impl_transposed(const RhsType& rhs, DstType& dst) const {
|
||||
// dst = P b
|
||||
dst = m_transpositions * rhs;
|
||||
|
||||
// dst = L^-1 (P b)
|
||||
// dst = L^-*T (P b)
|
||||
matrixL().template conjugateIf<!Conjugate>().solveInPlace(dst);
|
||||
|
||||
// dst = D^-* (L^-1 P b)
|
||||
// dst = D^-1 (L^-*T P b)
|
||||
// more precisely, use pseudo-inverse of D (see bug 241)
|
||||
using std::abs;
|
||||
const typename Diagonal<const MatrixType>::RealReturnType vecD(vectorD());
|
||||
// In some previous versions, tolerance was set to the max of 1/highest (or rather numeric_limits::min())
|
||||
// and the maximal diagonal entry * epsilon as motivated by LAPACK's xGELSS:
|
||||
// RealScalar tolerance = numext::maxi(vecD.array().abs().maxCoeff() * NumTraits<RealScalar>::epsilon(),RealScalar(1)
|
||||
// / NumTraits<RealScalar>::highest()); However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the
|
||||
// highest diagonal element is not well justified and leads to numerical issues in some cases. Moreover, Lapack's
|
||||
// xSYTRS routines use 0 for the tolerance. Using numeric_limits::min() gives us more robustness to denormals.
|
||||
RealScalar tolerance = (std::numeric_limits<RealScalar>::min)();
|
||||
for (Index i = 0; i < vecD.size(); ++i) {
|
||||
if (abs(vecD(i)) > tolerance)
|
||||
dst.row(i) /= vecD(i);
|
||||
else
|
||||
dst.row(i).setZero();
|
||||
}
|
||||
|
||||
// dst = L^-* (D^-* L^-1 P b)
|
||||
// dst = L^-T (D^-1 L^-*T P b)
|
||||
matrixL().transpose().template conjugateIf<Conjugate>().solveInPlace(dst);
|
||||
|
||||
// dst = P^T (L^-* D^-* L^-1 P b) = A^-1 b
|
||||
// dst = P^-T (L^-T D^-1 L^-*T P b) = A^-1 b
|
||||
dst = m_transpositions.transpose() * dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \internal use x = ldlt_object.solve(x);
|
||||
*
|
||||
* This is the \em in-place version of solve().
|
||||
*
|
||||
* \param bAndX represents both the right-hand side matrix b and result x.
|
||||
*
|
||||
* \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD.
|
||||
*
|
||||
* This version avoids a copy when the right hand side matrix b is not
|
||||
* needed anymore.
|
||||
*
|
||||
* \sa LDLT::solve(), MatrixBase::ldlt()
|
||||
*/
|
||||
template <typename MatrixType, int UpLo_>
|
||||
template <typename Derived>
|
||||
bool LDLT<MatrixType, UpLo_>::solveInPlace(MatrixBase<Derived>& bAndX) const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
eigen_assert(m_matrix.rows() == bAndX.rows());
|
||||
|
||||
bAndX = this->solve(bAndX);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \returns the matrix represented by the decomposition,
|
||||
* i.e., it returns the product: P^T L D L^* P.
|
||||
* This function is provided for debug purpose. */
|
||||
template <typename MatrixType, int UpLo_>
|
||||
MatrixType LDLT<MatrixType, UpLo_>::reconstructedMatrix() const {
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
const Index size = m_matrix.rows();
|
||||
MatrixType res(size, size);
|
||||
|
||||
// P
|
||||
res.setIdentity();
|
||||
res = transpositionsP() * res;
|
||||
// L^* P
|
||||
res = matrixU() * res;
|
||||
// D(L^*P)
|
||||
res = vectorD().real().asDiagonal() * res;
|
||||
// L(DL^*P)
|
||||
res = matrixL() * res;
|
||||
// P^T (LDL^*P)
|
||||
res = transpositionsP().transpose() * res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** \cholesky_module
|
||||
* \returns the Cholesky decomposition with full pivoting without square root of \c *this
|
||||
* \sa MatrixBase::ldlt()
|
||||
*/
|
||||
template <typename MatrixType, unsigned int UpLo>
|
||||
inline const LDLT<typename SelfAdjointView<MatrixType, UpLo>::PlainObject, UpLo>
|
||||
SelfAdjointView<MatrixType, UpLo>::ldlt() const {
|
||||
return LDLT<PlainObject, UpLo>(m_matrix);
|
||||
}
|
||||
|
||||
/** \cholesky_module
|
||||
* \returns the Cholesky decomposition with full pivoting without square root of \c *this
|
||||
* \sa SelfAdjointView::ldlt()
|
||||
*/
|
||||
template <typename Derived>
|
||||
inline const LDLT<typename MatrixBase<Derived>::PlainObject> MatrixBase<Derived>::ldlt() const {
|
||||
return LDLT<PlainObject>(derived());
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_LDLT_H
|
||||
@@ -0,0 +1,514 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_LLT_H
|
||||
#define EIGEN_LLT_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename MatrixType_, int UpLo_>
|
||||
struct traits<LLT<MatrixType_, UpLo_> > : traits<MatrixType_> {
|
||||
typedef MatrixXpr XprKind;
|
||||
typedef SolverStorage StorageKind;
|
||||
typedef int StorageIndex;
|
||||
enum { Flags = 0 };
|
||||
};
|
||||
|
||||
template <typename MatrixType, int UpLo>
|
||||
struct LLT_Traits;
|
||||
} // namespace internal
|
||||
|
||||
/** \ingroup Cholesky_Module
|
||||
*
|
||||
* \class LLT
|
||||
*
|
||||
* \brief Standard Cholesky decomposition (LL^T) of a matrix and associated features
|
||||
*
|
||||
* \tparam MatrixType_ the type of the matrix of which we are computing the LL^T Cholesky decomposition
|
||||
* \tparam UpLo_ the triangular part that will be used for the decomposition: Lower (default) or Upper.
|
||||
* The other triangular part won't be read.
|
||||
*
|
||||
* This class performs a LL^T Cholesky decomposition of a symmetric, positive definite
|
||||
* matrix A such that A = LL^* = U^*U, where L is lower triangular.
|
||||
*
|
||||
* While the Cholesky decomposition is particularly useful to solve selfadjoint problems like D^*D x = b,
|
||||
* for that purpose, we recommend the Cholesky decomposition without square root which is more stable
|
||||
* and even faster. Nevertheless, this standard Cholesky decomposition remains useful in many other
|
||||
* situations like generalised eigen problems with hermitian matrices.
|
||||
*
|
||||
* Remember that Cholesky decompositions are not rank-revealing. This LLT decomposition is only stable on positive
|
||||
* definite matrices, use LDLT instead for the semidefinite case. Also, do not use a Cholesky decomposition to determine
|
||||
* whether a system of equations has a solution.
|
||||
*
|
||||
* Example: \include LLT_example.cpp
|
||||
* Output: \verbinclude LLT_example.out
|
||||
*
|
||||
* \b Performance: for best performance, it is recommended to use a column-major storage format
|
||||
* with the Lower triangular part (the default), or, equivalently, a row-major storage format
|
||||
* with the Upper triangular part. Otherwise, you might get a 20% slowdown for the full factorization
|
||||
* step, and rank-updates can be up to 3 times slower.
|
||||
*
|
||||
* This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism.
|
||||
*
|
||||
* Note that during the decomposition, only the lower (or upper, as defined by UpLo_) triangular part of A is
|
||||
* considered. Therefore, the strict lower part does not have to store correct values.
|
||||
*
|
||||
* \sa MatrixBase::llt(), SelfAdjointView::llt(), class LDLT
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_>
|
||||
class LLT : public SolverBase<LLT<MatrixType_, UpLo_> > {
|
||||
public:
|
||||
typedef MatrixType_ MatrixType;
|
||||
typedef SolverBase<LLT> Base;
|
||||
friend class SolverBase<LLT>;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(LLT)
|
||||
enum { MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime };
|
||||
|
||||
enum { PacketSize = internal::packet_traits<Scalar>::size, AlignmentMask = int(PacketSize) - 1, UpLo = UpLo_ };
|
||||
|
||||
typedef internal::LLT_Traits<MatrixType, UpLo> Traits;
|
||||
|
||||
/**
|
||||
* \brief Default Constructor.
|
||||
*
|
||||
* The default constructor is useful in cases in which the user intends to
|
||||
* perform decompositions via LLT::compute(const MatrixType&).
|
||||
*/
|
||||
LLT() : m_matrix(), m_isInitialized(false) {}
|
||||
|
||||
/** \brief Default Constructor with memory preallocation
|
||||
*
|
||||
* Like the default constructor but with preallocation of the internal data
|
||||
* according to the specified problem \a size.
|
||||
* \sa LLT()
|
||||
*/
|
||||
explicit LLT(Index size) : m_matrix(size, size), m_isInitialized(false) {}
|
||||
|
||||
template <typename InputType>
|
||||
explicit LLT(const EigenBase<InputType>& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_isInitialized(false) {
|
||||
compute(matrix.derived());
|
||||
}
|
||||
|
||||
/** \brief Constructs a LLT factorization from a given matrix
|
||||
*
|
||||
* This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when
|
||||
* \c MatrixType is a Eigen::Ref.
|
||||
*
|
||||
* \sa LLT(const EigenBase&)
|
||||
*/
|
||||
template <typename InputType>
|
||||
explicit LLT(EigenBase<InputType>& matrix) : m_matrix(matrix.derived()), m_isInitialized(false) {
|
||||
compute(matrix.derived());
|
||||
}
|
||||
|
||||
/** \returns a view of the upper triangular matrix U */
|
||||
inline typename Traits::MatrixU matrixU() const {
|
||||
eigen_assert(m_isInitialized && "LLT is not initialized.");
|
||||
return Traits::getU(m_matrix);
|
||||
}
|
||||
|
||||
/** \returns a view of the lower triangular matrix L */
|
||||
inline typename Traits::MatrixL matrixL() const {
|
||||
eigen_assert(m_isInitialized && "LLT is not initialized.");
|
||||
return Traits::getL(m_matrix);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
|
||||
*
|
||||
* Since this LLT class assumes anyway that the matrix A is invertible, the solution
|
||||
* theoretically exists and is unique regardless of b.
|
||||
*
|
||||
* Example: \include LLT_solve.cpp
|
||||
* Output: \verbinclude LLT_solve.out
|
||||
*
|
||||
* \sa solveInPlace(), MatrixBase::llt(), SelfAdjointView::llt()
|
||||
*/
|
||||
template <typename Rhs>
|
||||
inline const Solve<LLT, Rhs> solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
template <typename Derived>
|
||||
void solveInPlace(const MatrixBase<Derived>& bAndX) const;
|
||||
|
||||
template <typename InputType>
|
||||
LLT& compute(const EigenBase<InputType>& matrix);
|
||||
|
||||
/** \returns an estimate of the reciprocal condition number of the matrix of
|
||||
* which \c *this is the Cholesky decomposition.
|
||||
*/
|
||||
RealScalar rcond() const {
|
||||
eigen_assert(m_isInitialized && "LLT is not initialized.");
|
||||
eigen_assert(m_info == Success && "LLT failed because matrix appears to be negative");
|
||||
return internal::rcond_estimate_helper(m_l1_norm, *this);
|
||||
}
|
||||
|
||||
/** \returns the LLT decomposition matrix
|
||||
*
|
||||
* TODO: document the storage layout
|
||||
*/
|
||||
inline const MatrixType& matrixLLT() const {
|
||||
eigen_assert(m_isInitialized && "LLT is not initialized.");
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
MatrixType reconstructedMatrix() const;
|
||||
|
||||
/** \brief Reports whether previous computation was successful.
|
||||
*
|
||||
* \returns \c Success if computation was successful,
|
||||
* \c NumericalIssue if the matrix.appears not to be positive definite.
|
||||
*/
|
||||
ComputationInfo info() const {
|
||||
eigen_assert(m_isInitialized && "LLT is not initialized.");
|
||||
return m_info;
|
||||
}
|
||||
|
||||
/** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix
|
||||
* is self-adjoint.
|
||||
*
|
||||
* This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as:
|
||||
* \code x = decomposition.adjoint().solve(b) \endcode
|
||||
*/
|
||||
const LLT& adjoint() const noexcept { return *this; }
|
||||
|
||||
constexpr Index rows() const noexcept { return m_matrix.rows(); }
|
||||
constexpr Index cols() const noexcept { return m_matrix.cols(); }
|
||||
|
||||
template <typename VectorType>
|
||||
LLT& rankUpdate(const VectorType& vec, const RealScalar& sigma = 1);
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template <typename RhsType, typename DstType>
|
||||
void _solve_impl(const RhsType& rhs, DstType& dst) const;
|
||||
|
||||
template <bool Conjugate, typename RhsType, typename DstType>
|
||||
void _solve_impl_transposed(const RhsType& rhs, DstType& dst) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
|
||||
|
||||
/** \internal
|
||||
* Used to compute and store L
|
||||
* The strict upper part is not used and even not initialized.
|
||||
*/
|
||||
MatrixType m_matrix;
|
||||
RealScalar m_l1_norm;
|
||||
bool m_isInitialized;
|
||||
ComputationInfo m_info;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Scalar, int UpLo>
|
||||
struct llt_inplace;
|
||||
|
||||
template <typename MatrixType, typename VectorType>
|
||||
static Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec,
|
||||
const typename MatrixType::RealScalar& sigma) {
|
||||
using std::sqrt;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::ColXpr ColXpr;
|
||||
typedef internal::remove_all_t<ColXpr> ColXprCleaned;
|
||||
typedef typename ColXprCleaned::SegmentReturnType ColXprSegment;
|
||||
typedef Matrix<Scalar, Dynamic, 1> TempVectorType;
|
||||
typedef typename TempVectorType::SegmentReturnType TempVecSegment;
|
||||
|
||||
Index n = mat.cols();
|
||||
eigen_assert(mat.rows() == n && vec.size() == n);
|
||||
|
||||
TempVectorType temp;
|
||||
|
||||
if (sigma > 0) {
|
||||
// This version is based on Givens rotations.
|
||||
// It is faster than the other one below, but only works for updates,
|
||||
// i.e., for sigma > 0
|
||||
temp = sqrt(sigma) * vec;
|
||||
|
||||
for (Index i = 0; i < n; ++i) {
|
||||
JacobiRotation<Scalar> g;
|
||||
g.makeGivens(mat(i, i), -temp(i), &mat(i, i));
|
||||
|
||||
Index rs = n - i - 1;
|
||||
if (rs > 0) {
|
||||
ColXprSegment x(mat.col(i).tail(rs));
|
||||
TempVecSegment y(temp.tail(rs));
|
||||
apply_rotation_in_the_plane(x, y, g);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
temp = vec;
|
||||
RealScalar beta = 1;
|
||||
for (Index j = 0; j < n; ++j) {
|
||||
RealScalar Ljj = numext::real(mat.coeff(j, j));
|
||||
RealScalar dj = numext::abs2(Ljj);
|
||||
Scalar wj = temp.coeff(j);
|
||||
RealScalar swj2 = sigma * numext::abs2(wj);
|
||||
RealScalar gamma = dj * beta + swj2;
|
||||
|
||||
RealScalar x = dj + swj2 / beta;
|
||||
if (x <= RealScalar(0)) return j;
|
||||
RealScalar nLjj = sqrt(x);
|
||||
mat.coeffRef(j, j) = nLjj;
|
||||
beta += swj2 / dj;
|
||||
|
||||
// Update the terms of L
|
||||
Index rs = n - j - 1;
|
||||
if (rs) {
|
||||
temp.tail(rs) -= (wj / Ljj) * mat.col(j).tail(rs);
|
||||
if (!numext::is_exactly_zero(gamma))
|
||||
mat.col(j).tail(rs) =
|
||||
(nLjj / Ljj) * mat.col(j).tail(rs) + (nLjj * sigma * numext::conj(wj) / gamma) * temp.tail(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
struct llt_inplace<Scalar, Lower> {
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
template <typename MatrixType>
|
||||
static Index unblocked(MatrixType& mat) {
|
||||
using std::sqrt;
|
||||
|
||||
eigen_assert(mat.rows() == mat.cols());
|
||||
const Index size = mat.rows();
|
||||
for (Index k = 0; k < size; ++k) {
|
||||
Index rs = size - k - 1; // remaining size
|
||||
|
||||
Block<MatrixType, Dynamic, 1> A21(mat, k + 1, k, rs, 1);
|
||||
Block<MatrixType, 1, Dynamic> A10(mat, k, 0, 1, k);
|
||||
Block<MatrixType, Dynamic, Dynamic> A20(mat, k + 1, 0, rs, k);
|
||||
|
||||
RealScalar x = numext::real(mat.coeff(k, k));
|
||||
if (k > 0) x -= A10.squaredNorm();
|
||||
if (x <= RealScalar(0)) return k;
|
||||
mat.coeffRef(k, k) = x = sqrt(x);
|
||||
if (k > 0 && rs > 0) A21.noalias() -= A20 * A10.adjoint();
|
||||
if (rs > 0) A21 /= x;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
static Index blocked(MatrixType& m) {
|
||||
eigen_assert(m.rows() == m.cols());
|
||||
Index size = m.rows();
|
||||
if (size < 32) return unblocked(m);
|
||||
|
||||
Index blockSize = size / 8;
|
||||
blockSize = (blockSize / 16) * 16;
|
||||
blockSize = (std::min)((std::max)(blockSize, Index(8)), Index(128));
|
||||
|
||||
for (Index k = 0; k < size; k += blockSize) {
|
||||
// partition the matrix:
|
||||
// A00 | - | -
|
||||
// lu = A10 | A11 | -
|
||||
// A20 | A21 | A22
|
||||
Index bs = (std::min)(blockSize, size - k);
|
||||
Index rs = size - k - bs;
|
||||
Block<MatrixType, Dynamic, Dynamic> A11(m, k, k, bs, bs);
|
||||
Block<MatrixType, Dynamic, Dynamic> A21(m, k + bs, k, rs, bs);
|
||||
Block<MatrixType, Dynamic, Dynamic> A22(m, k + bs, k + bs, rs, rs);
|
||||
|
||||
Index ret;
|
||||
if ((ret = unblocked(A11)) >= 0) return k + ret;
|
||||
if (rs > 0) A11.adjoint().template triangularView<Upper>().template solveInPlace<OnTheRight>(A21);
|
||||
if (rs > 0)
|
||||
A22.template selfadjointView<Lower>().rankUpdate(A21,
|
||||
typename NumTraits<RealScalar>::Literal(-1)); // bottleneck
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename MatrixType, typename VectorType>
|
||||
static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) {
|
||||
return Eigen::internal::llt_rank_update_lower(mat, vec, sigma);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct llt_inplace<Scalar, Upper> {
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
|
||||
template <typename MatrixType>
|
||||
static EIGEN_STRONG_INLINE Index unblocked(MatrixType& mat) {
|
||||
Transpose<MatrixType> matt(mat);
|
||||
return llt_inplace<Scalar, Lower>::unblocked(matt);
|
||||
}
|
||||
template <typename MatrixType>
|
||||
static EIGEN_STRONG_INLINE Index blocked(MatrixType& mat) {
|
||||
Transpose<MatrixType> matt(mat);
|
||||
return llt_inplace<Scalar, Lower>::blocked(matt);
|
||||
}
|
||||
template <typename MatrixType, typename VectorType>
|
||||
static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) {
|
||||
Transpose<MatrixType> matt(mat);
|
||||
return llt_inplace<Scalar, Lower>::rankUpdate(matt, vec.conjugate(), sigma);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename MatrixType>
|
||||
struct LLT_Traits<MatrixType, Lower> {
|
||||
typedef const TriangularView<const MatrixType, Lower> MatrixL;
|
||||
typedef const TriangularView<const typename MatrixType::AdjointReturnType, Upper> MatrixU;
|
||||
static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); }
|
||||
static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); }
|
||||
static bool inplace_decomposition(MatrixType& m) {
|
||||
return llt_inplace<typename MatrixType::Scalar, Lower>::blocked(m) == -1;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename MatrixType>
|
||||
struct LLT_Traits<MatrixType, Upper> {
|
||||
typedef const TriangularView<const typename MatrixType::AdjointReturnType, Lower> MatrixL;
|
||||
typedef const TriangularView<const MatrixType, Upper> MatrixU;
|
||||
static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); }
|
||||
static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); }
|
||||
static bool inplace_decomposition(MatrixType& m) {
|
||||
return llt_inplace<typename MatrixType::Scalar, Upper>::blocked(m) == -1;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
/** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix
|
||||
*
|
||||
* \returns a reference to *this
|
||||
*
|
||||
* Example: \include TutorialLinAlgComputeTwice.cpp
|
||||
* Output: \verbinclude TutorialLinAlgComputeTwice.out
|
||||
*/
|
||||
template <typename MatrixType, int UpLo_>
|
||||
template <typename InputType>
|
||||
LLT<MatrixType, UpLo_>& LLT<MatrixType, UpLo_>::compute(const EigenBase<InputType>& a) {
|
||||
eigen_assert(a.rows() == a.cols());
|
||||
const Index size = a.rows();
|
||||
m_matrix.resize(size, size);
|
||||
if (!internal::is_same_dense(m_matrix, a.derived())) m_matrix = a.derived();
|
||||
|
||||
// Compute matrix L1 norm = max abs column sum.
|
||||
m_l1_norm = RealScalar(0);
|
||||
// TODO move this code to SelfAdjointView
|
||||
for (Index col = 0; col < size; ++col) {
|
||||
RealScalar abs_col_sum;
|
||||
if (UpLo_ == Lower)
|
||||
abs_col_sum =
|
||||
m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>();
|
||||
else
|
||||
abs_col_sum =
|
||||
m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>();
|
||||
if (abs_col_sum > m_l1_norm) m_l1_norm = abs_col_sum;
|
||||
}
|
||||
|
||||
m_isInitialized = true;
|
||||
bool ok = Traits::inplace_decomposition(m_matrix);
|
||||
m_info = ok ? Success : NumericalIssue;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Performs a rank one update (or dowdate) of the current decomposition.
|
||||
* If A = LL^* before the rank one update,
|
||||
* then after it we have LL^* = A + sigma * v v^* where \a v must be a vector
|
||||
* of same dimension.
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_>
|
||||
template <typename VectorType>
|
||||
LLT<MatrixType_, UpLo_>& LLT<MatrixType_, UpLo_>::rankUpdate(const VectorType& v, const RealScalar& sigma) {
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType);
|
||||
eigen_assert(v.size() == m_matrix.cols());
|
||||
eigen_assert(m_isInitialized);
|
||||
if (internal::llt_inplace<typename MatrixType::Scalar, UpLo>::rankUpdate(m_matrix, v, sigma) >= 0)
|
||||
m_info = NumericalIssue;
|
||||
else
|
||||
m_info = Success;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template <typename MatrixType_, int UpLo_>
|
||||
template <typename RhsType, typename DstType>
|
||||
void LLT<MatrixType_, UpLo_>::_solve_impl(const RhsType& rhs, DstType& dst) const {
|
||||
_solve_impl_transposed<true>(rhs, dst);
|
||||
}
|
||||
|
||||
template <typename MatrixType_, int UpLo_>
|
||||
template <bool Conjugate, typename RhsType, typename DstType>
|
||||
void LLT<MatrixType_, UpLo_>::_solve_impl_transposed(const RhsType& rhs, DstType& dst) const {
|
||||
dst = rhs;
|
||||
|
||||
matrixL().template conjugateIf<!Conjugate>().solveInPlace(dst);
|
||||
matrixU().template conjugateIf<!Conjugate>().solveInPlace(dst);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \internal use x = llt_object.solve(x);
|
||||
*
|
||||
* This is the \em in-place version of solve().
|
||||
*
|
||||
* \param bAndX represents both the right-hand side matrix b and result x.
|
||||
*
|
||||
* This version avoids a copy when the right hand side matrix b is not needed anymore.
|
||||
*
|
||||
* \warning The parameter is only marked 'const' to make the C++ compiler accept a temporary expression here.
|
||||
* This function will const_cast it, so constness isn't honored here.
|
||||
*
|
||||
* \sa LLT::solve(), MatrixBase::llt()
|
||||
*/
|
||||
template <typename MatrixType, int UpLo_>
|
||||
template <typename Derived>
|
||||
void LLT<MatrixType, UpLo_>::solveInPlace(const MatrixBase<Derived>& bAndX) const {
|
||||
eigen_assert(m_isInitialized && "LLT is not initialized.");
|
||||
eigen_assert(m_matrix.rows() == bAndX.rows());
|
||||
matrixL().solveInPlace(bAndX);
|
||||
matrixU().solveInPlace(bAndX);
|
||||
}
|
||||
|
||||
/** \returns the matrix represented by the decomposition,
|
||||
* i.e., it returns the product: L L^*.
|
||||
* This function is provided for debug purpose. */
|
||||
template <typename MatrixType, int UpLo_>
|
||||
MatrixType LLT<MatrixType, UpLo_>::reconstructedMatrix() const {
|
||||
eigen_assert(m_isInitialized && "LLT is not initialized.");
|
||||
return matrixL() * matrixL().adjoint().toDenseMatrix();
|
||||
}
|
||||
|
||||
/** \cholesky_module
|
||||
* \returns the LLT decomposition of \c *this
|
||||
* \sa SelfAdjointView::llt()
|
||||
*/
|
||||
template <typename Derived>
|
||||
inline const LLT<typename MatrixBase<Derived>::PlainObject> MatrixBase<Derived>::llt() const {
|
||||
return LLT<PlainObject>(derived());
|
||||
}
|
||||
|
||||
/** \cholesky_module
|
||||
* \returns the LLT decomposition of \c *this
|
||||
* \sa SelfAdjointView::llt()
|
||||
*/
|
||||
template <typename MatrixType, unsigned int UpLo>
|
||||
inline const LLT<typename SelfAdjointView<MatrixType, UpLo>::PlainObject, UpLo> SelfAdjointView<MatrixType, UpLo>::llt()
|
||||
const {
|
||||
return LLT<PlainObject, UpLo>(m_matrix);
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_LLT_H
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright (c) 2011, Intel Corporation. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
********************************************************************************
|
||||
* Content : Eigen bindings to LAPACKe
|
||||
* LLt decomposition based on LAPACKE_?potrf function.
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef EIGEN_LLT_LAPACKE_H
|
||||
#define EIGEN_LLT_LAPACKE_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
namespace lapacke_helpers {
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Dispatch for rank update handling upper and lower parts
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <UpLoType Mode>
|
||||
struct rank_update {};
|
||||
|
||||
template <>
|
||||
struct rank_update<Lower> {
|
||||
template <typename MatrixType, typename VectorType>
|
||||
static Index run(MatrixType &mat, const VectorType &vec, const typename MatrixType::RealScalar &sigma) {
|
||||
return Eigen::internal::llt_rank_update_lower(mat, vec, sigma);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct rank_update<Upper> {
|
||||
template <typename MatrixType, typename VectorType>
|
||||
static Index run(MatrixType &mat, const VectorType &vec, const typename MatrixType::RealScalar &sigma) {
|
||||
Transpose<MatrixType> matt(mat);
|
||||
return Eigen::internal::llt_rank_update_lower(matt, vec.conjugate(), sigma);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Generic lapacke llt implementation that hands of to the dispatches
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <typename Scalar, UpLoType Mode>
|
||||
struct lapacke_llt {
|
||||
EIGEN_STATIC_ASSERT(((Mode == Lower) || (Mode == Upper)), MODE_MUST_BE_UPPER_OR_LOWER)
|
||||
template <typename MatrixType>
|
||||
static Index blocked(MatrixType &m) {
|
||||
eigen_assert(m.rows() == m.cols());
|
||||
if (m.rows() == 0) {
|
||||
return -1;
|
||||
}
|
||||
/* Set up parameters for ?potrf */
|
||||
lapack_int size = to_lapack(m.rows());
|
||||
lapack_int matrix_order = lapack_storage_of(m);
|
||||
constexpr char uplo = Mode == Upper ? 'U' : 'L';
|
||||
Scalar *a = &(m.coeffRef(0, 0));
|
||||
lapack_int lda = to_lapack(m.outerStride());
|
||||
|
||||
lapack_int info = potrf(matrix_order, uplo, size, to_lapack(a), lda);
|
||||
info = (info == 0) ? -1 : info > 0 ? info - 1 : size;
|
||||
return info;
|
||||
}
|
||||
|
||||
template <typename MatrixType, typename VectorType>
|
||||
static Index rankUpdate(MatrixType &mat, const VectorType &vec, const typename MatrixType::RealScalar &sigma) {
|
||||
return rank_update<Mode>::run(mat, vec, sigma);
|
||||
}
|
||||
};
|
||||
} // namespace lapacke_helpers
|
||||
// end namespace lapacke_helpers
|
||||
|
||||
/*
|
||||
* Here, we just put the generic implementation from lapacke_llt into a full specialization of the llt_inplace
|
||||
* type. By being a full specialization, the versions defined here thus get precedence over the generic implementation
|
||||
* in LLT.h for double, float and complex double, complex float types.
|
||||
*/
|
||||
|
||||
#define EIGEN_LAPACKE_LLT(EIGTYPE) \
|
||||
template <> \
|
||||
struct llt_inplace<EIGTYPE, Lower> : public lapacke_helpers::lapacke_llt<EIGTYPE, Lower> {}; \
|
||||
template <> \
|
||||
struct llt_inplace<EIGTYPE, Upper> : public lapacke_helpers::lapacke_llt<EIGTYPE, Upper> {};
|
||||
|
||||
EIGEN_LAPACKE_LLT(double)
|
||||
EIGEN_LAPACKE_LLT(float)
|
||||
EIGEN_LAPACKE_LLT(std::complex<double>)
|
||||
EIGEN_LAPACKE_LLT(std::complex<float>)
|
||||
|
||||
#undef EIGEN_LAPACKE_LLT
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_LLT_LAPACKE_H
|
||||
+738
@@ -0,0 +1,738 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CHOLMODSUPPORT_H
|
||||
#define EIGEN_CHOLMODSUPPORT_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Scalar>
|
||||
struct cholmod_configure_matrix;
|
||||
|
||||
template <>
|
||||
struct cholmod_configure_matrix<double> {
|
||||
template <typename CholmodType>
|
||||
static void run(CholmodType& mat) {
|
||||
mat.xtype = CHOLMOD_REAL;
|
||||
mat.dtype = CHOLMOD_DOUBLE;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct cholmod_configure_matrix<std::complex<double> > {
|
||||
template <typename CholmodType>
|
||||
static void run(CholmodType& mat) {
|
||||
mat.xtype = CHOLMOD_COMPLEX;
|
||||
mat.dtype = CHOLMOD_DOUBLE;
|
||||
}
|
||||
};
|
||||
|
||||
// Other scalar types are not yet supported by Cholmod
|
||||
// template<> struct cholmod_configure_matrix<float> {
|
||||
// template<typename CholmodType>
|
||||
// static void run(CholmodType& mat) {
|
||||
// mat.xtype = CHOLMOD_REAL;
|
||||
// mat.dtype = CHOLMOD_SINGLE;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// template<> struct cholmod_configure_matrix<std::complex<float> > {
|
||||
// template<typename CholmodType>
|
||||
// static void run(CholmodType& mat) {
|
||||
// mat.xtype = CHOLMOD_COMPLEX;
|
||||
// mat.dtype = CHOLMOD_SINGLE;
|
||||
// }
|
||||
// };
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object.
|
||||
* Note that the data are shared.
|
||||
*/
|
||||
template <typename Scalar_, int Options_, typename StorageIndex_>
|
||||
cholmod_sparse viewAsCholmod(Ref<SparseMatrix<Scalar_, Options_, StorageIndex_> > mat) {
|
||||
cholmod_sparse res;
|
||||
res.nzmax = mat.nonZeros();
|
||||
res.nrow = mat.rows();
|
||||
res.ncol = mat.cols();
|
||||
res.p = mat.outerIndexPtr();
|
||||
res.i = mat.innerIndexPtr();
|
||||
res.x = mat.valuePtr();
|
||||
res.z = 0;
|
||||
res.sorted = 1;
|
||||
if (mat.isCompressed()) {
|
||||
res.packed = 1;
|
||||
res.nz = 0;
|
||||
} else {
|
||||
res.packed = 0;
|
||||
res.nz = mat.innerNonZeroPtr();
|
||||
}
|
||||
|
||||
res.dtype = 0;
|
||||
res.stype = -1;
|
||||
|
||||
if (internal::is_same<StorageIndex_, int>::value) {
|
||||
res.itype = CHOLMOD_INT;
|
||||
} else if (internal::is_same<StorageIndex_, SuiteSparse_long>::value) {
|
||||
res.itype = CHOLMOD_LONG;
|
||||
} else {
|
||||
eigen_assert(false && "Index type not supported yet");
|
||||
}
|
||||
|
||||
// setup res.xtype
|
||||
internal::cholmod_configure_matrix<Scalar_>::run(res);
|
||||
|
||||
res.stype = 0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Scalar_, int Options_, typename Index_>
|
||||
const cholmod_sparse viewAsCholmod(const SparseMatrix<Scalar_, Options_, Index_>& mat) {
|
||||
cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<Scalar_, Options_, Index_> >(mat.const_cast_derived()));
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Scalar_, int Options_, typename Index_>
|
||||
const cholmod_sparse viewAsCholmod(const SparseVector<Scalar_, Options_, Index_>& mat) {
|
||||
cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<Scalar_, Options_, Index_> >(mat.const_cast_derived()));
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix.
|
||||
* The data are not copied but shared. */
|
||||
template <typename Scalar_, int Options_, typename Index_, unsigned int UpLo>
|
||||
cholmod_sparse viewAsCholmod(const SparseSelfAdjointView<const SparseMatrix<Scalar_, Options_, Index_>, UpLo>& mat) {
|
||||
cholmod_sparse res = viewAsCholmod(Ref<SparseMatrix<Scalar_, Options_, Index_> >(mat.matrix().const_cast_derived()));
|
||||
|
||||
if (UpLo == Upper) res.stype = 1;
|
||||
if (UpLo == Lower) res.stype = -1;
|
||||
// swap stype for rowmajor matrices (only works for real matrices)
|
||||
EIGEN_STATIC_ASSERT((Options_ & RowMajorBit) == 0 || NumTraits<Scalar_>::IsComplex == 0,
|
||||
THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
|
||||
if (Options_ & RowMajorBit) res.stype *= -1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Returns a view of the Eigen \b dense matrix \a mat as Cholmod dense matrix.
|
||||
* The data are not copied but shared. */
|
||||
template <typename Derived>
|
||||
cholmod_dense viewAsCholmod(MatrixBase<Derived>& mat) {
|
||||
EIGEN_STATIC_ASSERT((internal::traits<Derived>::Flags & RowMajorBit) == 0,
|
||||
THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
|
||||
cholmod_dense res;
|
||||
res.nrow = mat.rows();
|
||||
res.ncol = mat.cols();
|
||||
res.nzmax = res.nrow * res.ncol;
|
||||
res.d = Derived::IsVectorAtCompileTime ? mat.derived().size() : mat.derived().outerStride();
|
||||
res.x = (void*)(mat.derived().data());
|
||||
res.z = 0;
|
||||
|
||||
internal::cholmod_configure_matrix<Scalar>::run(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix.
|
||||
* The data are not copied but shared. */
|
||||
template <typename Scalar, typename StorageIndex>
|
||||
Map<const SparseMatrix<Scalar, ColMajor, StorageIndex> > viewAsEigen(cholmod_sparse& cm) {
|
||||
return Map<const SparseMatrix<Scalar, ColMajor, StorageIndex> >(
|
||||
cm.nrow, cm.ncol, static_cast<StorageIndex*>(cm.p)[cm.ncol], static_cast<StorageIndex*>(cm.p),
|
||||
static_cast<StorageIndex*>(cm.i), static_cast<Scalar*>(cm.x));
|
||||
}
|
||||
|
||||
/** Returns a view of the Cholmod sparse matrix factor \a cm as an Eigen sparse matrix.
|
||||
* The data are not copied but shared. */
|
||||
template <typename Scalar, typename StorageIndex>
|
||||
Map<const SparseMatrix<Scalar, ColMajor, StorageIndex> > viewAsEigen(cholmod_factor& cm) {
|
||||
return Map<const SparseMatrix<Scalar, ColMajor, StorageIndex> >(
|
||||
cm.n, cm.n, static_cast<StorageIndex*>(cm.p)[cm.n], static_cast<StorageIndex*>(cm.p),
|
||||
static_cast<StorageIndex*>(cm.i), static_cast<Scalar*>(cm.x));
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// template specializations for int and long that call the correct cholmod method
|
||||
|
||||
#define EIGEN_CHOLMOD_SPECIALIZE0(ret, name) \
|
||||
template <typename StorageIndex_> \
|
||||
inline ret cm_##name(cholmod_common& Common) { \
|
||||
return cholmod_##name(&Common); \
|
||||
} \
|
||||
template <> \
|
||||
inline ret cm_##name<SuiteSparse_long>(cholmod_common & Common) { \
|
||||
return cholmod_l_##name(&Common); \
|
||||
}
|
||||
|
||||
#define EIGEN_CHOLMOD_SPECIALIZE1(ret, name, t1, a1) \
|
||||
template <typename StorageIndex_> \
|
||||
inline ret cm_##name(t1& a1, cholmod_common& Common) { \
|
||||
return cholmod_##name(&a1, &Common); \
|
||||
} \
|
||||
template <> \
|
||||
inline ret cm_##name<SuiteSparse_long>(t1 & a1, cholmod_common & Common) { \
|
||||
return cholmod_l_##name(&a1, &Common); \
|
||||
}
|
||||
|
||||
EIGEN_CHOLMOD_SPECIALIZE0(int, start)
|
||||
EIGEN_CHOLMOD_SPECIALIZE0(int, finish)
|
||||
|
||||
EIGEN_CHOLMOD_SPECIALIZE1(int, free_factor, cholmod_factor*, L)
|
||||
EIGEN_CHOLMOD_SPECIALIZE1(int, free_dense, cholmod_dense*, X)
|
||||
EIGEN_CHOLMOD_SPECIALIZE1(int, free_sparse, cholmod_sparse*, A)
|
||||
|
||||
EIGEN_CHOLMOD_SPECIALIZE1(cholmod_factor*, analyze, cholmod_sparse, A)
|
||||
EIGEN_CHOLMOD_SPECIALIZE1(cholmod_sparse*, factor_to_sparse, cholmod_factor, L)
|
||||
|
||||
template <typename StorageIndex_>
|
||||
inline cholmod_dense* cm_solve(int sys, cholmod_factor& L, cholmod_dense& B, cholmod_common& Common) {
|
||||
return cholmod_solve(sys, &L, &B, &Common);
|
||||
}
|
||||
template <>
|
||||
inline cholmod_dense* cm_solve<SuiteSparse_long>(int sys, cholmod_factor& L, cholmod_dense& B, cholmod_common& Common) {
|
||||
return cholmod_l_solve(sys, &L, &B, &Common);
|
||||
}
|
||||
|
||||
template <typename StorageIndex_>
|
||||
inline cholmod_sparse* cm_spsolve(int sys, cholmod_factor& L, cholmod_sparse& B, cholmod_common& Common) {
|
||||
return cholmod_spsolve(sys, &L, &B, &Common);
|
||||
}
|
||||
template <>
|
||||
inline cholmod_sparse* cm_spsolve<SuiteSparse_long>(int sys, cholmod_factor& L, cholmod_sparse& B,
|
||||
cholmod_common& Common) {
|
||||
return cholmod_l_spsolve(sys, &L, &B, &Common);
|
||||
}
|
||||
|
||||
template <typename StorageIndex_>
|
||||
inline int cm_factorize_p(cholmod_sparse* A, double beta[2], StorageIndex_* fset, std::size_t fsize, cholmod_factor* L,
|
||||
cholmod_common& Common) {
|
||||
return cholmod_factorize_p(A, beta, fset, fsize, L, &Common);
|
||||
}
|
||||
template <>
|
||||
inline int cm_factorize_p<SuiteSparse_long>(cholmod_sparse* A, double beta[2], SuiteSparse_long* fset,
|
||||
std::size_t fsize, cholmod_factor* L, cholmod_common& Common) {
|
||||
return cholmod_l_factorize_p(A, beta, fset, fsize, L, &Common);
|
||||
}
|
||||
|
||||
#undef EIGEN_CHOLMOD_SPECIALIZE0
|
||||
#undef EIGEN_CHOLMOD_SPECIALIZE1
|
||||
|
||||
} // namespace internal
|
||||
|
||||
enum CholmodMode { CholmodAuto, CholmodSimplicialLLt, CholmodSupernodalLLt, CholmodLDLt };
|
||||
|
||||
/** \ingroup CholmodSupport_Module
|
||||
* \class CholmodBase
|
||||
* \brief The base class for the direct Cholesky factorization of Cholmod
|
||||
* \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_, typename Derived>
|
||||
class CholmodBase : public SparseSolverBase<Derived> {
|
||||
protected:
|
||||
typedef SparseSolverBase<Derived> Base;
|
||||
using Base::derived;
|
||||
using Base::m_isInitialized;
|
||||
|
||||
public:
|
||||
typedef MatrixType_ MatrixType;
|
||||
enum { UpLo = UpLo_ };
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef MatrixType CholMatrixType;
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
enum { ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime };
|
||||
|
||||
public:
|
||||
CholmodBase() : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) {
|
||||
EIGEN_STATIC_ASSERT((internal::is_same<double, RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
|
||||
m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
|
||||
internal::cm_start<StorageIndex>(m_cholmod);
|
||||
}
|
||||
|
||||
explicit CholmodBase(const MatrixType& matrix)
|
||||
: m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) {
|
||||
EIGEN_STATIC_ASSERT((internal::is_same<double, RealScalar>::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY);
|
||||
m_shiftOffset[0] = m_shiftOffset[1] = 0.0;
|
||||
internal::cm_start<StorageIndex>(m_cholmod);
|
||||
compute(matrix);
|
||||
}
|
||||
|
||||
~CholmodBase() {
|
||||
if (m_cholmodFactor) internal::cm_free_factor<StorageIndex>(m_cholmodFactor, m_cholmod);
|
||||
internal::cm_finish<StorageIndex>(m_cholmod);
|
||||
}
|
||||
|
||||
inline StorageIndex cols() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
|
||||
inline StorageIndex rows() const { return internal::convert_index<StorageIndex, Index>(m_cholmodFactor->n); }
|
||||
|
||||
/** \brief Reports whether previous computation was successful.
|
||||
*
|
||||
* \returns \c Success if computation was successful,
|
||||
* \c NumericalIssue if the matrix.appears to be negative.
|
||||
*/
|
||||
ComputationInfo info() const {
|
||||
eigen_assert(m_isInitialized && "Decomposition is not initialized.");
|
||||
return m_info;
|
||||
}
|
||||
|
||||
/** Computes the sparse Cholesky decomposition of \a matrix */
|
||||
Derived& compute(const MatrixType& matrix) {
|
||||
analyzePattern(matrix);
|
||||
factorize(matrix);
|
||||
return derived();
|
||||
}
|
||||
|
||||
/** Performs a symbolic decomposition on the sparsity pattern of \a matrix.
|
||||
*
|
||||
* This function is particularly useful when solving for several problems having the same structure.
|
||||
*
|
||||
* \sa factorize()
|
||||
*/
|
||||
void analyzePattern(const MatrixType& matrix) {
|
||||
if (m_cholmodFactor) {
|
||||
internal::cm_free_factor<StorageIndex>(m_cholmodFactor, m_cholmod);
|
||||
m_cholmodFactor = 0;
|
||||
}
|
||||
cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
|
||||
m_cholmodFactor = internal::cm_analyze<StorageIndex>(A, m_cholmod);
|
||||
|
||||
this->m_isInitialized = true;
|
||||
this->m_info = Success;
|
||||
m_analysisIsOk = true;
|
||||
m_factorizationIsOk = false;
|
||||
}
|
||||
|
||||
/** Performs a numeric decomposition of \a matrix
|
||||
*
|
||||
* The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been
|
||||
* performed.
|
||||
*
|
||||
* \sa analyzePattern()
|
||||
*/
|
||||
void factorize(const MatrixType& matrix) {
|
||||
eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
|
||||
cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView<UpLo>());
|
||||
internal::cm_factorize_p<StorageIndex>(&A, m_shiftOffset, 0, 0, m_cholmodFactor, m_cholmod);
|
||||
|
||||
// If the factorization failed, either the input matrix was zero (so m_cholmodFactor == nullptr), or minor is the
|
||||
// column at which it failed. On success minor == n.
|
||||
this->m_info =
|
||||
(m_cholmodFactor != nullptr && m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue);
|
||||
m_factorizationIsOk = true;
|
||||
}
|
||||
|
||||
/** Returns a reference to the Cholmod's configuration structure to get a full control over the performed operations.
|
||||
* See the Cholmod user guide for details. */
|
||||
cholmod_common& cholmod() { return m_cholmod; }
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \internal */
|
||||
template <typename Rhs, typename Dest>
|
||||
void _solve_impl(const MatrixBase<Rhs>& b, MatrixBase<Dest>& dest) const {
|
||||
eigen_assert(m_factorizationIsOk &&
|
||||
"The decomposition is not in a valid state for solving, you must first call either compute() or "
|
||||
"symbolic()/numeric()");
|
||||
const Index size = m_cholmodFactor->n;
|
||||
EIGEN_UNUSED_VARIABLE(size);
|
||||
eigen_assert(size == b.rows());
|
||||
|
||||
// Cholmod needs column-major storage without inner-stride, which corresponds to the default behavior of Ref.
|
||||
Ref<const Matrix<typename Rhs::Scalar, Dynamic, Dynamic, ColMajor> > b_ref(b.derived());
|
||||
|
||||
cholmod_dense b_cd = viewAsCholmod(b_ref);
|
||||
cholmod_dense* x_cd = internal::cm_solve<StorageIndex>(CHOLMOD_A, *m_cholmodFactor, b_cd, m_cholmod);
|
||||
if (!x_cd) {
|
||||
this->m_info = NumericalIssue;
|
||||
return;
|
||||
}
|
||||
// TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
|
||||
// NOTE Actually, the copy can be avoided by calling cholmod_solve2 instead of cholmod_solve
|
||||
dest = Matrix<Scalar, Dest::RowsAtCompileTime, Dest::ColsAtCompileTime>::Map(reinterpret_cast<Scalar*>(x_cd->x),
|
||||
b.rows(), b.cols());
|
||||
internal::cm_free_dense<StorageIndex>(x_cd, m_cholmod);
|
||||
}
|
||||
|
||||
/** \internal */
|
||||
template <typename RhsDerived, typename DestDerived>
|
||||
void _solve_impl(const SparseMatrixBase<RhsDerived>& b, SparseMatrixBase<DestDerived>& dest) const {
|
||||
eigen_assert(m_factorizationIsOk &&
|
||||
"The decomposition is not in a valid state for solving, you must first call either compute() or "
|
||||
"symbolic()/numeric()");
|
||||
const Index size = m_cholmodFactor->n;
|
||||
EIGEN_UNUSED_VARIABLE(size);
|
||||
eigen_assert(size == b.rows());
|
||||
|
||||
// note: cs stands for Cholmod Sparse
|
||||
Ref<SparseMatrix<typename RhsDerived::Scalar, ColMajor, typename RhsDerived::StorageIndex> > b_ref(
|
||||
b.const_cast_derived());
|
||||
cholmod_sparse b_cs = viewAsCholmod(b_ref);
|
||||
cholmod_sparse* x_cs = internal::cm_spsolve<StorageIndex>(CHOLMOD_A, *m_cholmodFactor, b_cs, m_cholmod);
|
||||
if (!x_cs) {
|
||||
this->m_info = NumericalIssue;
|
||||
return;
|
||||
}
|
||||
// TODO optimize this copy by swapping when possible (be careful with alignment, etc.)
|
||||
// NOTE cholmod_spsolve in fact just calls the dense solver for blocks of 4 columns at a time (similar to Eigen's
|
||||
// sparse solver)
|
||||
dest.derived() = viewAsEigen<typename DestDerived::Scalar, typename DestDerived::StorageIndex>(*x_cs);
|
||||
internal::cm_free_sparse<StorageIndex>(x_cs, m_cholmod);
|
||||
}
|
||||
#endif // EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/** Sets the shift parameter that will be used to adjust the diagonal coefficients during the numerical factorization.
|
||||
*
|
||||
* During the numerical factorization, an offset term is added to the diagonal coefficients:\n
|
||||
* \c d_ii = \a offset + \c d_ii
|
||||
*
|
||||
* The default is \a offset=0.
|
||||
*
|
||||
* \returns a reference to \c *this.
|
||||
*/
|
||||
Derived& setShift(const RealScalar& offset) {
|
||||
m_shiftOffset[0] = double(offset);
|
||||
return derived();
|
||||
}
|
||||
|
||||
/** \returns the determinant of the underlying matrix from the current factorization */
|
||||
Scalar determinant() const {
|
||||
using std::exp;
|
||||
return exp(logDeterminant());
|
||||
}
|
||||
|
||||
/** \returns the log determinant of the underlying matrix from the current factorization */
|
||||
Scalar logDeterminant() const {
|
||||
using numext::real;
|
||||
using std::log;
|
||||
eigen_assert(m_factorizationIsOk &&
|
||||
"The decomposition is not in a valid state for solving, you must first call either compute() or "
|
||||
"symbolic()/numeric()");
|
||||
|
||||
RealScalar logDet = 0;
|
||||
Scalar* x = static_cast<Scalar*>(m_cholmodFactor->x);
|
||||
if (m_cholmodFactor->is_super) {
|
||||
// Supernodal factorization stored as a packed list of dense column-major blocks,
|
||||
// as described by the following structure:
|
||||
|
||||
// super[k] == index of the first column of the j-th super node
|
||||
StorageIndex* super = static_cast<StorageIndex*>(m_cholmodFactor->super);
|
||||
// pi[k] == offset to the description of row indices
|
||||
StorageIndex* pi = static_cast<StorageIndex*>(m_cholmodFactor->pi);
|
||||
// px[k] == offset to the respective dense block
|
||||
StorageIndex* px = static_cast<StorageIndex*>(m_cholmodFactor->px);
|
||||
|
||||
Index nb_super_nodes = m_cholmodFactor->nsuper;
|
||||
for (Index k = 0; k < nb_super_nodes; ++k) {
|
||||
StorageIndex ncols = super[k + 1] - super[k];
|
||||
StorageIndex nrows = pi[k + 1] - pi[k];
|
||||
|
||||
Map<const Array<Scalar, 1, Dynamic>, 0, InnerStride<> > sk(x + px[k], ncols, InnerStride<>(nrows + 1));
|
||||
logDet += sk.real().log().sum();
|
||||
}
|
||||
} else {
|
||||
// Simplicial factorization stored as standard CSC matrix.
|
||||
StorageIndex* p = static_cast<StorageIndex*>(m_cholmodFactor->p);
|
||||
Index size = m_cholmodFactor->n;
|
||||
for (Index k = 0; k < size; ++k) logDet += log(real(x[p[k]]));
|
||||
}
|
||||
if (m_cholmodFactor->is_ll) logDet *= 2.0;
|
||||
return logDet;
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void dumpMemory(Stream& /*s*/) {}
|
||||
|
||||
protected:
|
||||
mutable cholmod_common m_cholmod;
|
||||
cholmod_factor* m_cholmodFactor;
|
||||
double m_shiftOffset[2];
|
||||
mutable ComputationInfo m_info;
|
||||
int m_factorizationIsOk;
|
||||
int m_analysisIsOk;
|
||||
};
|
||||
|
||||
/** \ingroup CholmodSupport_Module
|
||||
* \class CholmodSimplicialLLT
|
||||
* \brief A simplicial direct Cholesky (LLT) factorization and solver based on Cholmod
|
||||
*
|
||||
* This class allows to solve for A.X = B sparse linear problems via a simplicial LL^T Cholesky factorization
|
||||
* using the Cholmod library.
|
||||
* This simplicial variant is equivalent to Eigen's built-in SimplicialLLT class. Therefore, it has little practical
|
||||
* interest. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices X and B can be
|
||||
* either dense or sparse.
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ the triangular part that will be used for the computations. It can be Lower
|
||||
* or Upper. Default is Lower.
|
||||
*
|
||||
* \implsparsesolverconcept
|
||||
*
|
||||
* This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non
|
||||
* compressed.
|
||||
*
|
||||
* \warning Only double precision real and complex scalar types are supported by Cholmod.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLLT
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_ = Lower>
|
||||
class CholmodSimplicialLLT : public CholmodBase<MatrixType_, UpLo_, CholmodSimplicialLLT<MatrixType_, UpLo_> > {
|
||||
typedef CholmodBase<MatrixType_, UpLo_, CholmodSimplicialLLT> Base;
|
||||
using Base::m_cholmod;
|
||||
|
||||
public:
|
||||
typedef MatrixType_ MatrixType;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
typedef TriangularView<const MatrixType, Eigen::Lower> MatrixL;
|
||||
typedef TriangularView<const typename MatrixType::AdjointReturnType, Eigen::Upper> MatrixU;
|
||||
|
||||
CholmodSimplicialLLT() : Base() { init(); }
|
||||
|
||||
CholmodSimplicialLLT(const MatrixType& matrix) : Base() {
|
||||
init();
|
||||
this->compute(matrix);
|
||||
}
|
||||
|
||||
~CholmodSimplicialLLT() {}
|
||||
|
||||
/** \returns an expression of the factor L */
|
||||
inline MatrixL matrixL() const { return viewAsEigen<Scalar, StorageIndex>(*Base::m_cholmodFactor); }
|
||||
|
||||
/** \returns an expression of the factor U (= L^*) */
|
||||
inline MatrixU matrixU() const { return matrixL().adjoint(); }
|
||||
|
||||
protected:
|
||||
void init() {
|
||||
m_cholmod.final_asis = 0;
|
||||
m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
|
||||
m_cholmod.final_ll = 1;
|
||||
}
|
||||
};
|
||||
|
||||
/** \ingroup CholmodSupport_Module
|
||||
* \class CholmodSimplicialLDLT
|
||||
* \brief A simplicial direct Cholesky (LDLT) factorization and solver based on Cholmod
|
||||
*
|
||||
* This class allows to solve for A.X = B sparse linear problems via a simplicial LDL^T Cholesky factorization
|
||||
* using the Cholmod library.
|
||||
* This simplicial variant is equivalent to Eigen's built-in SimplicialLDLT class. Therefore, it has little practical
|
||||
* interest. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices X and B can be
|
||||
* either dense or sparse.
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ the triangular part that will be used for the computations. It can be Lower
|
||||
* or Upper. Default is Lower.
|
||||
*
|
||||
* \implsparsesolverconcept
|
||||
*
|
||||
* This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non
|
||||
* compressed.
|
||||
*
|
||||
* \warning Only double precision real and complex scalar types are supported by Cholmod.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLDLT
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_ = Lower>
|
||||
class CholmodSimplicialLDLT : public CholmodBase<MatrixType_, UpLo_, CholmodSimplicialLDLT<MatrixType_, UpLo_> > {
|
||||
typedef CholmodBase<MatrixType_, UpLo_, CholmodSimplicialLDLT> Base;
|
||||
using Base::m_cholmod;
|
||||
|
||||
public:
|
||||
typedef MatrixType_ MatrixType;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
typedef Matrix<Scalar, Dynamic, 1> VectorType;
|
||||
typedef TriangularView<const MatrixType, Eigen::UnitLower> MatrixL;
|
||||
typedef TriangularView<const typename MatrixType::AdjointReturnType, Eigen::UnitUpper> MatrixU;
|
||||
|
||||
CholmodSimplicialLDLT() : Base() { init(); }
|
||||
|
||||
CholmodSimplicialLDLT(const MatrixType& matrix) : Base() {
|
||||
init();
|
||||
this->compute(matrix);
|
||||
}
|
||||
|
||||
~CholmodSimplicialLDLT() {}
|
||||
|
||||
/** \returns a vector expression of the diagonal D */
|
||||
inline VectorType vectorD() const {
|
||||
auto cholmodL = viewAsEigen<Scalar, StorageIndex>(*Base::m_cholmodFactor);
|
||||
|
||||
VectorType D{cholmodL.rows()};
|
||||
|
||||
for (Index k = 0; k < cholmodL.outerSize(); ++k) {
|
||||
typename decltype(cholmodL)::InnerIterator it{cholmodL, k};
|
||||
D(k) = it.value();
|
||||
}
|
||||
|
||||
return D;
|
||||
}
|
||||
|
||||
/** \returns an expression of the factor L */
|
||||
inline MatrixL matrixL() const { return viewAsEigen<Scalar, StorageIndex>(*Base::m_cholmodFactor); }
|
||||
|
||||
/** \returns an expression of the factor U (= L^*) */
|
||||
inline MatrixU matrixU() const { return matrixL().adjoint(); }
|
||||
|
||||
protected:
|
||||
void init() {
|
||||
m_cholmod.final_asis = 1;
|
||||
m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
|
||||
}
|
||||
};
|
||||
|
||||
/** \ingroup CholmodSupport_Module
|
||||
* \class CholmodSupernodalLLT
|
||||
* \brief A supernodal Cholesky (LLT) factorization and solver based on Cholmod
|
||||
*
|
||||
* This class allows to solve for A.X = B sparse linear problems via a supernodal LL^T Cholesky factorization
|
||||
* using the Cholmod library.
|
||||
* This supernodal variant performs best on dense enough problems, e.g., 3D FEM, or very high order 2D FEM.
|
||||
* The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
|
||||
* X and B can be either dense or sparse.
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ the triangular part that will be used for the computations. It can be Lower
|
||||
* or Upper. Default is Lower.
|
||||
*
|
||||
* \implsparsesolverconcept
|
||||
*
|
||||
* This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non
|
||||
* compressed.
|
||||
*
|
||||
* \warning Only double precision real and complex scalar types are supported by Cholmod.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_ = Lower>
|
||||
class CholmodSupernodalLLT : public CholmodBase<MatrixType_, UpLo_, CholmodSupernodalLLT<MatrixType_, UpLo_> > {
|
||||
typedef CholmodBase<MatrixType_, UpLo_, CholmodSupernodalLLT> Base;
|
||||
using Base::m_cholmod;
|
||||
|
||||
public:
|
||||
typedef MatrixType_ MatrixType;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
|
||||
CholmodSupernodalLLT() : Base() { init(); }
|
||||
|
||||
CholmodSupernodalLLT(const MatrixType& matrix) : Base() {
|
||||
init();
|
||||
this->compute(matrix);
|
||||
}
|
||||
|
||||
~CholmodSupernodalLLT() {}
|
||||
|
||||
/** \returns an expression of the factor L */
|
||||
inline MatrixType matrixL() const {
|
||||
// Convert Cholmod factor's supernodal storage format to Eigen's CSC storage format
|
||||
cholmod_sparse* cholmodL = internal::cm_factor_to_sparse(*Base::m_cholmodFactor, m_cholmod);
|
||||
MatrixType L = viewAsEigen<Scalar, StorageIndex>(*cholmodL);
|
||||
internal::cm_free_sparse<StorageIndex>(cholmodL, m_cholmod);
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
/** \returns an expression of the factor U (= L^*) */
|
||||
inline MatrixType matrixU() const { return matrixL().adjoint(); }
|
||||
|
||||
protected:
|
||||
void init() {
|
||||
m_cholmod.final_asis = 1;
|
||||
m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
|
||||
}
|
||||
};
|
||||
|
||||
/** \ingroup CholmodSupport_Module
|
||||
* \class CholmodDecomposition
|
||||
* \brief A general Cholesky factorization and solver based on Cholmod
|
||||
*
|
||||
* This class allows to solve for A.X = B sparse linear problems via a LL^T or LDL^T Cholesky factorization
|
||||
* using the Cholmod library. The sparse matrix A must be selfadjoint and positive definite. The vectors or matrices
|
||||
* X and B can be either dense or sparse.
|
||||
*
|
||||
* This variant permits to change the underlying Cholesky method at runtime.
|
||||
* On the other hand, it does not provide access to the result of the factorization.
|
||||
* The default is to let Cholmod automatically choose between a simplicial and supernodal factorization.
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ the triangular part that will be used for the computations. It can be Lower
|
||||
* or Upper. Default is Lower.
|
||||
*
|
||||
* \implsparsesolverconcept
|
||||
*
|
||||
* This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non
|
||||
* compressed.
|
||||
*
|
||||
* \warning Only double precision real and complex scalar types are supported by Cholmod.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_ = Lower>
|
||||
class CholmodDecomposition : public CholmodBase<MatrixType_, UpLo_, CholmodDecomposition<MatrixType_, UpLo_> > {
|
||||
typedef CholmodBase<MatrixType_, UpLo_, CholmodDecomposition> Base;
|
||||
using Base::m_cholmod;
|
||||
|
||||
public:
|
||||
typedef MatrixType_ MatrixType;
|
||||
|
||||
CholmodDecomposition() : Base() { init(); }
|
||||
|
||||
CholmodDecomposition(const MatrixType& matrix) : Base() {
|
||||
init();
|
||||
this->compute(matrix);
|
||||
}
|
||||
|
||||
~CholmodDecomposition() {}
|
||||
|
||||
void setMode(CholmodMode mode) {
|
||||
switch (mode) {
|
||||
case CholmodAuto:
|
||||
m_cholmod.final_asis = 1;
|
||||
m_cholmod.supernodal = CHOLMOD_AUTO;
|
||||
break;
|
||||
case CholmodSimplicialLLt:
|
||||
m_cholmod.final_asis = 0;
|
||||
m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
|
||||
m_cholmod.final_ll = 1;
|
||||
break;
|
||||
case CholmodSupernodalLLt:
|
||||
m_cholmod.final_asis = 1;
|
||||
m_cholmod.supernodal = CHOLMOD_SUPERNODAL;
|
||||
break;
|
||||
case CholmodLDLt:
|
||||
m_cholmod.final_asis = 1;
|
||||
m_cholmod.supernodal = CHOLMOD_SIMPLICIAL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void init() {
|
||||
m_cholmod.final_asis = 1;
|
||||
m_cholmod.supernodal = CHOLMOD_AUTO;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_CHOLMODSUPPORT_H
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_CHOLMODSUPPORT_MODULE_H
|
||||
#error "Please include Eigen/CholmodSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,239 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_ARITHMETIC_SEQUENCE_H
|
||||
#define EIGEN_ARITHMETIC_SEQUENCE_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Helper to cleanup the type of the increment:
|
||||
template <typename T>
|
||||
struct cleanup_seq_incr {
|
||||
typedef typename cleanup_index_type<T, DynamicIndex>::type type;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// seq(first,last,incr) and seqN(first,size,incr)
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
template <typename FirstType = Index, typename SizeType = Index, typename IncrType = internal::FixedInt<1> >
|
||||
class ArithmeticSequence;
|
||||
|
||||
template <typename FirstType, typename SizeType, typename IncrType>
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,
|
||||
typename internal::cleanup_index_type<SizeType>::type,
|
||||
typename internal::cleanup_seq_incr<IncrType>::type>
|
||||
seqN(FirstType first, SizeType size, IncrType incr);
|
||||
|
||||
/** \class ArithmeticSequence
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* This class represents an arithmetic progression \f$ a_0, a_1, a_2, ..., a_{n-1}\f$ defined by
|
||||
* its \em first value \f$ a_0 \f$, its \em size (aka length) \em n, and the \em increment (aka stride)
|
||||
* that is equal to \f$ a_{i+1}-a_{i}\f$ for any \em i.
|
||||
*
|
||||
* It is internally used as the return type of the Eigen::seq and Eigen::seqN functions, and as the input arguments
|
||||
* of DenseBase::operator()(const RowIndices&, const ColIndices&), and most of the time this is the
|
||||
* only way it is used.
|
||||
*
|
||||
* \tparam FirstType type of the first element, usually an Index,
|
||||
* but internally it can be a symbolic expression
|
||||
* \tparam SizeType type representing the size of the sequence, usually an Index
|
||||
* or a compile time integral constant. Internally, it can also be a symbolic expression
|
||||
* \tparam IncrType type of the increment, can be a runtime Index, or a compile time integral constant (default is
|
||||
* compile-time 1)
|
||||
*
|
||||
* \sa Eigen::seq, Eigen::seqN, DenseBase::operator()(const RowIndices&, const ColIndices&), class IndexedView
|
||||
*/
|
||||
template <typename FirstType, typename SizeType, typename IncrType>
|
||||
class ArithmeticSequence {
|
||||
public:
|
||||
constexpr ArithmeticSequence() = default;
|
||||
constexpr ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {}
|
||||
constexpr ArithmeticSequence(FirstType first, SizeType size, IncrType incr)
|
||||
: m_first(first), m_size(size), m_incr(incr) {}
|
||||
|
||||
enum {
|
||||
// SizeAtCompileTime = internal::get_fixed_value<SizeType>::value,
|
||||
IncrAtCompileTime = internal::get_fixed_value<IncrType, DynamicIndex>::value
|
||||
};
|
||||
|
||||
/** \returns the size, i.e., number of elements, of the sequence */
|
||||
constexpr Index size() const { return m_size; }
|
||||
|
||||
/** \returns the first element \f$ a_0 \f$ in the sequence */
|
||||
constexpr Index first() const { return m_first; }
|
||||
|
||||
/** \returns the value \f$ a_i \f$ at index \a i in the sequence. */
|
||||
constexpr Index operator[](Index i) const { return m_first + i * m_incr; }
|
||||
|
||||
constexpr const FirstType& firstObject() const { return m_first; }
|
||||
constexpr const SizeType& sizeObject() const { return m_size; }
|
||||
constexpr const IncrType& incrObject() const { return m_incr; }
|
||||
|
||||
protected:
|
||||
FirstType m_first;
|
||||
SizeType m_size;
|
||||
IncrType m_incr;
|
||||
|
||||
public:
|
||||
constexpr auto reverse() const -> decltype(Eigen::seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr)) {
|
||||
return seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr);
|
||||
}
|
||||
};
|
||||
|
||||
/** \returns an ArithmeticSequence starting at \a first, of length \a size, and increment \a incr
|
||||
*
|
||||
* \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */
|
||||
template <typename FirstType, typename SizeType, typename IncrType>
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,
|
||||
typename internal::cleanup_index_type<SizeType>::type,
|
||||
typename internal::cleanup_seq_incr<IncrType>::type>
|
||||
seqN(FirstType first, SizeType size, IncrType incr) {
|
||||
return ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,
|
||||
typename internal::cleanup_index_type<SizeType>::type,
|
||||
typename internal::cleanup_seq_incr<IncrType>::type>(first, size, incr);
|
||||
}
|
||||
|
||||
/** \returns an ArithmeticSequence starting at \a first, of length \a size, and unit increment
|
||||
*
|
||||
* \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType) */
|
||||
template <typename FirstType, typename SizeType>
|
||||
ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,
|
||||
typename internal::cleanup_index_type<SizeType>::type>
|
||||
seqN(FirstType first, SizeType size) {
|
||||
return ArithmeticSequence<typename internal::cleanup_index_type<FirstType>::type,
|
||||
typename internal::cleanup_index_type<SizeType>::type>(first, size);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/** \returns an ArithmeticSequence starting at \a f, up (or down) to \a l, and with positive (or negative) increment \a
|
||||
* incr
|
||||
*
|
||||
* It is essentially an alias to:
|
||||
* \code
|
||||
* seqN(f, (l-f+incr)/incr, incr);
|
||||
* \endcode
|
||||
*
|
||||
* \sa seqN(FirstType,SizeType,IncrType), seq(FirstType,LastType)
|
||||
*/
|
||||
template <typename FirstType, typename LastType, typename IncrType>
|
||||
auto seq(FirstType f, LastType l, IncrType incr);
|
||||
|
||||
/** \returns an ArithmeticSequence starting at \a f, up (or down) to \a l, and unit increment
|
||||
*
|
||||
* It is essentially an alias to:
|
||||
* \code
|
||||
* seqN(f,l-f+1);
|
||||
* \endcode
|
||||
*
|
||||
* \sa seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType)
|
||||
*/
|
||||
template <typename FirstType, typename LastType>
|
||||
auto seq(FirstType f, LastType l);
|
||||
|
||||
#else // EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
template <typename FirstType, typename LastType>
|
||||
auto seq(FirstType f, LastType l)
|
||||
-> decltype(seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
(typename internal::cleanup_index_type<LastType>::type(l) -
|
||||
typename internal::cleanup_index_type<FirstType>::type(f) + fix<1>()))) {
|
||||
return seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
(typename internal::cleanup_index_type<LastType>::type(l) -
|
||||
typename internal::cleanup_index_type<FirstType>::type(f) + fix<1>()));
|
||||
}
|
||||
|
||||
template <typename FirstType, typename LastType, typename IncrType>
|
||||
auto seq(FirstType f, LastType l, IncrType incr)
|
||||
-> decltype(seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
(typename internal::cleanup_index_type<LastType>::type(l) -
|
||||
typename internal::cleanup_index_type<FirstType>::type(f) +
|
||||
typename internal::cleanup_seq_incr<IncrType>::type(incr)) /
|
||||
typename internal::cleanup_seq_incr<IncrType>::type(incr),
|
||||
typename internal::cleanup_seq_incr<IncrType>::type(incr))) {
|
||||
typedef typename internal::cleanup_seq_incr<IncrType>::type CleanedIncrType;
|
||||
return seqN(typename internal::cleanup_index_type<FirstType>::type(f),
|
||||
(typename internal::cleanup_index_type<LastType>::type(l) -
|
||||
typename internal::cleanup_index_type<FirstType>::type(f) + CleanedIncrType(incr)) /
|
||||
CleanedIncrType(incr),
|
||||
CleanedIncrType(incr));
|
||||
}
|
||||
|
||||
#endif // EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
namespace placeholders {
|
||||
|
||||
/** \cpp11
|
||||
* \returns a symbolic ArithmeticSequence representing the last \a size elements with increment \a incr.
|
||||
*
|
||||
* It is a shortcut for: \code seqN(last-(size-fix<1>)*incr, size, incr) \endcode
|
||||
*
|
||||
* \sa lastN(SizeType), seqN(FirstType,SizeType), seq(FirstType,LastType,IncrType) */
|
||||
template <typename SizeType, typename IncrType>
|
||||
auto lastN(SizeType size, IncrType incr)
|
||||
-> decltype(seqN(Eigen::placeholders::last - (size - fix<1>()) * incr, size, incr)) {
|
||||
return seqN(Eigen::placeholders::last - (size - fix<1>()) * incr, size, incr);
|
||||
}
|
||||
|
||||
/** \cpp11
|
||||
* \returns a symbolic ArithmeticSequence representing the last \a size elements with a unit increment.
|
||||
*
|
||||
* It is a shortcut for: \code seq(last+fix<1>-size, last) \endcode
|
||||
*
|
||||
* \sa lastN(SizeType,IncrType, seqN(FirstType,SizeType), seq(FirstType,LastType) */
|
||||
template <typename SizeType>
|
||||
auto lastN(SizeType size) -> decltype(seqN(Eigen::placeholders::last + fix<1>() - size, size)) {
|
||||
return seqN(Eigen::placeholders::last + fix<1>() - size, size);
|
||||
}
|
||||
|
||||
} // namespace placeholders
|
||||
|
||||
/** \namespace Eigen::indexing
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* The sole purpose of this namespace is to be able to import all functions
|
||||
* and symbols that are expected to be used within operator() for indexing
|
||||
* and slicing. If you already imported the whole Eigen namespace:
|
||||
* \code using namespace Eigen; \endcode
|
||||
* then you are already all set. Otherwise, if you don't want/cannot import
|
||||
* the whole Eigen namespace, the following line:
|
||||
* \code using namespace Eigen::indexing; \endcode
|
||||
* is equivalent to:
|
||||
* \code
|
||||
using Eigen::fix;
|
||||
using Eigen::seq;
|
||||
using Eigen::seqN;
|
||||
using Eigen::placeholders::all;
|
||||
using Eigen::placeholders::last;
|
||||
using Eigen::placeholders::lastN; // c++11 only
|
||||
using Eigen::placeholders::lastp1;
|
||||
\endcode
|
||||
*/
|
||||
namespace indexing {
|
||||
using Eigen::fix;
|
||||
using Eigen::seq;
|
||||
using Eigen::seqN;
|
||||
using Eigen::placeholders::all;
|
||||
using Eigen::placeholders::last;
|
||||
using Eigen::placeholders::lastN;
|
||||
using Eigen::placeholders::lastp1;
|
||||
} // namespace indexing
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_ARITHMETIC_SEQUENCE_H
|
||||
@@ -0,0 +1,376 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_ARRAY_H
|
||||
#define EIGEN_ARRAY_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
template <typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
|
||||
struct traits<Array<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>>
|
||||
: traits<Matrix<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>> {
|
||||
typedef ArrayXpr XprKind;
|
||||
typedef ArrayBase<Array<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>> XprBase;
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
/** \class Array
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief General-purpose arrays with easy API for coefficient-wise operations
|
||||
*
|
||||
* The %Array class is very similar to the Matrix class. It provides
|
||||
* general-purpose one- and two-dimensional arrays. The difference between the
|
||||
* %Array and the %Matrix class is primarily in the API: the API for the
|
||||
* %Array class provides easy access to coefficient-wise operations, while the
|
||||
* API for the %Matrix class provides easy access to linear-algebra
|
||||
* operations.
|
||||
*
|
||||
* See documentation of class Matrix for detailed information on the template parameters
|
||||
* storage layout.
|
||||
*
|
||||
* This class can be extended with the help of the plugin mechanism described on the page
|
||||
* \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN.
|
||||
*
|
||||
* \sa \blank \ref TutorialArrayClass, \ref TopicClassHierarchy
|
||||
*/
|
||||
template <typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
|
||||
class Array : public PlainObjectBase<Array<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>> {
|
||||
public:
|
||||
typedef PlainObjectBase<Array> Base;
|
||||
EIGEN_DENSE_PUBLIC_INTERFACE(Array)
|
||||
|
||||
enum { Options = Options_ };
|
||||
typedef typename Base::PlainObject PlainObject;
|
||||
|
||||
protected:
|
||||
template <typename Derived, typename OtherDerived, bool IsVector>
|
||||
friend struct internal::conservative_resize_like_impl;
|
||||
|
||||
using Base::m_storage;
|
||||
|
||||
public:
|
||||
using Base::base;
|
||||
using Base::coeff;
|
||||
using Base::coeffRef;
|
||||
|
||||
/**
|
||||
* The usage of
|
||||
* using Base::operator=;
|
||||
* fails on MSVC. Since the code below is working with GCC and MSVC, we skipped
|
||||
* the usage of 'using'. This should be done only for operator=.
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const EigenBase<OtherDerived>& other) {
|
||||
return Base::operator=(other);
|
||||
}
|
||||
|
||||
/** Set all the entries to \a value.
|
||||
* \sa DenseBase::setConstant(), DenseBase::fill()
|
||||
*/
|
||||
/* This overload is needed because the usage of
|
||||
* using Base::operator=;
|
||||
* fails on MSVC. Since the code below is working with GCC and MSVC, we skipped
|
||||
* the usage of 'using'. This should be done only for operator=.
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const Scalar& value) {
|
||||
Base::setConstant(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Copies the value of the expression \a other into \c *this with automatic resizing.
|
||||
*
|
||||
* *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized),
|
||||
* it will be initialized.
|
||||
*
|
||||
* Note that copying a row-vector into a vector (and conversely) is allowed.
|
||||
* The resizing, if any, is then done in the appropriate way so that row-vectors
|
||||
* remain row-vectors and vectors remain vectors.
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const DenseBase<OtherDerived>& other) {
|
||||
return Base::_set(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Assigns arrays to each other.
|
||||
*
|
||||
* \note This is a special case of the templated operator=. Its purpose is
|
||||
* to prevent a default operator= from hiding the templated operator=.
|
||||
*
|
||||
* \callgraph
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const Array& other) { return Base::_set(other); }
|
||||
|
||||
/** Default constructor.
|
||||
*
|
||||
* For fixed-size matrices, does nothing.
|
||||
*
|
||||
* For dynamic-size matrices, creates an empty matrix of size 0. Does not allocate any array. Such a matrix
|
||||
* is called a null matrix. This constructor is the unique way to create null matrices: resizing
|
||||
* a matrix to 0 is not supported.
|
||||
*
|
||||
* \sa resize(Index,Index)
|
||||
*/
|
||||
#ifdef EIGEN_INITIALIZE_COEFFS
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Array() : Base() { EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED }
|
||||
#else
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Array() = default;
|
||||
#endif
|
||||
/** \brief Move constructor */
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Array(Array&&) = default;
|
||||
EIGEN_DEVICE_FUNC Array& operator=(Array&& other) noexcept(std::is_nothrow_move_assignable<Scalar>::value) {
|
||||
Base::operator=(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** \brief Construct a row of column vector with fixed size from an arbitrary number of coefficients.
|
||||
*
|
||||
* \only_for_vectors
|
||||
*
|
||||
* This constructor is for 1D array or vectors with more than 4 coefficients.
|
||||
*
|
||||
* \warning To construct a column (resp. row) vector of fixed length, the number of values passed to this
|
||||
* constructor must match the the fixed number of rows (resp. columns) of \c *this.
|
||||
*
|
||||
*
|
||||
* Example: \include Array_variadic_ctor_cxx11.cpp
|
||||
* Output: \verbinclude Array_variadic_ctor_cxx11.out
|
||||
*
|
||||
* \sa Array(const std::initializer_list<std::initializer_list<Scalar>>&)
|
||||
* \sa Array(const Scalar&), Array(const Scalar&,const Scalar&)
|
||||
*/
|
||||
template <typename... ArgTypes>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3,
|
||||
const ArgTypes&... args)
|
||||
: Base(a0, a1, a2, a3, args...) {}
|
||||
|
||||
/** \brief Constructs an array and initializes it from the coefficients given as initializer-lists grouped by row.
|
||||
* \cpp11
|
||||
*
|
||||
* In the general case, the constructor takes a list of rows, each row being represented as a list of coefficients:
|
||||
*
|
||||
* Example: \include Array_initializer_list_23_cxx11.cpp
|
||||
* Output: \verbinclude Array_initializer_list_23_cxx11.out
|
||||
*
|
||||
* Each of the inner initializer lists must contain the exact same number of elements, otherwise an assertion is
|
||||
* triggered.
|
||||
*
|
||||
* In the case of a compile-time column 1D array, implicit transposition from a single row is allowed.
|
||||
* Therefore <code> Array<int,Dynamic,1>{{1,2,3,4,5}}</code> is legal and the more verbose syntax
|
||||
* <code>Array<int,Dynamic,1>{{1},{2},{3},{4},{5}}</code> can be avoided:
|
||||
*
|
||||
* Example: \include Array_initializer_list_vector_cxx11.cpp
|
||||
* Output: \verbinclude Array_initializer_list_vector_cxx11.out
|
||||
*
|
||||
* In the case of fixed-sized arrays, the initializer list sizes must exactly match the array sizes,
|
||||
* and implicit transposition is allowed for compile-time 1D arrays only.
|
||||
*
|
||||
* \sa Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args)
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Array(
|
||||
const std::initializer_list<std::initializer_list<Scalar>>& list)
|
||||
: Base(list) {}
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template <typename T>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Array(const T& x) {
|
||||
Base::template _init1<T>(x);
|
||||
}
|
||||
|
||||
template <typename T0, typename T1>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const T0& val0, const T1& val1) {
|
||||
this->template _init2<T0, T1>(val0, val1);
|
||||
}
|
||||
|
||||
#else
|
||||
/** \brief Constructs a fixed-sized array initialized with coefficients starting at \a data */
|
||||
EIGEN_DEVICE_FUNC explicit Array(const Scalar* data);
|
||||
/** Constructs a vector or row-vector with given dimension. \only_for_vectors
|
||||
*
|
||||
* Note that this is only useful for dynamic-size vectors. For fixed-size vectors,
|
||||
* it is redundant to pass the dimension here, so it makes more sense to use the default
|
||||
* constructor Array() instead.
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Array(Index dim);
|
||||
/** constructs an initialized 1x1 Array with the given coefficient
|
||||
* \sa const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args */
|
||||
Array(const Scalar& value);
|
||||
/** constructs an uninitialized array with \a rows rows and \a cols columns.
|
||||
*
|
||||
* This is useful for dynamic-size arrays. For fixed-size arrays,
|
||||
* it is redundant to pass these parameters, so one should use the default constructor
|
||||
* Array() instead. */
|
||||
Array(Index rows, Index cols);
|
||||
/** constructs an initialized 2D vector with given coefficients
|
||||
* \sa Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args) */
|
||||
Array(const Scalar& val0, const Scalar& val1);
|
||||
#endif // end EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/** constructs an initialized 3D vector with given coefficients
|
||||
* \sa Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args)
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2) {
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 3)
|
||||
m_storage.data()[0] = val0;
|
||||
m_storage.data()[1] = val1;
|
||||
m_storage.data()[2] = val2;
|
||||
}
|
||||
/** constructs an initialized 4D vector with given coefficients
|
||||
* \sa Array(const Scalar& a0, const Scalar& a1, const Scalar& a2, const Scalar& a3, const ArgTypes&... args)
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2,
|
||||
const Scalar& val3) {
|
||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Array, 4)
|
||||
m_storage.data()[0] = val0;
|
||||
m_storage.data()[1] = val1;
|
||||
m_storage.data()[2] = val2;
|
||||
m_storage.data()[3] = val3;
|
||||
}
|
||||
|
||||
/** Copy constructor */
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Array(const Array&) = default;
|
||||
|
||||
private:
|
||||
struct PrivateType {};
|
||||
|
||||
public:
|
||||
/** \sa MatrixBase::operator=(const EigenBase<OtherDerived>&) */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(
|
||||
const EigenBase<OtherDerived>& other,
|
||||
std::enable_if_t<internal::is_convertible<typename OtherDerived::Scalar, Scalar>::value, PrivateType> =
|
||||
PrivateType())
|
||||
: Base(other.derived()) {}
|
||||
|
||||
EIGEN_DEVICE_FUNC constexpr Index innerStride() const noexcept { return 1; }
|
||||
EIGEN_DEVICE_FUNC constexpr Index outerStride() const noexcept { return this->innerSize(); }
|
||||
|
||||
#ifdef EIGEN_ARRAY_PLUGIN
|
||||
#include EIGEN_ARRAY_PLUGIN
|
||||
#endif
|
||||
|
||||
private:
|
||||
template <typename MatrixType, typename OtherDerived, bool SwapPointers>
|
||||
friend struct internal::matrix_swap_impl;
|
||||
};
|
||||
|
||||
/** \defgroup arraytypedefs Global array typedefs
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* %Eigen defines several typedef shortcuts for most common 1D and 2D array types.
|
||||
*
|
||||
* The general patterns are the following:
|
||||
*
|
||||
* \c ArrayRowsColsType where \c Rows and \c Cols can be \c 2,\c 3,\c 4 for fixed size square matrices or \c X for
|
||||
* dynamic size, and where \c Type can be \c i for integer, \c f for float, \c d for double, \c cf for complex float, \c
|
||||
* cd for complex double.
|
||||
*
|
||||
* For example, \c Array33d is a fixed-size 3x3 array type of doubles, and \c ArrayXXf is a dynamic-size matrix of
|
||||
* floats.
|
||||
*
|
||||
* There are also \c ArraySizeType which are self-explanatory. For example, \c Array4cf is
|
||||
* a fixed-size 1D array of 4 complex floats.
|
||||
*
|
||||
* With \cpp11, template alias are also defined for common sizes.
|
||||
* They follow the same pattern as above except that the scalar type suffix is replaced by a
|
||||
* template parameter, i.e.:
|
||||
* - `ArrayRowsCols<Type>` where `Rows` and `Cols` can be \c 2,\c 3,\c 4, or \c X for fixed or dynamic size.
|
||||
* - `ArraySize<Type>` where `Size` can be \c 2,\c 3,\c 4 or \c X for fixed or dynamic size 1D arrays.
|
||||
*
|
||||
* \sa class Array
|
||||
*/
|
||||
|
||||
#define EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Size, SizeSuffix) \
|
||||
/** \ingroup arraytypedefs */ \
|
||||
typedef Array<Type, Size, Size> Array##SizeSuffix##SizeSuffix##TypeSuffix; \
|
||||
/** \ingroup arraytypedefs */ \
|
||||
typedef Array<Type, Size, 1> Array##SizeSuffix##TypeSuffix;
|
||||
|
||||
#define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, Size) \
|
||||
/** \ingroup arraytypedefs */ \
|
||||
typedef Array<Type, Size, Dynamic> Array##Size##X##TypeSuffix; \
|
||||
/** \ingroup arraytypedefs */ \
|
||||
typedef Array<Type, Dynamic, Size> Array##X##Size##TypeSuffix;
|
||||
|
||||
#define EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(Type, TypeSuffix) \
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 2, 2) \
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 3, 3) \
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, 4, 4) \
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS(Type, TypeSuffix, Dynamic, X) \
|
||||
EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 2) \
|
||||
EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 3) \
|
||||
EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Type, TypeSuffix, 4)
|
||||
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(int, i)
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(float, f)
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(double, d)
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex<float>, cf)
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES(std::complex<double>, cd)
|
||||
|
||||
#undef EIGEN_MAKE_ARRAY_TYPEDEFS_ALL_SIZES
|
||||
#undef EIGEN_MAKE_ARRAY_TYPEDEFS
|
||||
#undef EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS
|
||||
|
||||
#define EIGEN_MAKE_ARRAY_TYPEDEFS(Size, SizeSuffix) \
|
||||
/** \ingroup arraytypedefs */ \
|
||||
/** \brief \cpp11 */ \
|
||||
template <typename Type> \
|
||||
using Array##SizeSuffix##SizeSuffix = Array<Type, Size, Size>; \
|
||||
/** \ingroup arraytypedefs */ \
|
||||
/** \brief \cpp11 */ \
|
||||
template <typename Type> \
|
||||
using Array##SizeSuffix = Array<Type, Size, 1>;
|
||||
|
||||
#define EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(Size) \
|
||||
/** \ingroup arraytypedefs */ \
|
||||
/** \brief \cpp11 */ \
|
||||
template <typename Type> \
|
||||
using Array##Size##X = Array<Type, Size, Dynamic>; \
|
||||
/** \ingroup arraytypedefs */ \
|
||||
/** \brief \cpp11 */ \
|
||||
template <typename Type> \
|
||||
using Array##X##Size = Array<Type, Dynamic, Size>;
|
||||
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS(2, 2)
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS(3, 3)
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS(4, 4)
|
||||
EIGEN_MAKE_ARRAY_TYPEDEFS(Dynamic, X)
|
||||
EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(2)
|
||||
EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(3)
|
||||
EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS(4)
|
||||
|
||||
#undef EIGEN_MAKE_ARRAY_TYPEDEFS
|
||||
#undef EIGEN_MAKE_ARRAY_FIXED_TYPEDEFS
|
||||
|
||||
#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \
|
||||
using Eigen::Matrix##SizeSuffix##TypeSuffix; \
|
||||
using Eigen::Vector##SizeSuffix##TypeSuffix; \
|
||||
using Eigen::RowVector##SizeSuffix##TypeSuffix;
|
||||
|
||||
#define EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(TypeSuffix) \
|
||||
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \
|
||||
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \
|
||||
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \
|
||||
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X)
|
||||
|
||||
#define EIGEN_USING_ARRAY_TYPEDEFS \
|
||||
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(i) \
|
||||
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(f) \
|
||||
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(d) \
|
||||
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cf) \
|
||||
EIGEN_USING_ARRAY_TYPEDEFS_FOR_TYPE(cd)
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_ARRAY_H
|
||||
@@ -0,0 +1,213 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_ARRAYBASE_H
|
||||
#define EIGEN_ARRAYBASE_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template <typename ExpressionType>
|
||||
class MatrixWrapper;
|
||||
|
||||
/** \class ArrayBase
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Base class for all 1D and 2D array, and related expressions
|
||||
*
|
||||
* An array is similar to a dense vector or matrix. While matrices are mathematical
|
||||
* objects with well defined linear algebra operators, an array is just a collection
|
||||
* of scalar values arranged in a one or two dimensional fashion. As the main consequence,
|
||||
* all operations applied to an array are performed coefficient wise. Furthermore,
|
||||
* arrays support scalar math functions of the c++ standard library (e.g., std::sin(x)), and convenient
|
||||
* constructors allowing to easily write generic code working for both scalar values
|
||||
* and arrays.
|
||||
*
|
||||
* This class is the base that is inherited by all array expression types.
|
||||
*
|
||||
* \tparam Derived is the derived type, e.g., an array or an expression type.
|
||||
*
|
||||
* This class can be extended with the help of the plugin mechanism described on the page
|
||||
* \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAYBASE_PLUGIN.
|
||||
*
|
||||
* \sa class MatrixBase, \ref TopicClassHierarchy
|
||||
*/
|
||||
template <typename Derived>
|
||||
class ArrayBase : public DenseBase<Derived> {
|
||||
public:
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** The base class for a given storage type. */
|
||||
typedef ArrayBase StorageBaseType;
|
||||
|
||||
typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl;
|
||||
|
||||
typedef typename internal::traits<Derived>::StorageKind StorageKind;
|
||||
typedef typename internal::traits<Derived>::Scalar Scalar;
|
||||
typedef typename internal::packet_traits<Scalar>::type PacketScalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
|
||||
typedef DenseBase<Derived> Base;
|
||||
using Base::ColsAtCompileTime;
|
||||
using Base::Flags;
|
||||
using Base::IsVectorAtCompileTime;
|
||||
using Base::MaxColsAtCompileTime;
|
||||
using Base::MaxRowsAtCompileTime;
|
||||
using Base::MaxSizeAtCompileTime;
|
||||
using Base::RowsAtCompileTime;
|
||||
using Base::SizeAtCompileTime;
|
||||
|
||||
using Base::coeff;
|
||||
using Base::coeffRef;
|
||||
using Base::cols;
|
||||
using Base::const_cast_derived;
|
||||
using Base::derived;
|
||||
using Base::lazyAssign;
|
||||
using Base::rows;
|
||||
using Base::size;
|
||||
using Base::operator-;
|
||||
using Base::operator=;
|
||||
using Base::operator+=;
|
||||
using Base::operator-=;
|
||||
using Base::operator*=;
|
||||
using Base::operator/=;
|
||||
|
||||
typedef typename Base::CoeffReturnType CoeffReturnType;
|
||||
|
||||
typedef typename Base::PlainObject PlainObject;
|
||||
|
||||
/** \internal Represents a matrix with all coefficients equal to one another*/
|
||||
typedef CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> ConstantReturnType;
|
||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase
|
||||
#define EIGEN_DOC_UNARY_ADDONS(X, Y)
|
||||
#include "../plugins/MatrixCwiseUnaryOps.inc"
|
||||
#include "../plugins/ArrayCwiseUnaryOps.inc"
|
||||
#include "../plugins/CommonCwiseBinaryOps.inc"
|
||||
#include "../plugins/MatrixCwiseBinaryOps.inc"
|
||||
#include "../plugins/ArrayCwiseBinaryOps.inc"
|
||||
#ifdef EIGEN_ARRAYBASE_PLUGIN
|
||||
#include EIGEN_ARRAYBASE_PLUGIN
|
||||
#endif
|
||||
#undef EIGEN_CURRENT_STORAGE_BASE_CLASS
|
||||
#undef EIGEN_DOC_UNARY_ADDONS
|
||||
|
||||
/** Special case of the template operator=, in order to prevent the compiler
|
||||
* from generating a default operator= (issue hit with g++ 4.1)
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const ArrayBase& other) {
|
||||
internal::call_assignment(derived(), other.derived());
|
||||
return derived();
|
||||
}
|
||||
|
||||
/** Set all the entries to \a value.
|
||||
* \sa DenseBase::setConstant(), DenseBase::fill() */
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const Scalar& value) {
|
||||
Base::setConstant(value);
|
||||
return derived();
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const Scalar& other) {
|
||||
internal::call_assignment(this->derived(), PlainObject::Constant(rows(), cols(), other),
|
||||
internal::add_assign_op<Scalar, Scalar>());
|
||||
return derived();
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const Scalar& other) {
|
||||
internal::call_assignment(this->derived(), PlainObject::Constant(rows(), cols(), other),
|
||||
internal::sub_assign_op<Scalar, Scalar>());
|
||||
return derived();
|
||||
}
|
||||
|
||||
/** replaces \c *this by \c *this + \a other.
|
||||
*
|
||||
* \returns a reference to \c *this
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const ArrayBase<OtherDerived>& other) {
|
||||
call_assignment(derived(), other.derived(), internal::add_assign_op<Scalar, typename OtherDerived::Scalar>());
|
||||
return derived();
|
||||
}
|
||||
|
||||
/** replaces \c *this by \c *this - \a other.
|
||||
*
|
||||
* \returns a reference to \c *this
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const ArrayBase<OtherDerived>& other) {
|
||||
call_assignment(derived(), other.derived(), internal::sub_assign_op<Scalar, typename OtherDerived::Scalar>());
|
||||
return derived();
|
||||
}
|
||||
|
||||
/** replaces \c *this by \c *this * \a other coefficient wise.
|
||||
*
|
||||
* \returns a reference to \c *this
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator*=(const ArrayBase<OtherDerived>& other) {
|
||||
call_assignment(derived(), other.derived(), internal::mul_assign_op<Scalar, typename OtherDerived::Scalar>());
|
||||
return derived();
|
||||
}
|
||||
|
||||
/** replaces \c *this by \c *this / \a other coefficient wise.
|
||||
*
|
||||
* \returns a reference to \c *this
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator/=(const ArrayBase<OtherDerived>& other) {
|
||||
call_assignment(derived(), other.derived(), internal::div_assign_op<Scalar, typename OtherDerived::Scalar>());
|
||||
return derived();
|
||||
}
|
||||
|
||||
public:
|
||||
EIGEN_DEVICE_FUNC ArrayBase<Derived>& array() { return *this; }
|
||||
EIGEN_DEVICE_FUNC const ArrayBase<Derived>& array() const { return *this; }
|
||||
|
||||
/** \returns an \link Eigen::MatrixBase Matrix \endlink expression of this array
|
||||
* \sa MatrixBase::array() */
|
||||
EIGEN_DEVICE_FUNC MatrixWrapper<Derived> matrix() { return MatrixWrapper<Derived>(derived()); }
|
||||
EIGEN_DEVICE_FUNC const MatrixWrapper<const Derived> matrix() const {
|
||||
return MatrixWrapper<const Derived>(derived());
|
||||
}
|
||||
|
||||
// template<typename Dest>
|
||||
// inline void evalTo(Dest& dst) const { dst = matrix(); }
|
||||
|
||||
protected:
|
||||
EIGEN_DEFAULT_COPY_CONSTRUCTOR(ArrayBase)
|
||||
EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(ArrayBase)
|
||||
|
||||
private:
|
||||
explicit ArrayBase(Index);
|
||||
ArrayBase(Index, Index);
|
||||
template <typename OtherDerived>
|
||||
explicit ArrayBase(const ArrayBase<OtherDerived>&);
|
||||
|
||||
protected:
|
||||
// mixing arrays and matrices is not legal
|
||||
template <typename OtherDerived>
|
||||
Derived& operator+=(const MatrixBase<OtherDerived>&) {
|
||||
EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar)) == -1,
|
||||
YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);
|
||||
return *this;
|
||||
}
|
||||
// mixing arrays and matrices is not legal
|
||||
template <typename OtherDerived>
|
||||
Derived& operator-=(const MatrixBase<OtherDerived>&) {
|
||||
EIGEN_STATIC_ASSERT(std::ptrdiff_t(sizeof(typename OtherDerived::Scalar)) == -1,
|
||||
YOU_CANNOT_MIX_ARRAYS_AND_MATRICES);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_ARRAYBASE_H
|
||||
@@ -0,0 +1,165 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_ARRAYWRAPPER_H
|
||||
#define EIGEN_ARRAYWRAPPER_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/** \class ArrayWrapper
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Expression of a mathematical vector or matrix as an array object
|
||||
*
|
||||
* This class is the return type of MatrixBase::array(), and most of the time
|
||||
* this is the only way it is use.
|
||||
*
|
||||
* \sa MatrixBase::array(), class MatrixWrapper
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
template <typename ExpressionType>
|
||||
struct traits<ArrayWrapper<ExpressionType> > : public traits<remove_all_t<typename ExpressionType::Nested> > {
|
||||
typedef ArrayXpr XprKind;
|
||||
// Let's remove NestByRefBit
|
||||
enum {
|
||||
Flags0 = traits<remove_all_t<typename ExpressionType::Nested> >::Flags,
|
||||
LvalueBitFlag = is_lvalue<ExpressionType>::value ? LvalueBit : 0,
|
||||
Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag
|
||||
};
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
template <typename ExpressionType>
|
||||
class ArrayWrapper : public ArrayBase<ArrayWrapper<ExpressionType> > {
|
||||
public:
|
||||
typedef ArrayBase<ArrayWrapper> Base;
|
||||
EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper)
|
||||
EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper)
|
||||
typedef internal::remove_all_t<ExpressionType> NestedExpression;
|
||||
|
||||
typedef std::conditional_t<internal::is_lvalue<ExpressionType>::value, Scalar, const Scalar>
|
||||
ScalarWithConstIfNotLvalue;
|
||||
|
||||
typedef typename internal::ref_selector<ExpressionType>::non_const_type NestedExpressionType;
|
||||
|
||||
using Base::coeffRef;
|
||||
|
||||
EIGEN_DEVICE_FUNC explicit EIGEN_STRONG_INLINE ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {}
|
||||
|
||||
EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return m_expression.rows(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index cols() const noexcept { return m_expression.cols(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index outerStride() const noexcept { return m_expression.outerStride(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index innerStride() const noexcept { return m_expression.innerStride(); }
|
||||
|
||||
EIGEN_DEVICE_FUNC constexpr ScalarWithConstIfNotLvalue* data() { return m_expression.data(); }
|
||||
EIGEN_DEVICE_FUNC constexpr const Scalar* data() const { return m_expression.data(); }
|
||||
|
||||
EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const {
|
||||
return m_expression.coeffRef(rowId, colId);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { return m_expression.coeffRef(index); }
|
||||
|
||||
template <typename Dest>
|
||||
EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const {
|
||||
dst = m_expression;
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC const internal::remove_all_t<NestedExpressionType>& nestedExpression() const {
|
||||
return m_expression;
|
||||
}
|
||||
|
||||
/** Forwards the resizing request to the nested expression
|
||||
* \sa DenseBase::resize(Index) */
|
||||
EIGEN_DEVICE_FUNC void resize(Index newSize) { m_expression.resize(newSize); }
|
||||
/** Forwards the resizing request to the nested expression
|
||||
* \sa DenseBase::resize(Index,Index)*/
|
||||
EIGEN_DEVICE_FUNC void resize(Index rows, Index cols) { m_expression.resize(rows, cols); }
|
||||
|
||||
protected:
|
||||
NestedExpressionType m_expression;
|
||||
};
|
||||
|
||||
/** \class MatrixWrapper
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Expression of an array as a mathematical vector or matrix
|
||||
*
|
||||
* This class is the return type of ArrayBase::matrix(), and most of the time
|
||||
* this is the only way it is use.
|
||||
*
|
||||
* \sa MatrixBase::matrix(), class ArrayWrapper
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
template <typename ExpressionType>
|
||||
struct traits<MatrixWrapper<ExpressionType> > : public traits<remove_all_t<typename ExpressionType::Nested> > {
|
||||
typedef MatrixXpr XprKind;
|
||||
// Let's remove NestByRefBit
|
||||
enum {
|
||||
Flags0 = traits<remove_all_t<typename ExpressionType::Nested> >::Flags,
|
||||
LvalueBitFlag = is_lvalue<ExpressionType>::value ? LvalueBit : 0,
|
||||
Flags = (Flags0 & ~(NestByRefBit | LvalueBit)) | LvalueBitFlag
|
||||
};
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
template <typename ExpressionType>
|
||||
class MatrixWrapper : public MatrixBase<MatrixWrapper<ExpressionType> > {
|
||||
public:
|
||||
typedef MatrixBase<MatrixWrapper<ExpressionType> > Base;
|
||||
EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper)
|
||||
EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper)
|
||||
typedef internal::remove_all_t<ExpressionType> NestedExpression;
|
||||
|
||||
typedef std::conditional_t<internal::is_lvalue<ExpressionType>::value, Scalar, const Scalar>
|
||||
ScalarWithConstIfNotLvalue;
|
||||
|
||||
typedef typename internal::ref_selector<ExpressionType>::non_const_type NestedExpressionType;
|
||||
|
||||
using Base::coeffRef;
|
||||
|
||||
EIGEN_DEVICE_FUNC explicit inline MatrixWrapper(ExpressionType& matrix) : m_expression(matrix) {}
|
||||
|
||||
EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return m_expression.rows(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index cols() const noexcept { return m_expression.cols(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index outerStride() const noexcept { return m_expression.outerStride(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index innerStride() const noexcept { return m_expression.innerStride(); }
|
||||
|
||||
EIGEN_DEVICE_FUNC constexpr ScalarWithConstIfNotLvalue* data() { return m_expression.data(); }
|
||||
EIGEN_DEVICE_FUNC constexpr const Scalar* data() const { return m_expression.data(); }
|
||||
|
||||
EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const {
|
||||
return m_expression.derived().coeffRef(rowId, colId);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { return m_expression.coeffRef(index); }
|
||||
|
||||
EIGEN_DEVICE_FUNC const internal::remove_all_t<NestedExpressionType>& nestedExpression() const {
|
||||
return m_expression;
|
||||
}
|
||||
|
||||
/** Forwards the resizing request to the nested expression
|
||||
* \sa DenseBase::resize(Index) */
|
||||
EIGEN_DEVICE_FUNC void resize(Index newSize) { m_expression.resize(newSize); }
|
||||
/** Forwards the resizing request to the nested expression
|
||||
* \sa DenseBase::resize(Index,Index)*/
|
||||
EIGEN_DEVICE_FUNC void resize(Index rows, Index cols) { m_expression.resize(rows, cols); }
|
||||
|
||||
protected:
|
||||
NestedExpressionType m_expression;
|
||||
};
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_ARRAYWRAPPER_H
|
||||
@@ -0,0 +1,80 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2007 Michael Olbrich <michael.olbrich@gmx.net>
|
||||
// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_ASSIGN_H
|
||||
#define EIGEN_ASSIGN_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template <typename Derived>
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::lazyAssign(const DenseBase<OtherDerived>& other) {
|
||||
enum { SameType = internal::is_same<typename Derived::Scalar, typename OtherDerived::Scalar>::value };
|
||||
|
||||
EIGEN_STATIC_ASSERT_LVALUE(Derived)
|
||||
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived, OtherDerived)
|
||||
EIGEN_STATIC_ASSERT(
|
||||
SameType,
|
||||
YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
|
||||
|
||||
eigen_assert(rows() == other.rows() && cols() == other.cols());
|
||||
internal::call_assignment_no_alias(derived(), other.derived());
|
||||
|
||||
return derived();
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator=(const DenseBase<OtherDerived>& other) {
|
||||
internal::call_assignment(derived(), other.derived());
|
||||
return derived();
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator=(const DenseBase& other) {
|
||||
internal::call_assignment(derived(), other.derived());
|
||||
return derived();
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const MatrixBase& other) {
|
||||
internal::call_assignment(derived(), other.derived());
|
||||
return derived();
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const DenseBase<OtherDerived>& other) {
|
||||
internal::call_assignment(derived(), other.derived());
|
||||
return derived();
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const EigenBase<OtherDerived>& other) {
|
||||
internal::call_assignment(derived(), other.derived());
|
||||
return derived();
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(
|
||||
const ReturnByValue<OtherDerived>& other) {
|
||||
other.derived().evalTo(derived());
|
||||
return derived();
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_ASSIGN_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
Copyright (c) 2011, Intel Corporation. All rights reserved.
|
||||
Copyright (C) 2015 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
********************************************************************************
|
||||
* Content : Eigen bindings to Intel(R) MKL
|
||||
* MKL VML support for coefficient-wise unary Eigen expressions like a=b.sin()
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef EIGEN_ASSIGN_VML_H
|
||||
#define EIGEN_ASSIGN_VML_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Dst, typename Src>
|
||||
class vml_assign_traits {
|
||||
private:
|
||||
enum {
|
||||
DstHasDirectAccess = Dst::Flags & DirectAccessBit,
|
||||
SrcHasDirectAccess = Src::Flags & DirectAccessBit,
|
||||
StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)),
|
||||
InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime)
|
||||
: int(Dst::Flags) & RowMajorBit ? int(Dst::ColsAtCompileTime)
|
||||
: int(Dst::RowsAtCompileTime),
|
||||
InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime)
|
||||
: int(Dst::Flags) & RowMajorBit ? int(Dst::MaxColsAtCompileTime)
|
||||
: int(Dst::MaxRowsAtCompileTime),
|
||||
MaxSizeAtCompileTime = Dst::SizeAtCompileTime,
|
||||
|
||||
MightEnableVml = StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess &&
|
||||
Src::InnerStrideAtCompileTime == 1 && Dst::InnerStrideAtCompileTime == 1,
|
||||
MightLinearize = MightEnableVml && (int(Dst::Flags) & int(Src::Flags) & LinearAccessBit),
|
||||
VmlSize = MightLinearize ? MaxSizeAtCompileTime : InnerMaxSize,
|
||||
LargeEnough = VmlSize == Dynamic || VmlSize >= EIGEN_MKL_VML_THRESHOLD
|
||||
};
|
||||
|
||||
public:
|
||||
enum { EnableVml = MightEnableVml && LargeEnough, Traversal = MightLinearize ? LinearTraversal : DefaultTraversal };
|
||||
};
|
||||
|
||||
#define EIGEN_PP_EXPAND(ARG) ARG
|
||||
#if !defined(EIGEN_FAST_MATH) || (EIGEN_FAST_MATH != 1)
|
||||
#define EIGEN_VMLMODE_EXPAND_xLA , VML_HA
|
||||
#else
|
||||
#define EIGEN_VMLMODE_EXPAND_xLA , VML_LA
|
||||
#endif
|
||||
|
||||
#define EIGEN_VMLMODE_EXPAND_x_
|
||||
|
||||
#define EIGEN_VMLMODE_PREFIX_xLA vm
|
||||
#define EIGEN_VMLMODE_PREFIX_x_ v
|
||||
#define EIGEN_VMLMODE_PREFIX(VMLMODE) EIGEN_CAT(EIGEN_VMLMODE_PREFIX_x, VMLMODE)
|
||||
|
||||
#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \
|
||||
template <typename DstXprType, typename SrcXprNested> \
|
||||
struct Assignment<DstXprType, CwiseUnaryOp<scalar_##EIGENOP##_op<EIGENTYPE>, SrcXprNested>, \
|
||||
assign_op<EIGENTYPE, EIGENTYPE>, Dense2Dense, \
|
||||
std::enable_if_t<vml_assign_traits<DstXprType, SrcXprNested>::EnableVml>> { \
|
||||
typedef CwiseUnaryOp<scalar_##EIGENOP##_op<EIGENTYPE>, SrcXprNested> SrcXprType; \
|
||||
static void run(DstXprType &dst, const SrcXprType &src, const assign_op<EIGENTYPE, EIGENTYPE> &func) { \
|
||||
resize_if_allowed(dst, src, func); \
|
||||
eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \
|
||||
if (vml_assign_traits<DstXprType, SrcXprNested>::Traversal == (int)LinearTraversal) { \
|
||||
VMLOP(dst.size(), (const VMLTYPE *)src.nestedExpression().data(), \
|
||||
(VMLTYPE *)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_x##VMLMODE)); \
|
||||
} else { \
|
||||
const Index outerSize = dst.outerSize(); \
|
||||
for (Index outer = 0; outer < outerSize; ++outer) { \
|
||||
const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer, 0)) \
|
||||
: &(src.nestedExpression().coeffRef(0, outer)); \
|
||||
EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer, 0)) : &(dst.coeffRef(0, outer)); \
|
||||
VMLOP(dst.innerSize(), (const VMLTYPE *)src_ptr, \
|
||||
(VMLTYPE *)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_x##VMLMODE)); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
|
||||
#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE), s##VMLOP), float, float, VMLMODE) \
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE), d##VMLOP), double, double, VMLMODE)
|
||||
|
||||
#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) \
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE), c##VMLOP), scomplex, \
|
||||
MKL_Complex8, VMLMODE) \
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE), z##VMLOP), dcomplex, \
|
||||
MKL_Complex16, VMLMODE)
|
||||
|
||||
#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP, VMLMODE) \
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE)
|
||||
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sin, Sin, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(asin, Asin, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sinh, Sinh, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cos, Cos, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(acos, Acos, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cosh, Cosh, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tan, Tan, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(atan, Atan, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tanh, Tanh, LA)
|
||||
// EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs, _)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(exp, Exp, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log, Ln, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log10, Log10, LA)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sqrt, Sqrt, _)
|
||||
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr, _)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(arg, Arg, _)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(round, Round, _)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(floor, Floor, _)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(ceil, Ceil, _)
|
||||
EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(cbrt, Cbrt, _)
|
||||
|
||||
#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \
|
||||
template <typename DstXprType, typename SrcXprNested, typename Plain> \
|
||||
struct Assignment<DstXprType, \
|
||||
CwiseBinaryOp<scalar_##EIGENOP##_op<EIGENTYPE, EIGENTYPE>, SrcXprNested, \
|
||||
const CwiseNullaryOp<internal::scalar_constant_op<EIGENTYPE>, Plain>>, \
|
||||
assign_op<EIGENTYPE, EIGENTYPE>, Dense2Dense, \
|
||||
std::enable_if_t<vml_assign_traits<DstXprType, SrcXprNested>::EnableVml>> { \
|
||||
typedef CwiseBinaryOp<scalar_##EIGENOP##_op<EIGENTYPE, EIGENTYPE>, SrcXprNested, \
|
||||
const CwiseNullaryOp<internal::scalar_constant_op<EIGENTYPE>, Plain>> \
|
||||
SrcXprType; \
|
||||
static void run(DstXprType &dst, const SrcXprType &src, const assign_op<EIGENTYPE, EIGENTYPE> &func) { \
|
||||
resize_if_allowed(dst, src, func); \
|
||||
eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \
|
||||
VMLTYPE exponent = reinterpret_cast<const VMLTYPE &>(src.rhs().functor().m_other); \
|
||||
if (vml_assign_traits<DstXprType, SrcXprNested>::Traversal == LinearTraversal) { \
|
||||
VMLOP(dst.size(), (const VMLTYPE *)src.lhs().data(), exponent, \
|
||||
(VMLTYPE *)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_x##VMLMODE)); \
|
||||
} else { \
|
||||
const Index outerSize = dst.outerSize(); \
|
||||
for (Index outer = 0; outer < outerSize; ++outer) { \
|
||||
const EIGENTYPE *src_ptr = \
|
||||
src.IsRowMajor ? &(src.lhs().coeffRef(outer, 0)) : &(src.lhs().coeffRef(0, outer)); \
|
||||
EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer, 0)) : &(dst.coeffRef(0, outer)); \
|
||||
VMLOP(dst.innerSize(), (const VMLTYPE *)src_ptr, exponent, \
|
||||
(VMLTYPE *)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_x##VMLMODE)); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
|
||||
EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmsPowx, float, float, LA)
|
||||
EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdPowx, double, double, LA)
|
||||
EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcPowx, scomplex, MKL_Complex8, LA)
|
||||
EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzPowx, dcomplex, MKL_Complex16, LA)
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_ASSIGN_VML_H
|
||||
@@ -0,0 +1,338 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_BANDMATRIX_H
|
||||
#define EIGEN_BANDMATRIX_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Derived>
|
||||
class BandMatrixBase : public EigenBase<Derived> {
|
||||
public:
|
||||
enum {
|
||||
Flags = internal::traits<Derived>::Flags,
|
||||
CoeffReadCost = internal::traits<Derived>::CoeffReadCost,
|
||||
RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
|
||||
ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = internal::traits<Derived>::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = internal::traits<Derived>::MaxColsAtCompileTime,
|
||||
Supers = internal::traits<Derived>::Supers,
|
||||
Subs = internal::traits<Derived>::Subs,
|
||||
Options = internal::traits<Derived>::Options
|
||||
};
|
||||
typedef typename internal::traits<Derived>::Scalar Scalar;
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime> DenseMatrixType;
|
||||
typedef typename DenseMatrixType::StorageIndex StorageIndex;
|
||||
typedef typename internal::traits<Derived>::CoefficientsType CoefficientsType;
|
||||
typedef EigenBase<Derived> Base;
|
||||
|
||||
protected:
|
||||
enum {
|
||||
DataRowsAtCompileTime = ((Supers != Dynamic) && (Subs != Dynamic)) ? 1 + Supers + Subs : Dynamic,
|
||||
SizeAtCompileTime = min_size_prefer_dynamic(RowsAtCompileTime, ColsAtCompileTime)
|
||||
};
|
||||
|
||||
public:
|
||||
using Base::cols;
|
||||
using Base::derived;
|
||||
using Base::rows;
|
||||
|
||||
/** \returns the number of super diagonals */
|
||||
inline Index supers() const { return derived().supers(); }
|
||||
|
||||
/** \returns the number of sub diagonals */
|
||||
inline Index subs() const { return derived().subs(); }
|
||||
|
||||
/** \returns an expression of the underlying coefficient matrix */
|
||||
inline const CoefficientsType& coeffs() const { return derived().coeffs(); }
|
||||
|
||||
/** \returns an expression of the underlying coefficient matrix */
|
||||
inline CoefficientsType& coeffs() { return derived().coeffs(); }
|
||||
|
||||
/** \returns a vector expression of the \a i -th column,
|
||||
* only the meaningful part is returned.
|
||||
* \warning the internal storage must be column major. */
|
||||
inline Block<CoefficientsType, Dynamic, 1> col(Index i) {
|
||||
EIGEN_STATIC_ASSERT((int(Options) & int(RowMajor)) == 0, THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES);
|
||||
Index start = 0;
|
||||
Index len = coeffs().rows();
|
||||
if (i <= supers()) {
|
||||
start = supers() - i;
|
||||
len = (std::min)(rows(), std::max<Index>(0, coeffs().rows() - (supers() - i)));
|
||||
} else if (i >= rows() - subs())
|
||||
len = std::max<Index>(0, coeffs().rows() - (i + 1 - rows() + subs()));
|
||||
return Block<CoefficientsType, Dynamic, 1>(coeffs(), start, i, len, 1);
|
||||
}
|
||||
|
||||
/** \returns a vector expression of the main diagonal */
|
||||
inline Block<CoefficientsType, 1, SizeAtCompileTime> diagonal() {
|
||||
return Block<CoefficientsType, 1, SizeAtCompileTime>(coeffs(), supers(), 0, 1, (std::min)(rows(), cols()));
|
||||
}
|
||||
|
||||
/** \returns a vector expression of the main diagonal (const version) */
|
||||
inline const Block<const CoefficientsType, 1, SizeAtCompileTime> diagonal() const {
|
||||
return Block<const CoefficientsType, 1, SizeAtCompileTime>(coeffs(), supers(), 0, 1, (std::min)(rows(), cols()));
|
||||
}
|
||||
|
||||
template <int Index>
|
||||
struct DiagonalIntReturnType {
|
||||
enum {
|
||||
ReturnOpposite =
|
||||
(int(Options) & int(SelfAdjoint)) && (((Index) > 0 && Supers == 0) || ((Index) < 0 && Subs == 0)),
|
||||
Conjugate = ReturnOpposite && NumTraits<Scalar>::IsComplex,
|
||||
ActualIndex = ReturnOpposite ? -Index : Index,
|
||||
DiagonalSize =
|
||||
(RowsAtCompileTime == Dynamic || ColsAtCompileTime == Dynamic)
|
||||
? Dynamic
|
||||
: (ActualIndex < 0 ? min_size_prefer_dynamic(ColsAtCompileTime, RowsAtCompileTime + ActualIndex)
|
||||
: min_size_prefer_dynamic(RowsAtCompileTime, ColsAtCompileTime - ActualIndex))
|
||||
};
|
||||
typedef Block<CoefficientsType, 1, DiagonalSize> BuildType;
|
||||
typedef std::conditional_t<Conjugate, CwiseUnaryOp<internal::scalar_conjugate_op<Scalar>, BuildType>, BuildType>
|
||||
Type;
|
||||
};
|
||||
|
||||
/** \returns a vector expression of the \a N -th sub or super diagonal */
|
||||
template <int N>
|
||||
inline typename DiagonalIntReturnType<N>::Type diagonal() {
|
||||
return typename DiagonalIntReturnType<N>::BuildType(coeffs(), supers() - N, (std::max)(0, N), 1, diagonalLength(N));
|
||||
}
|
||||
|
||||
/** \returns a vector expression of the \a N -th sub or super diagonal */
|
||||
template <int N>
|
||||
inline const typename DiagonalIntReturnType<N>::Type diagonal() const {
|
||||
return typename DiagonalIntReturnType<N>::BuildType(coeffs(), supers() - N, (std::max)(0, N), 1, diagonalLength(N));
|
||||
}
|
||||
|
||||
/** \returns a vector expression of the \a i -th sub or super diagonal */
|
||||
inline Block<CoefficientsType, 1, Dynamic> diagonal(Index i) {
|
||||
eigen_assert((i < 0 && -i <= subs()) || (i >= 0 && i <= supers()));
|
||||
return Block<CoefficientsType, 1, Dynamic>(coeffs(), supers() - i, std::max<Index>(0, i), 1, diagonalLength(i));
|
||||
}
|
||||
|
||||
/** \returns a vector expression of the \a i -th sub or super diagonal */
|
||||
inline const Block<const CoefficientsType, 1, Dynamic> diagonal(Index i) const {
|
||||
eigen_assert((i < 0 && -i <= subs()) || (i >= 0 && i <= supers()));
|
||||
return Block<const CoefficientsType, 1, Dynamic>(coeffs(), supers() - i, std::max<Index>(0, i), 1,
|
||||
diagonalLength(i));
|
||||
}
|
||||
|
||||
template <typename Dest>
|
||||
inline void evalTo(Dest& dst) const {
|
||||
dst.resize(rows(), cols());
|
||||
dst.setZero();
|
||||
dst.diagonal() = diagonal();
|
||||
for (Index i = 1; i <= supers(); ++i) dst.diagonal(i) = diagonal(i);
|
||||
for (Index i = 1; i <= subs(); ++i) dst.diagonal(-i) = diagonal(-i);
|
||||
}
|
||||
|
||||
DenseMatrixType toDenseMatrix() const {
|
||||
DenseMatrixType res(rows(), cols());
|
||||
evalTo(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
protected:
|
||||
inline Index diagonalLength(Index i) const {
|
||||
return i < 0 ? (std::min)(cols(), rows() + i) : (std::min)(rows(), cols() - i);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \class BandMatrix
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Represents a rectangular matrix with a banded storage
|
||||
*
|
||||
* \tparam Scalar_ Numeric type, i.e. float, double, int
|
||||
* \tparam Rows_ Number of rows, or \b Dynamic
|
||||
* \tparam Cols_ Number of columns, or \b Dynamic
|
||||
* \tparam Supers_ Number of super diagonal
|
||||
* \tparam Subs_ Number of sub diagonal
|
||||
* \tparam Options_ A combination of either \b #RowMajor or \b #ColMajor, and of \b #SelfAdjoint
|
||||
* The former controls \ref TopicStorageOrders "storage order", and defaults to
|
||||
* column-major. The latter controls whether the matrix represents a selfadjoint
|
||||
* matrix in which case either Supers of Subs have to be null.
|
||||
*
|
||||
* \sa class TridiagonalMatrix
|
||||
*/
|
||||
|
||||
template <typename Scalar_, int Rows_, int Cols_, int Supers_, int Subs_, int Options_>
|
||||
struct traits<BandMatrix<Scalar_, Rows_, Cols_, Supers_, Subs_, Options_> > {
|
||||
typedef Scalar_ Scalar;
|
||||
typedef Dense StorageKind;
|
||||
typedef Eigen::Index StorageIndex;
|
||||
enum {
|
||||
CoeffReadCost = NumTraits<Scalar>::ReadCost,
|
||||
RowsAtCompileTime = Rows_,
|
||||
ColsAtCompileTime = Cols_,
|
||||
MaxRowsAtCompileTime = Rows_,
|
||||
MaxColsAtCompileTime = Cols_,
|
||||
Flags = LvalueBit,
|
||||
Supers = Supers_,
|
||||
Subs = Subs_,
|
||||
Options = Options_,
|
||||
DataRowsAtCompileTime = ((Supers != Dynamic) && (Subs != Dynamic)) ? 1 + Supers + Subs : Dynamic
|
||||
};
|
||||
typedef Matrix<Scalar, DataRowsAtCompileTime, ColsAtCompileTime, int(Options) & int(RowMajor) ? RowMajor : ColMajor>
|
||||
CoefficientsType;
|
||||
};
|
||||
|
||||
template <typename Scalar_, int Rows, int Cols, int Supers, int Subs, int Options>
|
||||
class BandMatrix : public BandMatrixBase<BandMatrix<Scalar_, Rows, Cols, Supers, Subs, Options> > {
|
||||
public:
|
||||
typedef typename internal::traits<BandMatrix>::Scalar Scalar;
|
||||
typedef typename internal::traits<BandMatrix>::StorageIndex StorageIndex;
|
||||
typedef typename internal::traits<BandMatrix>::CoefficientsType CoefficientsType;
|
||||
|
||||
explicit inline BandMatrix(Index rows = Rows, Index cols = Cols, Index supers = Supers, Index subs = Subs)
|
||||
: m_coeffs(1 + supers + subs, cols), m_rows(rows), m_supers(supers), m_subs(subs) {}
|
||||
|
||||
/** \returns the number of columns */
|
||||
constexpr Index rows() const { return m_rows.value(); }
|
||||
|
||||
/** \returns the number of rows */
|
||||
constexpr Index cols() const { return m_coeffs.cols(); }
|
||||
|
||||
/** \returns the number of super diagonals */
|
||||
constexpr Index supers() const { return m_supers.value(); }
|
||||
|
||||
/** \returns the number of sub diagonals */
|
||||
constexpr Index subs() const { return m_subs.value(); }
|
||||
|
||||
inline const CoefficientsType& coeffs() const { return m_coeffs; }
|
||||
inline CoefficientsType& coeffs() { return m_coeffs; }
|
||||
|
||||
protected:
|
||||
CoefficientsType m_coeffs;
|
||||
internal::variable_if_dynamic<Index, Rows> m_rows;
|
||||
internal::variable_if_dynamic<Index, Supers> m_supers;
|
||||
internal::variable_if_dynamic<Index, Subs> m_subs;
|
||||
};
|
||||
|
||||
template <typename CoefficientsType_, int Rows_, int Cols_, int Supers_, int Subs_, int Options_>
|
||||
class BandMatrixWrapper;
|
||||
|
||||
template <typename CoefficientsType_, int Rows_, int Cols_, int Supers_, int Subs_, int Options_>
|
||||
struct traits<BandMatrixWrapper<CoefficientsType_, Rows_, Cols_, Supers_, Subs_, Options_> > {
|
||||
typedef typename CoefficientsType_::Scalar Scalar;
|
||||
typedef typename CoefficientsType_::StorageKind StorageKind;
|
||||
typedef typename CoefficientsType_::StorageIndex StorageIndex;
|
||||
enum {
|
||||
CoeffReadCost = internal::traits<CoefficientsType_>::CoeffReadCost,
|
||||
RowsAtCompileTime = Rows_,
|
||||
ColsAtCompileTime = Cols_,
|
||||
MaxRowsAtCompileTime = Rows_,
|
||||
MaxColsAtCompileTime = Cols_,
|
||||
Flags = LvalueBit,
|
||||
Supers = Supers_,
|
||||
Subs = Subs_,
|
||||
Options = Options_,
|
||||
DataRowsAtCompileTime = ((Supers != Dynamic) && (Subs != Dynamic)) ? 1 + Supers + Subs : Dynamic
|
||||
};
|
||||
typedef CoefficientsType_ CoefficientsType;
|
||||
};
|
||||
|
||||
template <typename CoefficientsType_, int Rows_, int Cols_, int Supers_, int Subs_, int Options_>
|
||||
class BandMatrixWrapper
|
||||
: public BandMatrixBase<BandMatrixWrapper<CoefficientsType_, Rows_, Cols_, Supers_, Subs_, Options_> > {
|
||||
public:
|
||||
typedef typename internal::traits<BandMatrixWrapper>::Scalar Scalar;
|
||||
typedef typename internal::traits<BandMatrixWrapper>::CoefficientsType CoefficientsType;
|
||||
typedef typename internal::traits<BandMatrixWrapper>::StorageIndex StorageIndex;
|
||||
|
||||
explicit inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows = Rows_, Index cols = Cols_,
|
||||
Index supers = Supers_, Index subs = Subs_)
|
||||
: m_coeffs(coeffs), m_rows(rows), m_supers(supers), m_subs(subs) {
|
||||
EIGEN_UNUSED_VARIABLE(cols);
|
||||
// eigen_assert(coeffs.cols()==cols() && (supers()+subs()+1)==coeffs.rows());
|
||||
}
|
||||
|
||||
/** \returns the number of columns */
|
||||
constexpr Index rows() const { return m_rows.value(); }
|
||||
|
||||
/** \returns the number of rows */
|
||||
constexpr Index cols() const { return m_coeffs.cols(); }
|
||||
|
||||
/** \returns the number of super diagonals */
|
||||
constexpr Index supers() const { return m_supers.value(); }
|
||||
|
||||
/** \returns the number of sub diagonals */
|
||||
constexpr Index subs() const { return m_subs.value(); }
|
||||
|
||||
inline const CoefficientsType& coeffs() const { return m_coeffs; }
|
||||
|
||||
protected:
|
||||
const CoefficientsType& m_coeffs;
|
||||
internal::variable_if_dynamic<Index, Rows_> m_rows;
|
||||
internal::variable_if_dynamic<Index, Supers_> m_supers;
|
||||
internal::variable_if_dynamic<Index, Subs_> m_subs;
|
||||
};
|
||||
|
||||
/**
|
||||
* \class TridiagonalMatrix
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Represents a tridiagonal matrix with a compact banded storage
|
||||
*
|
||||
* \tparam Scalar Numeric type, i.e. float, double, int
|
||||
* \tparam Size Number of rows and cols, or \b Dynamic
|
||||
* \tparam Options Can be 0 or \b SelfAdjoint
|
||||
*
|
||||
* \sa class BandMatrix
|
||||
*/
|
||||
template <typename Scalar, int Size, int Options>
|
||||
class TridiagonalMatrix : public BandMatrix<Scalar, Size, Size, Options & SelfAdjoint ? 0 : 1, 1, Options | RowMajor> {
|
||||
typedef BandMatrix<Scalar, Size, Size, Options & SelfAdjoint ? 0 : 1, 1, Options | RowMajor> Base;
|
||||
typedef typename Base::StorageIndex StorageIndex;
|
||||
|
||||
public:
|
||||
explicit TridiagonalMatrix(Index size = Size) : Base(size, size, Options & SelfAdjoint ? 0 : 1, 1) {}
|
||||
|
||||
inline typename Base::template DiagonalIntReturnType<1>::Type super() { return Base::template diagonal<1>(); }
|
||||
inline const typename Base::template DiagonalIntReturnType<1>::Type super() const {
|
||||
return Base::template diagonal<1>();
|
||||
}
|
||||
inline typename Base::template DiagonalIntReturnType<-1>::Type sub() { return Base::template diagonal<-1>(); }
|
||||
inline const typename Base::template DiagonalIntReturnType<-1>::Type sub() const {
|
||||
return Base::template diagonal<-1>();
|
||||
}
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
struct BandShape {};
|
||||
|
||||
template <typename Scalar_, int Rows_, int Cols_, int Supers_, int Subs_, int Options_>
|
||||
struct evaluator_traits<BandMatrix<Scalar_, Rows_, Cols_, Supers_, Subs_, Options_> >
|
||||
: public evaluator_traits_base<BandMatrix<Scalar_, Rows_, Cols_, Supers_, Subs_, Options_> > {
|
||||
typedef BandShape Shape;
|
||||
};
|
||||
|
||||
template <typename CoefficientsType_, int Rows_, int Cols_, int Supers_, int Subs_, int Options_>
|
||||
struct evaluator_traits<BandMatrixWrapper<CoefficientsType_, Rows_, Cols_, Supers_, Subs_, Options_> >
|
||||
: public evaluator_traits_base<BandMatrixWrapper<CoefficientsType_, Rows_, Cols_, Supers_, Subs_, Options_> > {
|
||||
typedef BandShape Shape;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct AssignmentKind<DenseShape, BandShape> {
|
||||
typedef EigenBase2EigenBase Kind;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_BANDMATRIX_H
|
||||
@@ -0,0 +1,429 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_BLOCK_H
|
||||
#define EIGEN_BLOCK_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
template <typename XprType_, int BlockRows, int BlockCols, bool InnerPanel_>
|
||||
struct traits<Block<XprType_, BlockRows, BlockCols, InnerPanel_>> : traits<XprType_> {
|
||||
typedef typename traits<XprType_>::Scalar Scalar;
|
||||
typedef typename traits<XprType_>::StorageKind StorageKind;
|
||||
typedef typename traits<XprType_>::XprKind XprKind;
|
||||
typedef typename ref_selector<XprType_>::type XprTypeNested;
|
||||
typedef std::remove_reference_t<XprTypeNested> XprTypeNested_;
|
||||
enum {
|
||||
MatrixRows = traits<XprType_>::RowsAtCompileTime,
|
||||
MatrixCols = traits<XprType_>::ColsAtCompileTime,
|
||||
RowsAtCompileTime = MatrixRows == 0 ? 0 : BlockRows,
|
||||
ColsAtCompileTime = MatrixCols == 0 ? 0 : BlockCols,
|
||||
MaxRowsAtCompileTime = BlockRows == 0 ? 0
|
||||
: RowsAtCompileTime != Dynamic ? int(RowsAtCompileTime)
|
||||
: int(traits<XprType_>::MaxRowsAtCompileTime),
|
||||
MaxColsAtCompileTime = BlockCols == 0 ? 0
|
||||
: ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime)
|
||||
: int(traits<XprType_>::MaxColsAtCompileTime),
|
||||
|
||||
XprTypeIsRowMajor = (int(traits<XprType_>::Flags) & RowMajorBit) != 0,
|
||||
IsRowMajor = (MaxRowsAtCompileTime == 1 && MaxColsAtCompileTime != 1) ? 1
|
||||
: (MaxColsAtCompileTime == 1 && MaxRowsAtCompileTime != 1) ? 0
|
||||
: XprTypeIsRowMajor,
|
||||
HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor),
|
||||
InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime),
|
||||
InnerStrideAtCompileTime = HasSameStorageOrderAsXprType ? int(inner_stride_at_compile_time<XprType_>::ret)
|
||||
: int(outer_stride_at_compile_time<XprType_>::ret),
|
||||
OuterStrideAtCompileTime = HasSameStorageOrderAsXprType ? int(outer_stride_at_compile_time<XprType_>::ret)
|
||||
: int(inner_stride_at_compile_time<XprType_>::ret),
|
||||
|
||||
// FIXME, this traits is rather specialized for dense object and it needs to be cleaned further
|
||||
FlagsLvalueBit = is_lvalue<XprType_>::value ? LvalueBit : 0,
|
||||
FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0,
|
||||
Flags = (traits<XprType_>::Flags & (DirectAccessBit | (InnerPanel_ ? CompressedAccessBit : 0))) | FlagsLvalueBit |
|
||||
FlagsRowMajorBit,
|
||||
// FIXME DirectAccessBit should not be handled by expressions
|
||||
//
|
||||
// Alignment is needed by MapBase's assertions
|
||||
// We can sefely set it to false here. Internal alignment errors will be detected by an eigen_internal_assert in the
|
||||
// respective evaluator
|
||||
Alignment = 0,
|
||||
InnerPanel = InnerPanel_ ? 1 : 0
|
||||
};
|
||||
};
|
||||
|
||||
template <typename XprType, int BlockRows = Dynamic, int BlockCols = Dynamic, bool InnerPanel = false,
|
||||
bool HasDirectAccess = internal::has_direct_access<XprType>::ret>
|
||||
class BlockImpl_dense;
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel, typename StorageKind>
|
||||
class BlockImpl;
|
||||
|
||||
/** \class Block
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Expression of a fixed-size or dynamic-size block
|
||||
*
|
||||
* \tparam XprType the type of the expression in which we are taking a block
|
||||
* \tparam BlockRows the number of rows of the block we are taking at compile time (optional)
|
||||
* \tparam BlockCols the number of columns of the block we are taking at compile time (optional)
|
||||
* \tparam InnerPanel is true, if the block maps to a set of rows of a row major matrix or
|
||||
* to set of columns of a column major matrix (optional). The parameter allows to determine
|
||||
* at compile time whether aligned access is possible on the block expression.
|
||||
*
|
||||
* This class represents an expression of either a fixed-size or dynamic-size block. It is the return
|
||||
* type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block<int,int>(Index,Index) and
|
||||
* most of the time this is the only way it is used.
|
||||
*
|
||||
* However, if you want to directly manipulate block expressions,
|
||||
* for instance if you want to write a function returning such an expression, you
|
||||
* will need to use this class.
|
||||
*
|
||||
* Here is an example illustrating the dynamic case:
|
||||
* \include class_Block.cpp
|
||||
* Output: \verbinclude class_Block.out
|
||||
*
|
||||
* \note Even though this expression has dynamic size, in the case where \a XprType
|
||||
* has fixed size, this expression inherits a fixed maximal size which means that evaluating
|
||||
* it does not cause a dynamic memory allocation.
|
||||
*
|
||||
* Here is an example illustrating the fixed-size case:
|
||||
* \include class_FixedBlock.cpp
|
||||
* Output: \verbinclude class_FixedBlock.out
|
||||
*
|
||||
* \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock
|
||||
*/
|
||||
template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
|
||||
class Block
|
||||
: public BlockImpl<XprType, BlockRows, BlockCols, InnerPanel, typename internal::traits<XprType>::StorageKind> {
|
||||
typedef BlockImpl<XprType, BlockRows, BlockCols, InnerPanel, typename internal::traits<XprType>::StorageKind> Impl;
|
||||
using BlockHelper = internal::block_xpr_helper<Block>;
|
||||
|
||||
public:
|
||||
// typedef typename Impl::Base Base;
|
||||
typedef Impl Base;
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(Block)
|
||||
EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block)
|
||||
|
||||
typedef internal::remove_all_t<XprType> NestedExpression;
|
||||
|
||||
/** Column or Row constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Block(XprType& xpr, Index i) : Impl(xpr, i) {
|
||||
eigen_assert((i >= 0) && (((BlockRows == 1) && (BlockCols == XprType::ColsAtCompileTime) && i < xpr.rows()) ||
|
||||
((BlockRows == XprType::RowsAtCompileTime) && (BlockCols == 1) && i < xpr.cols())));
|
||||
}
|
||||
|
||||
/** Fixed-size constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Block(XprType& xpr, Index startRow, Index startCol)
|
||||
: Impl(xpr, startRow, startCol) {
|
||||
EIGEN_STATIC_ASSERT(RowsAtCompileTime != Dynamic && ColsAtCompileTime != Dynamic,
|
||||
THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE)
|
||||
eigen_assert(startRow >= 0 && BlockRows >= 0 && startRow + BlockRows <= xpr.rows() && startCol >= 0 &&
|
||||
BlockCols >= 0 && startCol + BlockCols <= xpr.cols());
|
||||
}
|
||||
|
||||
/** Dynamic-size constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Block(XprType& xpr, Index startRow, Index startCol, Index blockRows,
|
||||
Index blockCols)
|
||||
: Impl(xpr, startRow, startCol, blockRows, blockCols) {
|
||||
eigen_assert((RowsAtCompileTime == Dynamic || RowsAtCompileTime == blockRows) &&
|
||||
(ColsAtCompileTime == Dynamic || ColsAtCompileTime == blockCols));
|
||||
eigen_assert(startRow >= 0 && blockRows >= 0 && startRow <= xpr.rows() - blockRows && startCol >= 0 &&
|
||||
blockCols >= 0 && startCol <= xpr.cols() - blockCols);
|
||||
}
|
||||
|
||||
// convert nested blocks (e.g. Block<Block<MatrixType>>) to a simple block expression (Block<MatrixType>)
|
||||
|
||||
using ConstUnwindReturnType = Block<const typename BlockHelper::BaseType, BlockRows, BlockCols, InnerPanel>;
|
||||
using UnwindReturnType = Block<typename BlockHelper::BaseType, BlockRows, BlockCols, InnerPanel>;
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ConstUnwindReturnType unwind() const {
|
||||
return ConstUnwindReturnType(BlockHelper::base(*this), BlockHelper::row(*this, 0), BlockHelper::col(*this, 0),
|
||||
this->rows(), this->cols());
|
||||
}
|
||||
|
||||
template <typename T = Block, typename EnableIf = std::enable_if_t<!std::is_const<T>::value>>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE UnwindReturnType unwind() {
|
||||
return UnwindReturnType(BlockHelper::base(*this), BlockHelper::row(*this, 0), BlockHelper::col(*this, 0),
|
||||
this->rows(), this->cols());
|
||||
}
|
||||
};
|
||||
|
||||
// The generic default implementation for dense block simply forward to the internal::BlockImpl_dense
|
||||
// that must be specialized for direct and non-direct access...
|
||||
template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
|
||||
class BlockImpl<XprType, BlockRows, BlockCols, InnerPanel, Dense>
|
||||
: public internal::BlockImpl_dense<XprType, BlockRows, BlockCols, InnerPanel> {
|
||||
typedef internal::BlockImpl_dense<XprType, BlockRows, BlockCols, InnerPanel> Impl;
|
||||
typedef typename XprType::StorageIndex StorageIndex;
|
||||
|
||||
public:
|
||||
typedef Impl Base;
|
||||
EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl)
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE BlockImpl(XprType& xpr, Index i) : Impl(xpr, i) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE BlockImpl(XprType& xpr, Index startRow, Index startCol)
|
||||
: Impl(xpr, startRow, startCol) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows,
|
||||
Index blockCols)
|
||||
: Impl(xpr, startRow, startCol, blockRows, blockCols) {}
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
/** \internal Internal implementation of dense Blocks in the general case. */
|
||||
template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel, bool HasDirectAccess>
|
||||
class BlockImpl_dense : public internal::dense_xpr_base<Block<XprType, BlockRows, BlockCols, InnerPanel>>::type {
|
||||
typedef Block<XprType, BlockRows, BlockCols, InnerPanel> BlockType;
|
||||
typedef typename internal::ref_selector<XprType>::non_const_type XprTypeNested;
|
||||
|
||||
public:
|
||||
typedef typename internal::dense_xpr_base<BlockType>::type Base;
|
||||
EIGEN_DENSE_PUBLIC_INTERFACE(BlockType)
|
||||
EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense)
|
||||
|
||||
// class InnerIterator; // FIXME apparently never used
|
||||
|
||||
/** Column or Row constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i)
|
||||
: m_xpr(xpr),
|
||||
// It is a row if and only if BlockRows==1 and BlockCols==XprType::ColsAtCompileTime,
|
||||
// and it is a column if and only if BlockRows==XprType::RowsAtCompileTime and BlockCols==1,
|
||||
// all other cases are invalid.
|
||||
// The case a 1x1 matrix seems ambiguous, but the result is the same anyway.
|
||||
m_startRow((BlockRows == 1) && (BlockCols == XprType::ColsAtCompileTime) ? i : 0),
|
||||
m_startCol((BlockRows == XprType::RowsAtCompileTime) && (BlockCols == 1) ? i : 0),
|
||||
m_blockRows(BlockRows == 1 ? 1 : xpr.rows()),
|
||||
m_blockCols(BlockCols == 1 ? 1 : xpr.cols()) {}
|
||||
|
||||
/** Fixed-size constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol)
|
||||
: m_xpr(xpr), m_startRow(startRow), m_startCol(startCol), m_blockRows(BlockRows), m_blockCols(BlockCols) {}
|
||||
|
||||
/** Dynamic-size constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol, Index blockRows,
|
||||
Index blockCols)
|
||||
: m_xpr(xpr), m_startRow(startRow), m_startCol(startCol), m_blockRows(blockRows), m_blockCols(blockCols) {}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline Index rows() const { return m_blockRows.value(); }
|
||||
EIGEN_DEVICE_FUNC inline Index cols() const { return m_blockCols.value(); }
|
||||
|
||||
EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index rowId, Index colId) {
|
||||
EIGEN_STATIC_ASSERT_LVALUE(XprType)
|
||||
return m_xpr.coeffRef(rowId + m_startRow.value(), colId + m_startCol.value());
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const {
|
||||
return m_xpr.derived().coeffRef(rowId + m_startRow.value(), colId + m_startCol.value());
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index rowId, Index colId) const {
|
||||
return m_xpr.coeff(rowId + m_startRow.value(), colId + m_startCol.value());
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) {
|
||||
EIGEN_STATIC_ASSERT_LVALUE(XprType)
|
||||
return m_xpr.coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
|
||||
m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const {
|
||||
return m_xpr.coeffRef(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
|
||||
m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const {
|
||||
return m_xpr.coeff(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
|
||||
m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
|
||||
}
|
||||
|
||||
template <int LoadMode>
|
||||
EIGEN_DEVICE_FUNC inline PacketScalar packet(Index rowId, Index colId) const {
|
||||
return m_xpr.template packet<Unaligned>(rowId + m_startRow.value(), colId + m_startCol.value());
|
||||
}
|
||||
|
||||
template <int LoadMode>
|
||||
EIGEN_DEVICE_FUNC inline void writePacket(Index rowId, Index colId, const PacketScalar& val) {
|
||||
m_xpr.template writePacket<Unaligned>(rowId + m_startRow.value(), colId + m_startCol.value(), val);
|
||||
}
|
||||
|
||||
template <int LoadMode>
|
||||
EIGEN_DEVICE_FUNC inline PacketScalar packet(Index index) const {
|
||||
return m_xpr.template packet<Unaligned>(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
|
||||
m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0));
|
||||
}
|
||||
|
||||
template <int LoadMode>
|
||||
EIGEN_DEVICE_FUNC inline void writePacket(Index index, const PacketScalar& val) {
|
||||
m_xpr.template writePacket<Unaligned>(m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index),
|
||||
m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), val);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \sa MapBase::data() */
|
||||
EIGEN_DEVICE_FUNC constexpr const Scalar* data() const;
|
||||
EIGEN_DEVICE_FUNC inline Index innerStride() const;
|
||||
EIGEN_DEVICE_FUNC inline Index outerStride() const;
|
||||
#endif
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const internal::remove_all_t<XprTypeNested>& nestedExpression() const {
|
||||
return m_xpr;
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE XprType& nestedExpression() { return m_xpr; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr StorageIndex startRow() const noexcept { return m_startRow.value(); }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr StorageIndex startCol() const noexcept { return m_startCol.value(); }
|
||||
|
||||
protected:
|
||||
XprTypeNested m_xpr;
|
||||
const internal::variable_if_dynamic<StorageIndex, (XprType::RowsAtCompileTime == 1 && BlockRows == 1) ? 0 : Dynamic>
|
||||
m_startRow;
|
||||
const internal::variable_if_dynamic<StorageIndex, (XprType::ColsAtCompileTime == 1 && BlockCols == 1) ? 0 : Dynamic>
|
||||
m_startCol;
|
||||
const internal::variable_if_dynamic<StorageIndex, RowsAtCompileTime> m_blockRows;
|
||||
const internal::variable_if_dynamic<StorageIndex, ColsAtCompileTime> m_blockCols;
|
||||
};
|
||||
|
||||
/** \internal Internal implementation of dense Blocks in the direct access case.*/
|
||||
template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
|
||||
class BlockImpl_dense<XprType, BlockRows, BlockCols, InnerPanel, true>
|
||||
: public MapBase<Block<XprType, BlockRows, BlockCols, InnerPanel>> {
|
||||
typedef Block<XprType, BlockRows, BlockCols, InnerPanel> BlockType;
|
||||
typedef typename internal::ref_selector<XprType>::non_const_type XprTypeNested;
|
||||
enum { XprTypeIsRowMajor = (int(traits<XprType>::Flags) & RowMajorBit) != 0 };
|
||||
|
||||
/** \internal Returns base+offset (unless base is null, in which case returns null).
|
||||
* Adding an offset to nullptr is undefined behavior, so we must avoid it.
|
||||
*/
|
||||
template <typename Scalar>
|
||||
EIGEN_DEVICE_FUNC constexpr EIGEN_ALWAYS_INLINE static Scalar* add_to_nullable_pointer(Scalar* base, Index offset) {
|
||||
return base != nullptr ? base + offset : nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef MapBase<BlockType> Base;
|
||||
EIGEN_DENSE_PUBLIC_INTERFACE(BlockType)
|
||||
EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense)
|
||||
|
||||
/** Column or Row constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE BlockImpl_dense(XprType& xpr, Index i)
|
||||
: Base((BlockRows == 0 || BlockCols == 0)
|
||||
? nullptr
|
||||
: add_to_nullable_pointer(
|
||||
xpr.data(),
|
||||
i * (((BlockRows == 1) && (BlockCols == XprType::ColsAtCompileTime) && (!XprTypeIsRowMajor)) ||
|
||||
((BlockRows == XprType::RowsAtCompileTime) && (BlockCols == 1) &&
|
||||
(XprTypeIsRowMajor))
|
||||
? xpr.innerStride()
|
||||
: xpr.outerStride())),
|
||||
BlockRows == 1 ? 1 : xpr.rows(), BlockCols == 1 ? 1 : xpr.cols()),
|
||||
m_xpr(xpr),
|
||||
m_startRow((BlockRows == 1) && (BlockCols == XprType::ColsAtCompileTime) ? i : 0),
|
||||
m_startCol((BlockRows == XprType::RowsAtCompileTime) && (BlockCols == 1) ? i : 0) {
|
||||
init();
|
||||
}
|
||||
|
||||
/** Fixed-size constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE BlockImpl_dense(XprType& xpr, Index startRow, Index startCol)
|
||||
: Base((BlockRows == 0 || BlockCols == 0)
|
||||
? nullptr
|
||||
: add_to_nullable_pointer(xpr.data(),
|
||||
xpr.innerStride() * (XprTypeIsRowMajor ? startCol : startRow) +
|
||||
xpr.outerStride() * (XprTypeIsRowMajor ? startRow : startCol))),
|
||||
m_xpr(xpr),
|
||||
m_startRow(startRow),
|
||||
m_startCol(startCol) {
|
||||
init();
|
||||
}
|
||||
|
||||
/** Dynamic-size constructor
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE BlockImpl_dense(XprType& xpr, Index startRow, Index startCol, Index blockRows,
|
||||
Index blockCols)
|
||||
: Base((blockRows == 0 || blockCols == 0)
|
||||
? nullptr
|
||||
: add_to_nullable_pointer(xpr.data(),
|
||||
xpr.innerStride() * (XprTypeIsRowMajor ? startCol : startRow) +
|
||||
xpr.outerStride() * (XprTypeIsRowMajor ? startRow : startCol)),
|
||||
blockRows, blockCols),
|
||||
m_xpr(xpr),
|
||||
m_startRow(startRow),
|
||||
m_startCol(startCol) {
|
||||
init();
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const internal::remove_all_t<XprTypeNested>& nestedExpression() const noexcept {
|
||||
return m_xpr;
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE XprType& nestedExpression() { return m_xpr; }
|
||||
|
||||
/** \sa MapBase::innerStride() */
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Index innerStride() const noexcept {
|
||||
return internal::traits<BlockType>::HasSameStorageOrderAsXprType ? m_xpr.innerStride() : m_xpr.outerStride();
|
||||
}
|
||||
|
||||
/** \sa MapBase::outerStride() */
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Index outerStride() const noexcept {
|
||||
return internal::traits<BlockType>::HasSameStorageOrderAsXprType ? m_xpr.outerStride() : m_xpr.innerStride();
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr StorageIndex startRow() const noexcept { return m_startRow.value(); }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr StorageIndex startCol() const noexcept { return m_startCol.value(); }
|
||||
|
||||
#ifndef __SUNPRO_CC
|
||||
// FIXME sunstudio is not friendly with the above friend...
|
||||
// META-FIXME there is no 'friend' keyword around here. Is this obsolete?
|
||||
protected:
|
||||
#endif
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \internal used by allowAligned() */
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE BlockImpl_dense(XprType& xpr, const Scalar* data, Index blockRows,
|
||||
Index blockCols)
|
||||
: Base(data, blockRows, blockCols), m_xpr(xpr) {
|
||||
init();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void init() {
|
||||
m_outerStride =
|
||||
internal::traits<BlockType>::HasSameStorageOrderAsXprType ? m_xpr.outerStride() : m_xpr.innerStride();
|
||||
}
|
||||
|
||||
XprTypeNested m_xpr;
|
||||
const internal::variable_if_dynamic<StorageIndex, (XprType::RowsAtCompileTime == 1 && BlockRows == 1) ? 0 : Dynamic>
|
||||
m_startRow;
|
||||
const internal::variable_if_dynamic<StorageIndex, (XprType::ColsAtCompileTime == 1 && BlockCols == 1) ? 0 : Dynamic>
|
||||
m_startCol;
|
||||
Index m_outerStride;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_BLOCK_H
|
||||
@@ -0,0 +1,149 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_COMMAINITIALIZER_H
|
||||
#define EIGEN_COMMAINITIALIZER_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/** \class CommaInitializer
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Helper class used by the comma initializer operator
|
||||
*
|
||||
* This class is internally used to implement the comma initializer feature. It is
|
||||
* the return type of MatrixBase::operator<<, and most of the time this is the only
|
||||
* way it is used.
|
||||
*
|
||||
* \sa \blank \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished()
|
||||
*/
|
||||
template <typename XprType>
|
||||
struct CommaInitializer {
|
||||
typedef typename XprType::Scalar Scalar;
|
||||
|
||||
EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const Scalar& s)
|
||||
: m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) {
|
||||
eigen_assert(m_xpr.rows() > 0 && m_xpr.cols() > 0 && "Cannot comma-initialize a 0x0 matrix (operator<<)");
|
||||
m_xpr.coeffRef(0, 0) = s;
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const DenseBase<OtherDerived>& other)
|
||||
: m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows()) {
|
||||
eigen_assert(m_xpr.rows() >= other.rows() && m_xpr.cols() >= other.cols() &&
|
||||
"Cannot comma-initialize a 0x0 matrix (operator<<)");
|
||||
m_xpr.template block<OtherDerived::RowsAtCompileTime, OtherDerived::ColsAtCompileTime>(0, 0, other.rows(),
|
||||
other.cols()) = other;
|
||||
}
|
||||
|
||||
/* Copy/Move constructor which transfers ownership. This is crucial in
|
||||
* absence of return value optimization to avoid assertions during destruction. */
|
||||
// FIXME in C++11 mode this could be replaced by a proper RValue constructor
|
||||
EIGEN_DEVICE_FUNC inline CommaInitializer(const CommaInitializer& o)
|
||||
: m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) {
|
||||
// Mark original object as finished. In absence of R-value references we need to const_cast:
|
||||
const_cast<CommaInitializer&>(o).m_row = m_xpr.rows();
|
||||
const_cast<CommaInitializer&>(o).m_col = m_xpr.cols();
|
||||
const_cast<CommaInitializer&>(o).m_currentBlockRows = 0;
|
||||
}
|
||||
|
||||
/* inserts a scalar value in the target matrix */
|
||||
EIGEN_DEVICE_FUNC CommaInitializer &operator,(const Scalar& s) {
|
||||
if (m_col == m_xpr.cols()) {
|
||||
m_row += m_currentBlockRows;
|
||||
m_col = 0;
|
||||
m_currentBlockRows = 1;
|
||||
eigen_assert(m_row < m_xpr.rows() && "Too many rows passed to comma initializer (operator<<)");
|
||||
}
|
||||
eigen_assert(m_col < m_xpr.cols() && "Too many coefficients passed to comma initializer (operator<<)");
|
||||
eigen_assert(m_currentBlockRows == 1);
|
||||
m_xpr.coeffRef(m_row, m_col++) = s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* inserts a matrix expression in the target matrix */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC CommaInitializer &operator,(const DenseBase<OtherDerived>& other) {
|
||||
if (m_col == m_xpr.cols() && (other.cols() != 0 || other.rows() != m_currentBlockRows)) {
|
||||
m_row += m_currentBlockRows;
|
||||
m_col = 0;
|
||||
m_currentBlockRows = other.rows();
|
||||
eigen_assert(m_row + m_currentBlockRows <= m_xpr.rows() &&
|
||||
"Too many rows passed to comma initializer (operator<<)");
|
||||
}
|
||||
eigen_assert((m_col + other.cols() <= m_xpr.cols()) &&
|
||||
"Too many coefficients passed to comma initializer (operator<<)");
|
||||
eigen_assert(m_currentBlockRows == other.rows());
|
||||
m_xpr.template block<OtherDerived::RowsAtCompileTime, OtherDerived::ColsAtCompileTime>(m_row, m_col, other.rows(),
|
||||
other.cols()) = other;
|
||||
m_col += other.cols();
|
||||
return *this;
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline ~CommaInitializer()
|
||||
#if defined VERIFY_RAISES_ASSERT && (!defined EIGEN_NO_ASSERTION_CHECKING) && defined EIGEN_EXCEPTIONS
|
||||
noexcept(false) // Eigen::eigen_assert_exception
|
||||
#endif
|
||||
{
|
||||
finished();
|
||||
}
|
||||
|
||||
/** \returns the built matrix once all its coefficients have been set.
|
||||
* Calling finished is 100% optional. Its purpose is to write expressions
|
||||
* like this:
|
||||
* \code
|
||||
* quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished());
|
||||
* \endcode
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline XprType& finished() {
|
||||
eigen_assert(((m_row + m_currentBlockRows) == m_xpr.rows() || m_xpr.cols() == 0) && m_col == m_xpr.cols() &&
|
||||
"Too few coefficients passed to comma initializer (operator<<)");
|
||||
return m_xpr;
|
||||
}
|
||||
|
||||
XprType& m_xpr; // target expression
|
||||
Index m_row; // current row id
|
||||
Index m_col; // current col id
|
||||
Index m_currentBlockRows; // current block height
|
||||
};
|
||||
|
||||
/** \anchor MatrixBaseCommaInitRef
|
||||
* Convenient operator to set the coefficients of a matrix.
|
||||
*
|
||||
* The coefficients must be provided in a row major order and exactly match
|
||||
* the size of the matrix. Otherwise an assertion is raised.
|
||||
*
|
||||
* Example: \include MatrixBase_set.cpp
|
||||
* Output: \verbinclude MatrixBase_set.out
|
||||
*
|
||||
* \note According the c++ standard, the argument expressions of this comma initializer are evaluated in arbitrary
|
||||
* order.
|
||||
*
|
||||
* \sa CommaInitializer::finished(), class CommaInitializer
|
||||
*/
|
||||
template <typename Derived>
|
||||
EIGEN_DEVICE_FUNC inline CommaInitializer<Derived> DenseBase<Derived>::operator<<(const Scalar& s) {
|
||||
return CommaInitializer<Derived>(*static_cast<Derived*>(this), s);
|
||||
}
|
||||
|
||||
/** \sa operator<<(const Scalar&) */
|
||||
template <typename Derived>
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline CommaInitializer<Derived> DenseBase<Derived>::operator<<(
|
||||
const DenseBase<OtherDerived>& other) {
|
||||
return CommaInitializer<Derived>(*static_cast<Derived*>(this), other);
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_COMMAINITIALIZER_H
|
||||
@@ -0,0 +1,173 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2016 Rasmus Munk Larsen (rmlarsen@google.com)
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CONDITIONESTIMATOR_H
|
||||
#define EIGEN_CONDITIONESTIMATOR_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Vector, typename RealVector, bool IsComplex>
|
||||
struct rcond_compute_sign {
|
||||
static inline Vector run(const Vector& v) {
|
||||
const RealVector v_abs = v.cwiseAbs();
|
||||
return (v_abs.array() == static_cast<typename Vector::RealScalar>(0))
|
||||
.select(Vector::Ones(v.size()), v.cwiseQuotient(v_abs));
|
||||
}
|
||||
};
|
||||
|
||||
// Partial specialization to avoid elementwise division for real vectors.
|
||||
template <typename Vector>
|
||||
struct rcond_compute_sign<Vector, Vector, false> {
|
||||
static inline Vector run(const Vector& v) {
|
||||
return (v.array() < static_cast<typename Vector::RealScalar>(0))
|
||||
.select(-Vector::Ones(v.size()), Vector::Ones(v.size()));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \returns an estimate of ||inv(matrix)||_1 given a decomposition of
|
||||
* \a matrix that implements .solve() and .adjoint().solve() methods.
|
||||
*
|
||||
* This function implements Algorithms 4.1 and 5.1 from
|
||||
* http://www.maths.manchester.ac.uk/~higham/narep/narep135.pdf
|
||||
* which also forms the basis for the condition number estimators in
|
||||
* LAPACK. Since at most 10 calls to the solve method of dec are
|
||||
* performed, the total cost is O(dims^2), as opposed to O(dims^3)
|
||||
* needed to compute the inverse matrix explicitly.
|
||||
*
|
||||
* The most common usage is in estimating the condition number
|
||||
* ||matrix||_1 * ||inv(matrix)||_1. The first term ||matrix||_1 can be
|
||||
* computed directly in O(n^2) operations.
|
||||
*
|
||||
* Supports the following decompositions: FullPivLU, PartialPivLU, LDLT, and
|
||||
* LLT.
|
||||
*
|
||||
* \sa FullPivLU, PartialPivLU, LDLT, LLT.
|
||||
*/
|
||||
template <typename Decomposition>
|
||||
typename Decomposition::RealScalar rcond_invmatrix_L1_norm_estimate(const Decomposition& dec) {
|
||||
typedef typename Decomposition::MatrixType MatrixType;
|
||||
typedef typename Decomposition::Scalar Scalar;
|
||||
typedef typename Decomposition::RealScalar RealScalar;
|
||||
typedef typename internal::plain_col_type<MatrixType>::type Vector;
|
||||
typedef typename internal::plain_col_type<MatrixType, RealScalar>::type RealVector;
|
||||
const bool is_complex = (NumTraits<Scalar>::IsComplex != 0);
|
||||
|
||||
eigen_assert(dec.rows() == dec.cols());
|
||||
const Index n = dec.rows();
|
||||
if (n == 0) return 0;
|
||||
|
||||
// Disable Index to float conversion warning
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning push
|
||||
#pragma warning(disable : 2259)
|
||||
#endif
|
||||
Vector v = dec.solve(Vector::Ones(n) / Scalar(n));
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning pop
|
||||
#endif
|
||||
|
||||
// lower_bound is a lower bound on
|
||||
// ||inv(matrix)||_1 = sup_v ||inv(matrix) v||_1 / ||v||_1
|
||||
// and is the objective maximized by the ("super-") gradient ascent
|
||||
// algorithm below.
|
||||
RealScalar lower_bound = v.template lpNorm<1>();
|
||||
if (n == 1) return lower_bound;
|
||||
|
||||
// Gradient ascent algorithm follows: We know that the optimum is achieved at
|
||||
// one of the simplices v = e_i, so in each iteration we follow a
|
||||
// super-gradient to move towards the optimal one.
|
||||
RealScalar old_lower_bound = lower_bound;
|
||||
Vector sign_vector(n);
|
||||
Vector old_sign_vector;
|
||||
Index v_max_abs_index = -1;
|
||||
Index old_v_max_abs_index = v_max_abs_index;
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
sign_vector = internal::rcond_compute_sign<Vector, RealVector, is_complex>::run(v);
|
||||
if (k > 0 && !is_complex && sign_vector == old_sign_vector) {
|
||||
// Break if the solution stagnated.
|
||||
break;
|
||||
}
|
||||
// v_max_abs_index = argmax |real( inv(matrix)^T * sign_vector )|
|
||||
v = dec.adjoint().solve(sign_vector);
|
||||
v.real().cwiseAbs().maxCoeff(&v_max_abs_index);
|
||||
if (v_max_abs_index == old_v_max_abs_index) {
|
||||
// Break if the solution stagnated.
|
||||
break;
|
||||
}
|
||||
// Move to the new simplex e_j, where j = v_max_abs_index.
|
||||
v = dec.solve(Vector::Unit(n, v_max_abs_index)); // v = inv(matrix) * e_j.
|
||||
lower_bound = v.template lpNorm<1>();
|
||||
if (lower_bound <= old_lower_bound) {
|
||||
// Break if the gradient step did not increase the lower_bound.
|
||||
break;
|
||||
}
|
||||
if (!is_complex) {
|
||||
old_sign_vector = sign_vector;
|
||||
}
|
||||
old_v_max_abs_index = v_max_abs_index;
|
||||
old_lower_bound = lower_bound;
|
||||
}
|
||||
// The following calculates an independent estimate of ||matrix||_1 by
|
||||
// multiplying matrix by a vector with entries of slowly increasing
|
||||
// magnitude and alternating sign:
|
||||
// v_i = (-1)^{i} (1 + (i / (dim-1))), i = 0,...,dim-1.
|
||||
// This improvement to Hager's algorithm above is due to Higham. It was
|
||||
// added to make the algorithm more robust in certain corner cases where
|
||||
// large elements in the matrix might otherwise escape detection due to
|
||||
// exact cancellation (especially when op and op_adjoint correspond to a
|
||||
// sequence of backsubstitutions and permutations), which could cause
|
||||
// Hager's algorithm to vastly underestimate ||matrix||_1.
|
||||
Scalar alternating_sign(RealScalar(1));
|
||||
for (Index i = 0; i < n; ++i) {
|
||||
// The static_cast is needed when Scalar is a complex and RealScalar implements expression templates
|
||||
v[i] = alternating_sign * static_cast<RealScalar>(RealScalar(1) + (RealScalar(i) / (RealScalar(n - 1))));
|
||||
alternating_sign = -alternating_sign;
|
||||
}
|
||||
v = dec.solve(v);
|
||||
const RealScalar alternate_lower_bound = (2 * v.template lpNorm<1>()) / (3 * RealScalar(n));
|
||||
return numext::maxi(lower_bound, alternate_lower_bound);
|
||||
}
|
||||
|
||||
/** \brief Reciprocal condition number estimator.
|
||||
*
|
||||
* Computing a decomposition of a dense matrix takes O(n^3) operations, while
|
||||
* this method estimates the condition number quickly and reliably in O(n^2)
|
||||
* operations.
|
||||
*
|
||||
* \returns an estimate of the reciprocal condition number
|
||||
* (1 / (||matrix||_1 * ||inv(matrix)||_1)) of matrix, given ||matrix||_1 and
|
||||
* its decomposition. Supports the following decompositions: FullPivLU,
|
||||
* PartialPivLU, LDLT, and LLT.
|
||||
*
|
||||
* \sa FullPivLU, PartialPivLU, LDLT, LLT.
|
||||
*/
|
||||
template <typename Decomposition>
|
||||
typename Decomposition::RealScalar rcond_estimate_helper(typename Decomposition::RealScalar matrix_norm,
|
||||
const Decomposition& dec) {
|
||||
typedef typename Decomposition::RealScalar RealScalar;
|
||||
eigen_assert(dec.rows() == dec.cols());
|
||||
if (dec.rows() == 0) return NumTraits<RealScalar>::infinity();
|
||||
if (numext::is_exactly_zero(matrix_norm)) return RealScalar(0);
|
||||
if (dec.rows() == 1) return RealScalar(1);
|
||||
const RealScalar inverse_matrix_norm = rcond_invmatrix_L1_norm_estimate(dec);
|
||||
return (numext::is_exactly_zero(inverse_matrix_norm) ? RealScalar(0)
|
||||
: (RealScalar(1) / inverse_matrix_norm) / matrix_norm);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user