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:
+11
@@ -0,0 +1,11 @@
|
|||||||
|
# 编译产物
|
||||||
|
build/
|
||||||
|
devel/
|
||||||
|
install/
|
||||||
|
logs/
|
||||||
|
src/CMakeLists.txt # catkin_make 生成的软链
|
||||||
|
*.pyc
|
||||||
|
__pycache__/
|
||||||
|
|
||||||
|
# onnxruntime 动态库装到 devel/lib 下会被重复安装,不纳入版本管理
|
||||||
|
src/invicta_deploy/third_party/onnxruntime/*/lib/libonnxruntime.so.1.22.0
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2025, DEEPRoboticsLab
|
||||||
|
|
||||||
|
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. Neither the name of the copyright holder 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 HOLDER 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,158 @@
|
|||||||
|
# invicta(火蚁)RL sim2real 工程
|
||||||
|
|
||||||
|
从 DeepRobotics `sdk_deploy` 的 **M20 sim2real 部分**剥离出来的 ROS1(Noetic)工程,并按照厂家完整协议 `proto.md` 把**遥控/设备协议**与**RL 控制**拆成两个节点。
|
||||||
|
|
||||||
|
- 上游参考代码:`sdk_deploy/src/M20_sdk_deploy`(ROS2 / ament / drdds)
|
||||||
|
- 本工程:ROS1 / catkin / Noetic / Ubuntu 20.04
|
||||||
|
- 协议依据:`proto.md`(山猫 M20 basic_server V1.2.0,UDP + JSON)
|
||||||
|
|
||||||
|
> 代码源自 [DeepRoboticsLab/sdk_deploy](https://github.com/DeepRoboticsLab/sdk_deploy) 的 M20 sim2real 部分,遵循 BSD-3-Clause(见 `LICENSE`);已按 ROS1、厂家完整协议与本机器人形态重构。
|
||||||
|
|
||||||
|
## 目录与职责
|
||||||
|
|
||||||
|
```
|
||||||
|
invicta_ws/src/
|
||||||
|
├── invicta_msgs/ 消息与共享值域(只用 3 条自定义消息,其余复用 sensor_msgs)
|
||||||
|
├── invicta_remote/ 遥控/设备协议节点:UDP + JSON ↔ ROS,厂家错误码、状态上报(待实现)
|
||||||
|
├── invicta_deploy/ RL 控制节点:状态机 + ONNX 推理 + 安全检查(不碰网络协议)
|
||||||
|
└── invicta_hardware/ 关节/IMU 数据源 + 关节指令执行端(骨架,硬件 I/O 待实现)
|
||||||
|
```
|
||||||
|
|
||||||
|
这样拆的依据:协议面是平台级接口(控制 + 上报 + 充电/休眠/导航),会跟厂家版本演进;控制面要求 200 Hz 稳定运行、最怕重启。两者生命周期和变更节奏不同。
|
||||||
|
|
||||||
|
## 数据流
|
||||||
|
|
||||||
|
```
|
||||||
|
遥控 App ──UDP:30000 JSON──→ invicta_remote ──/motion_command──→ invicta_deploy
|
||||||
|
↑ │
|
||||||
|
└────────── /motion_state ───────────┘
|
||||||
|
│
|
||||||
|
invicta_hardware ──/joint_states (200 Hz)──→ invicta_deploy ──/joint_commands──→ invicta_hardware
|
||||||
|
──/imu/data (200 Hz)──────→ (200 Hz,RL 状态下 50 Hz)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 话题与消息
|
||||||
|
|
||||||
|
| 话题 | 消息 | 频率 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `/joint_states` | `sensor_msgs/JointState`(标准) | 200 Hz | 关节状态回馈 |
|
||||||
|
| `/imu/data` | `sensor_msgs/Imu`(标准) | 200 Hz | IMU 回报(四元数,弧度) |
|
||||||
|
| `/joint_commands` | `invicta_msgs/JointCommandArray`(自定义) | 200 Hz / RL 下 50 Hz | 关节指令(kp/kd/前馈/控制字) |
|
||||||
|
| `/motion_command` | `invicta_msgs/MotionCommand`(自定义) | 事件 + 轴指令帧 | 协议节点 → RL 节点 |
|
||||||
|
| `/motion_state` | `invicta_msgs/MotionState`(自定义) | 20 Hz | RL 节点 → 协议节点(真实状态) |
|
||||||
|
|
||||||
|
消息细节见 [`src/invicta_msgs/README.md`](src/invicta_msgs/README.md)。
|
||||||
|
|
||||||
|
## 频率
|
||||||
|
|
||||||
|
| 环节 | 频率 | 出处 |
|
||||||
|
|---|---|---|
|
||||||
|
| 控制周期 | 200 Hz(5 ms) | `control_period_ms: 5` |
|
||||||
|
| RL 策略 | 50 Hz(decimation 4) | `InvictaPolicyRunner::SetDecimation(4)`,`agent_timestep=0.02` |
|
||||||
|
| 关节状态 / IMU 上报 | 200 Hz | 与上游 M20 仿真发布一致;低于 100 Hz 明显退化,50 Hz 是功能下限 |
|
||||||
|
| 状态回报 `/motion_state` | 20 Hz | 协议里基础状态上报是 2 Hz,从这里取即可 |
|
||||||
|
| 协议轴指令 | 协议建议 ≥20 Hz | 实测老版 App 静杆时更低,动杆时待确认 |
|
||||||
|
|
||||||
|
上游厂商侧口径:Lite3 的数据面上限 200 Hz 且必须整除 1000(内部 1 kHz)。M20 实机的真实上报频率请在接上硬件后用 `rostopic hz` 实测。
|
||||||
|
|
||||||
|
## 关键约定:硬件约定 vs policy 约定
|
||||||
|
|
||||||
|
关节量有两套约定,**必须只施加一次**:
|
||||||
|
|
||||||
|
- 硬件约定:电机方向、编码器零点、单位(CAN 原始值)。
|
||||||
|
- policy 约定:与 `policy.onnx` 训练一致(rad / rad/s / Nm)。
|
||||||
|
|
||||||
|
默认由 `invicta_hardware` 承担换算,话题上流动的就是 policy 约定;因此 `invicta_deploy` 的 `calibration/joint_dir` 全 1、`joint_offset_deg` 全 0、`auto_calibrate=false`。若反过来让 RL 节点承担,则填 M20 的表并打开 `auto_calibrate`:
|
||||||
|
|
||||||
|
| | 值 |
|
||||||
|
|---|---|
|
||||||
|
| `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]` |
|
||||||
|
|
||||||
|
两条 M20 遗留语义保持原样:轮关节(下标 `%4==3`)指令 `kp` 强制 0(`wheel_kp_zero`);关节顺序固定为 `fl/fr/hl/hr × hipx/hipy/knee/wheel`,与 `policy.onnx` 绑定。
|
||||||
|
|
||||||
|
## 步态 = RL 模型
|
||||||
|
|
||||||
|
厂家协议里的 `GaitParam` 不是简单参数,**每个步态对应一个 RL 模型**:
|
||||||
|
|
||||||
|
| GaitParam | 步态 | 当前 |
|
||||||
|
|---|---|---|
|
||||||
|
| `0x1001` 4097 | 基础(标准,平地) | ✅ 默认模型 |
|
||||||
|
| `0x3002` 12290 | 平地(敏捷) | ❌ 未提供模型,请求被拒绝(训练好后在 `gait/policy_map` 填路径) |
|
||||||
|
| `0x1003` 4099 | 楼梯(标准) | ❌ 同上 |
|
||||||
|
| `0x3003` 12291 | 楼梯(敏捷) | ❌ 同上 |
|
||||||
|
|
||||||
|
`invicta_deploy` 支持多模型:启动时把 `gait/policy_map` 里提供了路径的步态全部预加载,运行中按当前步态切换(切换时清空该模型的 `last_action`)。**只有真正加载成功的步态才接受切换**,`/motion_state.gait` 只报实际生效值,不会出现"显示切了但还在用旧模型"。
|
||||||
|
|
||||||
|
## 构建(Ubuntu 20.04 + ROS Noetic)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source /opt/ros/noetic/setup.bash
|
||||||
|
cd invicta_ws
|
||||||
|
catkin_make -j4 # 交叉编译:-DBUILD_PLATFORM=arm
|
||||||
|
source devel/setup.bash
|
||||||
|
```
|
||||||
|
|
||||||
|
依赖:`roscpp`、`roslib`、`sensor_msgs`、`std_msgs` + 自建 `invicta_msgs`。`eigen`、`onnxruntime 1.22`(x86/aarch64)、`policy.onnx` 已 vendor,无需联网。
|
||||||
|
|
||||||
|
## 运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1) 硬件桥接(当前是骨架:发零位状态、不驱动电机)
|
||||||
|
roslaunch invicta_hardware invicta_hardware.launch
|
||||||
|
|
||||||
|
# 2) 协议节点(UDP 30000)
|
||||||
|
roslaunch invicta_remote invicta_remote.launch
|
||||||
|
|
||||||
|
# 3) RL 控制
|
||||||
|
roslaunch invicta_deploy invicta_deploy.launch
|
||||||
|
# 无硬件台架(状态是零位)时必须关掉自检,否则站立后不会自动进 RL:
|
||||||
|
# roslaunch invicta_deploy invicta_deploy.launch rl_require_pose:=false rl_require_imu:=false
|
||||||
|
|
||||||
|
# 无硬件自检(起 roscore + 三个节点,测话题/频率/协议/ONNX)
|
||||||
|
bash src/invicta_deploy/scripts/smoke_test.sh
|
||||||
|
|
||||||
|
# 无遥控器时模拟协议报文
|
||||||
|
python3 src/invicta_remote/scripts/protocol_udp_test.py --steer 0.3,0,0 --motion 1
|
||||||
|
```
|
||||||
|
|
||||||
|
遥控器(云卓 G20)在 App 里把目标地址设为本机 IP、端口 30000。老版 App 用 `2/22 MotionParam` 切状态,新版(≥ V1.5.11)用 `1101/12` 按键事件,两套都支持。
|
||||||
|
|
||||||
|
## 已验证到什么程度
|
||||||
|
|
||||||
|
在 `localhost/custom-ros-noetic:v1.0`(Ubuntu 20.04 + ROS Noetic)容器里实测:
|
||||||
|
|
||||||
|
| 项目 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| 四个包 catkin_make | 通过 |
|
||||||
|
| `ldd` 解析 `libonnxruntime.so.1` | 通过(RPATH 生效) |
|
||||||
|
| `/joint_states` | 200.001 Hz,关节名/顺序正确 |
|
||||||
|
| `/joint_commands` | 站立 200 Hz;RL 状态 50.001 Hz,策略输出正常(kp=80,kd=2/0.6) |
|
||||||
|
| `/motion_state` | 20.000 Hz,RL 时 `motion_state=17`、`gait=4097` |
|
||||||
|
| 协议:心跳 / 轴指令 / MotionParam | 回 0,状态机正确切换(空闲→站立→RL) |
|
||||||
|
| 状态上报 `1002/3,4,5,6` | 2 / 10 / 2 / 2 Hz;RL 时 `BasicStatus.MotionState=17`、切步态后 `Gait` 同步变化 |
|
||||||
|
| 协议:非 RL 下切步态 | 回 `0xE008 Not allowed operation`(57352) |
|
||||||
|
| 协议:楼梯步态 | 协议节点回 0(已接收),RL 节点拒绝并记录"模型尚未注册" |
|
||||||
|
| 协议:照明灯 / 导航模式 / 未知命令 | `0xE00A`(57354)/ `0xE00A` / `0xE003`(57347) |
|
||||||
|
| 手柄实测(真遥控器) | 心跳、摇杆、MotionParam、照明灯、使用模式报文均能收到并正确应答 |
|
||||||
|
|
||||||
|
**未验证**:真实电机与 IMU(`invicta_hardware` 的 `ReadHardware/WriteHardware` 还是 TODO)、实机上报频率、新机器人几何参数、状态上报(未实现)。
|
||||||
|
|
||||||
|
## 与上游 M20 的差异
|
||||||
|
|
||||||
|
保留:状态机五状态、ONNX 策略与关节顺序/动作尺度、安全检查、厂家协议的头/JSON 结构与心跳、`eigen`/`onnxruntime`/`policy.onnx`。
|
||||||
|
|
||||||
|
删除或改写:ROS2→ROS1;`drdds` 消息→标准消息 + 3 条自定义;电池订阅(上游死代码);键盘控制模式;`third_party/gamepad`(未被引用);Mujoco 仿真与 `M20_description`;Lite3 三个包;`backward.hpp` 死代码;M20 几何硬编码→ROS 参数;原厂控制字→平台无关控制字;**UDP/JSON 协议层从 RL 进程拆到 `invicta_remote`**。
|
||||||
|
|
||||||
|
## 已知缺口
|
||||||
|
|
||||||
|
1. **设备状态数据未接**(`1002/5` 的电池/温度/CPU/GPS):报文结构已按协议发出,但数值是占位 0,需要 `invicta_hardware` 提供(建议标准消息,如 `sensor_msgs/BatteryState`)。运控状态里的线速度/高度/剩余里程同理。
|
||||||
|
2. **遥控断连不停机**:协议层 3 s 判离线只登记/log;`UserCommand.time_stamp` 已写入但断连判断未接线,策略会沿用最后一帧指令。当前按"硬件急停兜底"处理。
|
||||||
|
3. **未实现功能**:照明灯、休眠、自主充电、导航模式/速度指令(均回 `0xE00A`)。
|
||||||
|
4. **关节温度与驱动器状态字缺失**:`sensor_msgs/JointState` 无对应字段,是相对 M20 少的保护项(详见 `invicta_msgs/README.md`)。
|
||||||
|
5. **中文日志**:`ROS_*` 文案在非 UTF-8 locale 下显示为 `?`(容器内实测),机器人上用 UTF-8 终端则正常。
|
||||||
|
6. **`charge/hes/sleep` 恒为 0**:需要硬件侧提供充电状态、硬急停信号与休眠管理。
|
||||||
|
|
||||||
|
## 版本管理
|
||||||
|
|
||||||
|
`third_party/eigen`(22 MB)与 `third_party/onnxruntime`(113 MB)是 vendor 的二进制/头文件,便于离线构建;嫌大可改为系统 Eigen + 单独分发 ORT。
|
||||||
@@ -0,0 +1,612 @@
|
|||||||
|
# 山猫 M20 basic_server 通信协议(UDP + JSON)
|
||||||
|
|
||||||
|
本协议基于 TCP/UDP 传输层,本项目使用 **UDP + JSON** 模式。机器人本体为服务端,上位机(Android App)为客户端。
|
||||||
|
|
||||||
|
- **协议版本**: V1.2.0
|
||||||
|
- **更新日期**: 2026-05-18
|
||||||
|
- **服务端地址**: `10.21.31.103:30000` (UDP)
|
||||||
|
- **载荷编码**: JSON(协议头 `ASDU格式` 字段填 `0x01`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. APDU 报文结构
|
||||||
|
|
||||||
|
```
|
||||||
|
+---------------------+------------------+
|
||||||
|
| Header (16 bytes) | ASDU (JSON 文本) |
|
||||||
|
+---------------------+------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.1 Header(固定 16 字节,小端 LE)
|
||||||
|
|
||||||
|
| 偏移 | 长度 | 字段 | 值 | 说明 |
|
||||||
|
| ---: | ---: | --- | --- | --- |
|
||||||
|
| 0 | 1 | Sync0 | `0xEB` | 固定 |
|
||||||
|
| 1 | 1 | Sync1 | `0x91` | 固定 |
|
||||||
|
| 2 | 1 | Sync2 | `0xEB` | 固定 |
|
||||||
|
| 3 | 1 | Sync3 | `0x90` | 固定 |
|
||||||
|
| 4 | 2 | Length | u16 LE | ASDU 字节长度,最大 65535 |
|
||||||
|
| 6 | 2 | MsgId | u16 LE | 请求/响应配对;请求方从 0 递增,回绕 65535→0 |
|
||||||
|
| 8 | 1 | Format | `0x01` | JSON(XML 为 `0x00`) |
|
||||||
|
| 9 | 7 | Reserved | `0x00`×7 | 预留 |
|
||||||
|
|
||||||
|
### 1.2 ASDU(JSON 格式)
|
||||||
|
|
||||||
|
固定外层包裹 `PatrolDevice`,包含 4 个通用字段:
|
||||||
|
|
||||||
|
| 字段 | 类型 | 含义 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Type` | int | 消息类型(十进制) |
|
||||||
|
| `Command` | int | 命令码(十进制) |
|
||||||
|
| `Time` | string | 本地时区,格式 `YYYY-MM-DD HH:MM:SS` |
|
||||||
|
| `Items` | object | 参数项,视 Type/Command 而定 |
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 100,
|
||||||
|
"Command": 100,
|
||||||
|
"Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 控制类指令(上位机 → 机器人)
|
||||||
|
|
||||||
|
### 2.1 心跳指令
|
||||||
|
|
||||||
|
| Type | Command | 频率 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 100 | 100 | ≥1 Hz |
|
||||||
|
|
||||||
|
`Items` 为空。服务端记录来源 IP/端口,并按需推送状态上报(见第 3 节)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.2 使用模式切换
|
||||||
|
|
||||||
|
| Type | Command | 说明 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 1101 | 5 | 切换机器人使用模式 |
|
||||||
|
|
||||||
|
**Items**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Mode` | int | `0`=常规模式 · `1`=导航模式 · `2`=辅助模式 |
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 1101, "Command": 5, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": { "Mode": 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **常规模式**:支持轴指令(Type=2, Cmd=21)
|
||||||
|
- **导航模式**:支持速度指令(Type=2, Cmd=25)和导航任务
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.3 运动状态转换
|
||||||
|
|
||||||
|
| Type | Command | 说明 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 2 | 22 | 机器人运动状态转换 |
|
||||||
|
|
||||||
|
**Items**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `MotionParam` | int | `0`=空闲 · `1`=站立 · `2`=关节阻尼/软急停 · `3`=开机阻尼 · `4`=趴下 · `17`=RL控制 |
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 2, "Command": 22, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": { "MotionParam": 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
状态流转:`空闲 → 站立 → RL控制` 为正向流程。RL 控制状态下才能下发步态切换和运动指令。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.4 步态切换
|
||||||
|
|
||||||
|
| Type | Command | 说明 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 2 | 23 | 切换步态(需在 RL 控制下) |
|
||||||
|
|
||||||
|
**Items**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `GaitParam` | int | 见下表 |
|
||||||
|
|
||||||
|
| 值 | 步态 | 适用模式 |
|
||||||
|
| ---: | --- | --- |
|
||||||
|
| `0x1001` | 基础(标准运动模式) | 常规/辅助/导航 |
|
||||||
|
| `0x1003` | 楼梯(标准运动模式) | 常规/辅助/导航 |
|
||||||
|
| `0x3002` | 平地(敏捷运动模式) | 辅助/导航 |
|
||||||
|
| `0x3003` | 楼梯(敏捷运动模式) | 辅助/导航 |
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 2, "Command": 23, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": { "GaitParam": 4097 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 敏捷运动模式速度响应更好,适合自主算法开发
|
||||||
|
- 每次起立后或切换使用模式时,步态重置为基础步态 `0x1001`
|
||||||
|
- 步态切换仅支持在 **RL 控制** 状态下执行
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.5 运动控制(轴指令 — 常规模式)
|
||||||
|
|
||||||
|
| Type | Command | 说明 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 2 | 21 | 速度比例控制,仅常规模式 |
|
||||||
|
|
||||||
|
**Items** (全部 float, 范围 [-1, 1]):
|
||||||
|
|
||||||
|
| 参数 | 含义 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `X` | 前后方向速度比例 | 正=前进,负=后退 |
|
||||||
|
| `Y` | 左右方向速度比例 | 正=左移,负=右移 |
|
||||||
|
| `Z` | 高度方向速度比例 | 正=向上,负=向下 |
|
||||||
|
| `Roll` | 翻滚角速度比例 | |
|
||||||
|
| `Pitch` | 俯仰角速度比例 | |
|
||||||
|
| `Yaw` | 偏航角速度比例 | 正=逆时针,负=顺时针 |
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 2, "Command": 21, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": { "X": 0.5, "Y": 0.0, "Z": 0.0, "Roll": 0.0, "Pitch": 0.0, "Yaw": 0.0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 建议发送频率 ≥20 Hz
|
||||||
|
- 常规模式的基础/楼梯步态仅 `X`, `Y`, `Yaw` 生效
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.6 运动控制(速度指令 — 导航模式)
|
||||||
|
|
||||||
|
| Type | Command | 说明 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 2 | 25 | 速度绝对值控制,仅导航模式 |
|
||||||
|
|
||||||
|
**Items** (全部 float, 带物理单位):
|
||||||
|
|
||||||
|
| 参数 | 含义 | 单位 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `X` | 前后方向速度 | m/s |
|
||||||
|
| `Y` | 左右方向速度 | m/s |
|
||||||
|
| `Z` | 高度方向速度 | m/s |
|
||||||
|
| `Roll` | 翻滚角速度 | rad/s |
|
||||||
|
| `Pitch` | 俯仰角速度 | rad/s |
|
||||||
|
| `Yaw` | 偏航角速度 | rad/s |
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 2, "Command": 25, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": { "X": 0.5, "Y": 0.0, "Z": 0.0, "Roll": 0.0, "Pitch": 0.0, "Yaw": 0.0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.7 照明灯控制
|
||||||
|
|
||||||
|
| Type | Command | 说明 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 1101 | 2 | 照明灯开关 |
|
||||||
|
|
||||||
|
**Items**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Front` | int | `0`=关闭 · `1`=开启 |
|
||||||
|
| `Back` | int | `0`=关闭 · `1`=开启 |
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 1101, "Command": 2, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": { "Front": 1, "Back": 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.8 自主充电
|
||||||
|
|
||||||
|
| Type | Command | 说明 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 2 | 24 | 自主充电控制 |
|
||||||
|
|
||||||
|
**Items**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Charge` | int | `0`=结束充电 · `1`=开始充电 · `2`=清除充电状态(强制归零,谨慎使用) |
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 2, "Command": 24, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": { "Charge": 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.9 休眠模式设置
|
||||||
|
|
||||||
|
| Type | Command | 说明 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 1101 | 6 | 设置休眠模式 |
|
||||||
|
|
||||||
|
**Items**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Sleep` | bool | `true`=进入休眠 · `false`=唤醒 |
|
||||||
|
| `Auto` | bool | `true`=启用自动休眠 · `false`=关闭 |
|
||||||
|
| `Time` | uint | 自动休眠等待时间(分钟),范围 [5, 30] |
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 1101, "Command": 6, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": { "Sleep": false, "Auto": true, "Time": 5 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.10 休眠状态查询
|
||||||
|
|
||||||
|
| Type | Command | 说明 |
|
||||||
|
| ---: | ---: | --- |
|
||||||
|
| 1101 | 7 | 查询休眠状态及设置 |
|
||||||
|
|
||||||
|
`Items` 为空。响应同 2.9 的 Items 结构(`Sleep`, `Auto`, `Time`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 状态上报(机器人 → 上位机)
|
||||||
|
|
||||||
|
UDP 下需先发一次对应查询请求触发订阅,服务端记录来源 IP/端口后持续推送。
|
||||||
|
|
||||||
|
### 3.1 基础状态上报 — Type=1002, Cmd=6
|
||||||
|
|
||||||
|
**频率**: 2 Hz
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 1002, "Command": 6, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": {
|
||||||
|
"BasicStatus": {
|
||||||
|
"MotionState": 0,
|
||||||
|
"Gait": 0,
|
||||||
|
"Charge": 0,
|
||||||
|
"HES": 0,
|
||||||
|
"ControlUsageMode": 0,
|
||||||
|
"Direction": 0,
|
||||||
|
"OOA": 0,
|
||||||
|
"PowerManagement": 0,
|
||||||
|
"Sleep": 0,
|
||||||
|
"Version": "STD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `MotionState` | int | `0`=空闲 · `1`=站立 · `2`=软急停 · `3`=开机阻尼 · `4`=趴下 · `17`=RL控制 |
|
||||||
|
| `Gait` | int | `0x1001`=基础 · `0x1003`=楼梯 · `0x3002`=平地敏捷 · `0x3003`=楼梯敏捷 |
|
||||||
|
| `Charge` | int | `0`=空闲 · `1`=前往充电桩 · `2`=充电中 · `3`=退出充电桩 · `4`=异常 · `5`=在桩上未充电 |
|
||||||
|
| `HES` | int | `0`=未触发 · `1`=已触发(硬急停) |
|
||||||
|
| `ControlUsageMode` | int | `0`=常规 · `1`=导航 · `2`=辅助 |
|
||||||
|
| `Direction` | int | `0`=正向为前进正方向 · `1`=后向为前进正方向 |
|
||||||
|
| `OOA` | int | `0`=未启动 · `1`=空闲中 · `2`=未触发避障 · `3`=主动避障中 |
|
||||||
|
| `PowerManagement` | int | `0`=常规 · `1`=单电池模式 |
|
||||||
|
| `Sleep` | int | `0`=未休眠 · `1`=已休眠 · `2`=进入休眠中 |
|
||||||
|
| `Version` | string | `STD`=山猫M20 · `PRO`=山猫M20 Pro |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.2 运控状态上报 — Type=1002, Cmd=4
|
||||||
|
|
||||||
|
**频率**: 10 Hz
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 1002, "Command": 4, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": {
|
||||||
|
"MotionStatus": {
|
||||||
|
"Roll": 0.0, "Pitch": 0.0, "Yaw": 0.0,
|
||||||
|
"OmegaZ": 0.0, "LinearX": 0.0, "LinearY": 0.0,
|
||||||
|
"Height": 0.0, "Payload": 0.0, "RemainMile": 0.0
|
||||||
|
},
|
||||||
|
"MotorStatus": {
|
||||||
|
"Joint": [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],
|
||||||
|
"LeftFrontHipX": 0.0, "LeftFrontHipY": 0.0, "LeftFrontKnee": 0.0, "LeftFrontWheel": 0.0,
|
||||||
|
"RightFrontHipX": 0.0, "RightFrontHipY": 0.0, "RightFrontKnee": 0.0, "RightFrontWheel": 0.0,
|
||||||
|
"LeftBackHipX": 0.0, "LeftBackHipY": 0.0, "LeftBackKnee": 0.0, "LeftBackWheel": 0.0,
|
||||||
|
"RightBackHipX": 0.0, "RightBackHipY": 0.0, "RightBackKnee": 0.0, "RightBackWheel": 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**MotionStatus**:
|
||||||
|
|
||||||
|
| 字段 | 单位 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Roll/Pitch/Yaw` | rad | 机身姿态角 |
|
||||||
|
| `OmegaZ` | rad/s | Z 方向角速度 |
|
||||||
|
| `LinearX/LinearY` | m/s | X/Y 方向线速度 |
|
||||||
|
| `Height` | m | 机身高度 |
|
||||||
|
| `RemainMile` | km | 预计剩余续航里程 |
|
||||||
|
|
||||||
|
**MotorStatus** — 16 关节顺序:LeftFrontHipX, HipY, Knee, Wheel → RightFrontHipX, HipY, Knee, Wheel → LeftBack... → RightBack...
|
||||||
|
|
||||||
|
| 字段 | 单位 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Joint` | rad / rad/s | 16 元素数组,关节角度/转速 |
|
||||||
|
| `*HipX` | rad | 侧摆关节角度 |
|
||||||
|
| `*HipY` | rad | 髋关节角度 |
|
||||||
|
| `*Knee` | rad | 膝关节角度 |
|
||||||
|
| `*Wheel` | rad/s | 足轮转速 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.3 设备状态上报 — Type=1002, Cmd=5
|
||||||
|
|
||||||
|
**频率**: 2 Hz。包含 BatteryList, BatteryStatus, DeviceTemperature, Led, GPS, DevEnable, CPU 七组参数。
|
||||||
|
|
||||||
|
**BatteryList** (2 块电池):
|
||||||
|
```json
|
||||||
|
"BatteryList": [
|
||||||
|
{ "Voltage": 0.0, "BatteryLevel": 100.0, "battery_temperature": 0.0, "charge": false, "serial": "xxx" },
|
||||||
|
{ "Voltage": 0.0, "BatteryLevel": 100.0, "battery_temperature": 0.0, "charge": false, "serial": "xxx" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**BatteryStatus**:
|
||||||
|
```json
|
||||||
|
"BatteryStatus": {
|
||||||
|
"VoltageLeft": 0.0, "VoltageRight": 0.0,
|
||||||
|
"BatteryLevelLeft": 0.0, "BatteryLevelRight": 0.0,
|
||||||
|
"battery_temperatureLeft": 0.0, "battery_temperatureRight": 0.0,
|
||||||
|
"chargeLeft": false, "chargeRight": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**DeviceTemperature** — 16 电机 + 16 驱动器温度:
|
||||||
|
```json
|
||||||
|
"DeviceTemperature": {
|
||||||
|
"Motor": [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],
|
||||||
|
"Driver": [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],
|
||||||
|
"LeftFrontHipXMotor": 0.0, "LeftFrontHipXDriver": 0.0, ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Led**:
|
||||||
|
```json
|
||||||
|
"Led": { "Fill": { "Front": 1, "Back": 1 } }
|
||||||
|
```
|
||||||
|
|
||||||
|
**GPS**:
|
||||||
|
```json
|
||||||
|
"GPS": {
|
||||||
|
"Latitude": 0.0, "Longitude": 0.0, "Speed": 0.0, "Course": 0.0,
|
||||||
|
"FixQuality": 0, "NumSatellites": 0, "Altitude": 0.0,
|
||||||
|
"HDOP": 0.0, "VDOP": 0.0, "PDOP": 0.0, "VisibleSatellites": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**DevEnable**:
|
||||||
|
```json
|
||||||
|
"DevEnable": {
|
||||||
|
"FanSpeed": 100, "LoadPower": 1, "LedHost": 1, "LedExt": 1, "FP": 1,
|
||||||
|
"Lidar": { "Front": 1, "Back": 1 },
|
||||||
|
"GPS": 1,
|
||||||
|
"Video": { "Front": 1, "Back": 1 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**CPU**:
|
||||||
|
```json
|
||||||
|
"CPU": {
|
||||||
|
"AOS": { "Temperature": 0.0, "FrequencyInt": 0.0, "FrequencyApp": 0.0 },
|
||||||
|
"NOS": { "Temperature": 0.0, "FrequencyInt": 0.0, "FrequencyApp": 0.0 },
|
||||||
|
"GOS": { "Temperature": 0.0, "FrequencyInt": 0.0, "FrequencyApp": 0.0 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.4 异常状态上报 — Type=1002, Cmd=3
|
||||||
|
|
||||||
|
**频率**: 2 Hz,状态变更时即时上报。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 1002, "Command": 3, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": {
|
||||||
|
"ErrorList": [
|
||||||
|
{ "errorCode": 32769, "component": 1 },
|
||||||
|
{ "errorCode": 32770, "component": 4 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `errorCode` | int | 错误码,见下文 |
|
||||||
|
| `component` | int | bit 位标识部件编号(关节/电池) |
|
||||||
|
|
||||||
|
`component` 关节位编号(自低位起):FL HipX(0) → FL HipY(1) → FL Knee(2) → FL Wheel(3) → FR HipX(4) → ... → RB Wheel(15)。电池位编号:bit0=后侧电池,bit1=前侧电池。
|
||||||
|
|
||||||
|
常见错误码(部分):
|
||||||
|
|
||||||
|
| errorCode | 含义 | errorCode | 含义 |
|
||||||
|
| ---: | --- | ---: | --- |
|
||||||
|
| `0x8001` | 电机温度预警 | `0x8002` | 电机温度过高保护 |
|
||||||
|
| `0x8003` | 电机温度致命截止 | `0x8007` | 关节驱动器过温 |
|
||||||
|
| `0x8008` | 驱动器欠压保护 | `0x8009` | 驱动器过压保护 |
|
||||||
|
| `0x8012` | 与关节驱动器通讯超时 | `0x8016` | 编码器无值 |
|
||||||
|
| `0x8020` | 驱动器过流保护 | `0x8102` | 低电量预警 |
|
||||||
|
| `0x8103` | 保护电量 | `0x8107` | 电池放电过温保护 |
|
||||||
|
| `0x8115` | 电池充电过温保护 | `0x8117` | 电池单体过压保护 |
|
||||||
|
| `0x8201` | CPU占用率过高预警 | `0x8202` | CPU温度过高预警 |
|
||||||
|
| `0x8211` | CPU占用率过高保护 | `0x8212` | CPU温度过高保护 |
|
||||||
|
| `0x8501` | 自主充电定位超时 | `0x8503` | 自主充电定位异常 |
|
||||||
|
| `0x8506` | 充电桩无电流 | `0x8507` | 充电停障错误 |
|
||||||
|
| `0x8510` | 退桩超时 | `0x8022` | 关节角超限 |
|
||||||
|
| `0x8027` | 机身姿态错误 | `0x8029` | 运动姿态错误 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 通用响应与错误码
|
||||||
|
|
||||||
|
每一条请求都会收到同 Type/Command 的响应,Items 至少包含 ErrorCode 和 ErrorMessage:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"PatrolDevice": {
|
||||||
|
"Type": 100, "Command": 100, "Time": "2026-07-17 12:00:00",
|
||||||
|
"Items": { "ErrorCode": 0, "ErrorMessage": "Success" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| ErrorCode (hex) | dec | ErrorMessage | 含义 |
|
||||||
|
| --- | ---: | --- | --- |
|
||||||
|
| `0x0000` | 0 | Success | 命令已接收并触发(不代表业务成功) |
|
||||||
|
| `0xE001` | 57345 | Unsupported data format | 帧头 Format 非 JSON/XML |
|
||||||
|
| `0xE002` | 57346 | Data parsing failed | 缺少 PatrolDevice/Items/Type/Command |
|
||||||
|
| `0xE003` | 57347 | Unsupported protocol type | Type/Command 组合不存在 |
|
||||||
|
| `0xE004` | 57348 | Missing necessary fields | Items 缺字段 |
|
||||||
|
| `0xE005` | 57349 | Mismatched data type | 字段类型不匹配 |
|
||||||
|
| `0xE006` | 57350 | Mismatched request client | 2s 内轴指令须来自同一客户端 |
|
||||||
|
| `0xE007` | 57351 | No operation permission | 无操作权限 |
|
||||||
|
| `0xE008` | 57352 | Not allowed operation | 状态机不允许 |
|
||||||
|
| `0xE009` | 57353 | Operation failure | 操作失败,查 Cmd=3 错误详情 |
|
||||||
|
| `0xE00A` | 57354 | Unsupported function | 固件不支持(如导航需 Pro) |
|
||||||
|
| `0xE00B` | 57355 | Internal error | 内部错误,查日志 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 导航任务(Pro 版本)
|
||||||
|
|
||||||
|
以下指令仅山猫 M20 Pro 支持。
|
||||||
|
|
||||||
|
### 5.1 下发单点导航 — Type=1003, Cmd=1
|
||||||
|
|
||||||
|
**Items**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Value` | int | 目标点编号(默认 0) |
|
||||||
|
| `MapID` | int | 地图编号(默认 0) |
|
||||||
|
| `PosX/Y/Z` | float | 目标点在地图坐标系中的位置 (m) |
|
||||||
|
| `AngleYaw` | float | 目标点朝向 (rad) |
|
||||||
|
| `PointInfo` | int | `0`=过渡点 · `1`=任务点 · `3`=充电点 |
|
||||||
|
| `Gait` | int | `0x3002`=平地敏捷 · `0x3003`=楼梯敏捷 |
|
||||||
|
| `Speed` | int | `0`=正常 · `1`=低速 · `2`=高速 |
|
||||||
|
| `Manner` | int | `0`=前进行走 · `1`=倒退行走 |
|
||||||
|
| `ObsMode` | int | `0`=开启停避障 · `1`=关闭 |
|
||||||
|
| `NavMode` | int | `0`=直线导航 · `1`=自主导航 |
|
||||||
|
|
||||||
|
### 5.2 取消导航 — Type=1004, Cmd=1
|
||||||
|
|
||||||
|
`Items` 为空。响应 `ErrorCode`: `0`=成功, `1`=失败。
|
||||||
|
|
||||||
|
### 5.3 查询导航任务状态 — Type=1007, Cmd=1
|
||||||
|
|
||||||
|
`Items` 为空。响应包含 `Value`, `Status`, `ErrorCode`。
|
||||||
|
|
||||||
|
`Status`: `0`=空闲 · `1`=退出充电桩中 · `2`=导航预处理 · `3`=导航中 · `4`=导航完成 · `5`=进入充电桩中 · `0xFF`=暂停中
|
||||||
|
|
||||||
|
### 5.4 获取地图位置 — Type=1007, Cmd=2
|
||||||
|
|
||||||
|
**响应 Items**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Location` | int | `0`=定位正常 · `1`=定位丢失 |
|
||||||
|
| `PosX/Y/Z` | float | 地图坐标 (m) |
|
||||||
|
| `Roll/Pitch/Yaw` | float | 姿态角 (rad) |
|
||||||
|
|
||||||
|
### 5.5 初始化定位 — Type=2101, Cmd=1
|
||||||
|
|
||||||
|
**Items**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `PosX/Y/Z` | float | 重新定位坐标 (m) |
|
||||||
|
| `Yaw` | float | 绕 Z 轴姿态角 (rad) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 手柄 App 接口清单
|
||||||
|
|
||||||
|
| 用途 | Type | Cmd | 方向 | 频率 |
|
||||||
|
| --- | ---: | ---: | --- | --- |
|
||||||
|
| 心跳保活 | 100 | 100 | 上位机→机器人 | ≥1 Hz |
|
||||||
|
| 使用模式切换 | 1101 | 5 | 上位机→机器人 | 事件 |
|
||||||
|
| 运动状态转换 | 2 | 22 | 上位机→机器人 | 事件 |
|
||||||
|
| 步态切换 | 2 | 23 | 上位机→机器人 | 事件 |
|
||||||
|
| 轴指令(常规模式) | 2 | 21 | 上位机→机器人 | ≥20 Hz |
|
||||||
|
| 速度指令(导航模式) | 2 | 25 | 上位机→机器人 | ≥10 Hz |
|
||||||
|
| 照明灯控制 | 1101 | 2 | 上位机→机器人 | 事件 |
|
||||||
|
| 自主充电 | 2 | 24 | 上位机→机器人 | 事件 |
|
||||||
|
| 休眠设置 | 1101 | 6 | 上位机→机器人 | 事件 |
|
||||||
|
| 订阅基础状态 | 1002 | 6 | 双向 | 2 Hz 推送 |
|
||||||
|
| 订阅运控状态 | 1002 | 4 | 双向 | 10 Hz 推送 |
|
||||||
|
| 订阅设备状态 | 1002 | 5 | 双向 | 2 Hz 推送 |
|
||||||
|
| 订阅异常状态 | 1002 | 3 | 双向 | 2 Hz / 即时 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 实现要点
|
||||||
|
|
||||||
|
1. UDP socket 绑定本地随机端口(源端口即为上报回执地址)。
|
||||||
|
2. 心跳线程 1 Hz,发 `Type=100, Cmd=100`。
|
||||||
|
3. 速度/轴指令线程 ≥20 Hz(无输入时发零速度保持连接)。
|
||||||
|
4. 接收线程:解析 16 字节 header → 按 `Length` 读 JSON 字节 → 分发 handler。
|
||||||
|
5. 请求 MsgId 从 0 递增,用于匹配响应帧。
|
||||||
|
6. 首次连接时主动发 `1002/4`, `1002/5`, `1002/6`, `1002/3` 触发 UDP 订阅推送。
|
||||||
|
7. 断线判定:>3 s 无任何 UDP 包 → 标记离线并 UI 提示。
|
||||||
|
8. 轴指令 `X/Y/Yaw` 比例 [-1,1] 需映射到手柄摇杆范围。
|
||||||
|
9. 步态切换仅 RL 控制状态下有效,需先发 `MotionParam=17`。
|
||||||
|
10. 导航模式切换后需等待 `BasicStatus.ControlUsageMode` 确认。
|
||||||
@@ -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
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user