伴随矩阵介绍及C++实现
在线性代数中,一个方形矩阵的伴随矩阵是一个类似于逆矩阵的概念。如果矩阵可逆,那么它的逆矩阵和它的伴随矩阵之间只差一个系数。然而,伴随矩阵对不可逆的矩阵也有定义,并且不需要用到除法。
设R是一个交换环(在抽象代数之分支环论中,一个交换环(commutative ring)是乘法运算满足交换律的环),A是一个以R中元素为系数的n*n的矩阵。A的伴随矩阵可按如下步骤定义:
定义:A关于第i行第j列的余子式(记作Mij)是去掉A的第i行第j列之后得到的(n-1)*(n-1)矩阵的行列式。
定义:A关于第i行第j列的代数余子式是:Cij=(-1)i+jMij。
定义:A的余子矩阵是一个n*n的矩阵C,使得其第i行第j列的元素是A关于第i行第j列的代数余子式。
引入以上的概念后,可以定义:矩阵A的伴随矩阵是A的余子矩阵的转置矩阵:adj(A)= CT.
也就是说,A的伴随矩阵是一个n*n的矩阵(记作adj(A)),使得其第i行第j列的元素是A关于第j行第i列的代数余子式:[adj(A)]ij=Cji。
伴随矩阵性质:对n*n的矩阵A和B,有:
(1)、adj(I) = I;
(2)、adj(AB) = adj(B)adj(A);
(3)、adj(AT) = adj(A)T;
(4)、det(adj(A)) = det(A)n-1;
(5)、adj(kA) = kn-1adj(A);
(6)、当n>2时,adj(adj(A)) = (detA)n-2A;
(7)、如果A可逆,那么adj(A-1) = adj(A)-1 = A / detA;
(8)、如果A是对称矩阵,那么其伴随矩阵也是对称矩阵;如果A是反对称矩阵,那么当n为偶数时,A的伴随矩阵也是反对称矩阵,n为奇数时则是对称矩阵;
(9)、如果A是(半)正定矩阵,那么其伴随矩阵也是(半)正定矩阵;
(10)、如果矩阵A和B相似,那么adj(A)和adj(B)也相似;
(11)、如果n>2,那么非零矩阵A是正交矩阵当且仅当adj(A) = ±AT.
以上内容整理自 维基百科
以下是用C++实现的求伴随矩阵:
#include "funset.hpp"
#include <math.h>
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "common.hpp"// 计算行列式
template<typename _Tp>
_Tp determinant(const std::vector<std::vector<_Tp>>& mat, int N)
{if (mat.size() != N) {fprintf(stderr, "mat must be square matrix\n");return -1;}for (int i = 0; i < mat.size(); ++i) {if (mat[i].size() != N) {fprintf(stderr, "mat must be square matrix\n");return -1;}}_Tp ret{ 0 };if (N == 1) return mat[0][0];if (N == 2) {return (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]);}else {// first colfor (int i = 0; i < N; ++i) {std::vector<std::vector<_Tp>> m(N - 1);std::vector<int> m_rows;for (int t = 0; t < N; ++t) {if (i != t) m_rows.push_back(t);}for (int x = 0; x < N - 1; ++x) {m[x].resize(N - 1);for (int y = 0; y < N - 1; ++y) {m[x][y] = mat[m_rows[x]][y + 1];}}int sign = (int)pow(-1, 1 + i + 1);ret += mat[i][0] * sign * determinant<_Tp>(m, N - 1);}}return ret;
}// 计算伴随矩阵
template<typename _Tp>
int adjoint(const std::vector<std::vector<_Tp>>& mat, std::vector<std::vector<_Tp>>& adj, int N)
{if (mat.size() != N) {fprintf(stderr, "mat must be square matrix\n");return -1;}for (int i = 0; i < mat.size(); ++i) {if (mat[i].size() != N) {fprintf(stderr, "mat must be square matrix\n");return -1;}}adj.resize(N);for (int i = 0; i < N; ++i) {adj[i].resize(N);}for (int y = 0; y < N; ++y) {std::vector<int> m_cols;for (int i = 0; i < N; ++i) {if (i != y) m_cols.push_back(i);}for (int x = 0; x < N; ++x) {std::vector<int> m_rows;for (int i = 0; i < N; ++i) {if (i != x) m_rows.push_back(i);}std::vector<std::vector<_Tp>> m(N - 1);for (int i = 0; i < N - 1; ++i) {m[i].resize(N - 1);}for (int j = 0; j < N - 1; ++j) {for (int i = 0; i < N - 1; ++i) {m[j][i] = mat[m_rows[j]][m_cols[i]];}}int sign = (int)pow(-1, x + y);adj[y][x] = sign * determinant<_Tp>(m, N-1);}}return 0;
}template<typename _Tp>
void print_matrix(const std::vector<std::vector<_Tp>>& mat)
{int rows = mat.size();for (int y = 0; y < rows; ++y) {for (int x = 0; x < mat[y].size(); ++x) {fprintf(stderr, " %f ", mat[y][x]);}fprintf(stderr, "\n");}fprintf(stderr, "\n");
}int test_adjoint_matrix()
{std::vector<float> vec{5, -2, 2, 7, 1, 0, 0, 3, -3, 1, 5, 0, 3, -1, -9, 4 };const int N{ 4 };if (vec.size() != (int)pow(N, 2)) {fprintf(stderr, "vec must be N^2\n");return -1;}std::vector<std::vector<float>> arr(N);for (int i = 0; i < N; ++i) {arr[i].resize(N);for (int j = 0; j < N; ++j) {arr[i][j] = vec[i * N + j];}}std::vector<std::vector<float>> adj;int ret = adjoint<float>(arr, adj, N);fprintf(stderr, "source matrix: \n");print_matrix<float>(arr);fprintf(stderr, "adjoint matrx: \n");print_matrix<float>(adj);return 0;
}
输出结果如下:
GitHub:https://github.com/fengbingchun/NN_Test
伴随矩阵介绍及C++实现相关推荐
- DirectX数学介绍
本文为 Introduction to 3D Game Programming with DirectX 11 读书笔记 坐标系统 Vector Algebra Matrix Algebra 行列式 ...
- 一文带你用Python玩转线性回归模型《加利福尼亚房价预测》回归模型评估指标介绍
大家早上好,本人姓吴,如果觉得文章写得还行的话也可以叫我吴老师.欢迎大家跟我一起走进数据分析的世界,一起学习! 感兴趣的朋友可以关注我或者我的数据分析专栏,里面有许多优质的文章跟大家分享哦. 前言 这 ...
- 简单介绍互联网领域选择与营销方法
在我看来,互联网领域的选择是"安家",而营销方法的不同则表现了"定家"的方式多种多样,只有选对了,"家"才得以"安定". ...
- 常用开源协议介绍以及开源软件规范列表
1. 开源协议介绍 GPL: General Public License,开源项目最常用的许可证,衍生代码的分发需开源并且也要遵守此协议.该协议也有很多变种,不同变种要求会略微不同. MPL: MP ...
- python:Json模块dumps、loads、dump、load介绍
20210831 https://www.cnblogs.com/bigtreei/p/10466518.html json dump dumps 区别 python:Json模块dumps.load ...
- pytorch学习笔记(九):PyTorch结构介绍
PyTorch结构介绍 对PyTorch架构的粗浅理解,不能保证完全正确,但是希望可以从更高层次上对PyTorch上有个整体把握.水平有限,如有错误,欢迎指错,谢谢! 几个重要的类型 和数值相关的 T ...
- Python字节码介绍
了解 Python 字节码是什么,Python 如何使用它来执行你的代码,以及知道它是如何帮到你的. 如果你曾经编写过 Python,或者只是使用过 Python,你或许经常会看到 Python 源代 ...
- Pytest - 使用介绍
1. 概述 pytest是一个非常成熟的全功能的Python测试框架,主要特点有以下几点: 1.简单灵活,容易上手,文档丰富: 2.支持参数化,可以细粒度地控制要测试的测试用例: 3.能够支持简单的单 ...
- 遗传算法的简单介绍以及模式定理的简单证明
遗传算法 遗传算法(Genetic Algorithm,GA),最早是由美国的John holland在20世纪70年代提出.算法通过模拟达尔文生物进化论的自然选择以及遗传学机理的生物进化过程来搜 ...
- k8s核心组件详细介绍教程(配超详细实例演示)
本文实验环境基于上篇文章手把手从零开始搭建k8s集群超详细教程 本文根据B站课程云原生Java架构师的第一课K8s+Docker+KubeSphere+DevOps学习总结而来 k8s核心组件介绍 1 ...
最新文章
- canvas绘制的文字如何换行
- 小程序的生命周期函数?
- 从入门到精通系列Java高级工程师路线介绍,附答案
- 【C 语言】二级指针作为输出 ( 指针输入 | 指针输出 | 二级指针 作为 函数形参 使用示例 )
- 【学习总结】数学-欧拉函数
- 解决thymeleaf报错 $ is not defined
- 个人博客前端模板_腾讯前端开发工程师,教你极速搭建一个个人博客网站
- 论文浅尝 | AutoETER: 用于知识图谱嵌入的自动实体类型表示
- oracle 论坛 千万级表,Oracle千万级记录操作总结
- 带父节点的平衡二叉树_平衡二叉树的左右旋以及双旋转的图文详解
- SBCL 使用中文时的错误记录 --close 问题已经解决
- Java JDBC中的Statement和PreparedStatement
- Django之HttpRequest和HttpReponse
- 微信解绑手机号服务器会保留吗,我把我的微信号给了别人,银行卡都解绑了,但手机号还在绑定,会不会有危险...
- 蒸汽管道图纸符号_管道设备表常用符号.ppt
- 从零开始的机器人比赛(一)——项目准备篇
- dns服务器哪个稳定,几个非常好用的DNS服务器(解决电信DNS此劫问题) - 电脑技术,dns,ricky,...
- 下沉市场不需要巨头,但很需要社区团购
- Vue项目中实现改变屏幕尺寸重新刷新页面-计算页面尺寸
- 四川一度智信:电商平台商品关键词优化技巧