雅可比(Jacobi)计算特征值和特征向量

2023-10-30

雅可比迭代法法

在图形图像中很多地方用到求矩阵的特征值和特征向量,比如主成分分析、OBB包围盒等。编程时一般都是用数值分析的方法来计算,这里介绍一下雅可比迭代法求解特征值和特征向量。雅可比迭代法的原理,网上资料很多,详细可见参考资料1。这里我们简单介绍求解矩阵S特征值和特征向量的步骤:

  1. 初始化特征向量为对角阵V,即主对角线的元素都是1.其他元素为0。
  2. 在S的非主对角线元素中,找到绝对值最大元素 Sij。
  3. 用下 式计算tan2θ,求 cosθ、sinθ 及旋转矩阵Gij 。
    在这里插入图片描述
  4. 用下面公式求S‘;用当前特征向量矩阵V乘以矩阵Gij得到当前的特征向量V。
    在这里插入图片描述
  5. 若当前迭代前的矩阵A的非主对角线元素中最大值小于给定的阈值e时,停止计算;否则, 令S =S‘, 重复执行(2) ~ (5)。 停止计算时,得到特征值 li≈(S‘) ij ,i,j= 1,2,…,n.以及特征向量V。
  6. 这一步可选。根据特征值的大小从大到小的顺序重新排列矩阵的特征值和特征向量。

代码实现

用C++实现,并与参考资料1示例对比。

#include <iostream>
#include <map>
#include<math.h>
#include <iomanip>
using namespace std;

/**
* @brief                        Jacobi eigenvalue algorithm
* @param matrix				    n*n array
* @param dim					dim represent n
* @param eigenvectors			n*n array
* @param eigenvalues			n*1 array
* @param precision   			precision requirements
* @param max					max number of iterations
* @return
*/
bool Jacobi(double* matrix, int dim, double* eigenvectors, double* eigenvalues, double precision, int max)
{
	for (int i = 0; i < dim; i++) {
		eigenvectors[i*dim + i] = 1.0f;
		for (int j = 0; j < dim; j++) {
			if (i != j)
				eigenvectors[i*dim + j] = 0.0f;
		}
	}

	int nCount = 0;		//current iteration
	while (1) {
		//find the largest element on the off-diagonal line of the matrix
		double dbMax = matrix[1];
		int nRow = 0;
		int nCol = 1;
		for (int i = 0; i < dim; i++) {			//row
			for (int j = 0; j < dim; j++) {		//column
				double d = fabs(matrix[i*dim + j]);
				if ((i != j) && (d > dbMax)) {
					dbMax = d;
					nRow = i;
					nCol = j;
				}
			}
		}

		if (dbMax < precision)     //precision check 
			break;
		if (nCount > max)       //iterations check
			break;
		nCount++;

		double dbApp = matrix[nRow*dim + nRow];
		double dbApq = matrix[nRow*dim + nCol];
		double dbAqq = matrix[nCol*dim + nCol];
		//compute rotate angle
		double dbAngle = 0.5*atan2(-2 * dbApq, dbAqq - dbApp);
		double dbSinTheta = sin(dbAngle);
		double dbCosTheta = cos(dbAngle);
		double dbSin2Theta = sin(2 * dbAngle);
		double dbCos2Theta = cos(2 * dbAngle);
		matrix[nRow*dim + nRow] = dbApp*dbCosTheta*dbCosTheta +
			dbAqq*dbSinTheta*dbSinTheta + 2 * dbApq*dbCosTheta*dbSinTheta;
		matrix[nCol*dim + nCol] = dbApp*dbSinTheta*dbSinTheta +
			dbAqq*dbCosTheta*dbCosTheta - 2 * dbApq*dbCosTheta*dbSinTheta;
		matrix[nRow*dim + nCol] = 0.5*(dbAqq - dbApp)*dbSin2Theta + dbApq*dbCos2Theta;
		matrix[nCol*dim + nRow] = matrix[nRow*dim + nCol];

		for (int i = 0; i < dim; i++) {
			if ((i != nCol) && (i != nRow)) {
				int u = i*dim + nRow;	//p  
				int w = i*dim + nCol;	//q
				dbMax = matrix[u];
				matrix[u] = matrix[w] * dbSinTheta + dbMax*dbCosTheta;
				matrix[w] = matrix[w] * dbCosTheta - dbMax*dbSinTheta;
			}
		}

		for (int j = 0; j < dim; j++) {
			if ((j != nCol) && (j != nRow)) {
				int u = nRow*dim + j;	//p
				int w = nCol*dim + j;	//q
				dbMax = matrix[u];
				matrix[u] = matrix[w] * dbSinTheta + dbMax*dbCosTheta;
				matrix[w] = matrix[w] * dbCosTheta - dbMax*dbSinTheta;
			}
		}

		//compute eigenvector
		for (int i = 0; i < dim; i++) {
			int u = i*dim + nRow;		//p   
			int w = i*dim + nCol;		//q
			dbMax = eigenvectors[u];
			eigenvectors[u] = eigenvectors[w] * dbSinTheta + dbMax*dbCosTheta;
			eigenvectors[w] = eigenvectors[w] * dbCosTheta - dbMax*dbSinTheta;
		}
	}

	//sort eigenvalues
	std::map<double, int> mapEigen;
	for (int i = 0; i < dim; i++) {
		eigenvalues[i] = matrix[i*dim + i];
		mapEigen.insert(make_pair(eigenvalues[i], i));
	}

	double *pdbTmpVec = new double[dim*dim];
	std::map<double, int>::reverse_iterator iter = mapEigen.rbegin();
	for (int j = 0; iter != mapEigen.rend(), j < dim; ++iter, ++j)	{
		for (int i = 0; i < dim; i++) {
			pdbTmpVec[i*dim + j] = eigenvectors[i*dim + iter->second];
		}
		eigenvalues[j] = iter->first;
	}

	for (int i = 0; i < dim; i++) {
		double dSumVec = 0;
		for (int j = 0; j < dim; j++)
			dSumVec += pdbTmpVec[j * dim + i];
		if (dSumVec < 0) {
			for (int j = 0; j < dim; j++)
				pdbTmpVec[j * dim + i] *= -1;
		}
	}
	memcpy(eigenvectors, pdbTmpVec, sizeof(double)*dim*dim);
	delete[]pdbTmpVec;
	return true;
}


int main()
{
	double a[4][4] = { {4, -30, 60, -35}, {-30, 300, -675, 420},{ 60, -675, 1620, -1050},{ -35, 420, -1050, 700}};
	int n = 4;
	double eps = 1e-10;
	int T = 10000;
	double p[4][4] = { 0 };
	double v[4] = { 0 };
	bool re = Jacobi(&a[0][0], n, &p[0][0], v, eps, T);
	if (re)	{
		cout << "Matrix:" << endl;
		for (int i = 0; i < n; i++)	{
			for (int j = 0; j < n; j++)
				cout << setw(15) << a[i][j];
			cout << endl;
		}
		cout << "eigenvectors:" << endl;
		for (int i = 0; i < n; i++)	{
			for (int j = 0; j < n; j++)
				cout << setw(15) << p[i][j];
			cout << endl;
		}
		cout << "eigenvalues:" << endl;
		for (int i = 0; i < n; i++)	{
				cout << setw(15) << v[i];
			cout << endl;
		}
	}
	else
		cout << "false" << endl;
	system("pause");
}

运行结果:

在这里插入图片描述

参考资料1示例结果:

在这里插入图片描述

参考资料

【Jacobi eigenvalue algorithm】https://en.wikipedia.org/wiki/Jacobi_eigenvalue_algorithm

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

雅可比(Jacobi)计算特征值和特征向量 的相关文章

  • windows:ngix无法绑定80端口

    问题 cmd运行ngix提示 nginx emerg bind to 0 0 0 0 80 failed 10013 An attempt was made to access a socket in a way forbidden by
  • vue 默认选中复选框案例

  • JFrame的一些简单操作

    前几天在Java课上 老师有一段代码用到了Jframe和Jbutton这两个东西 起初我以为这是我们老师自己写的类 但是之后我一查发现这是Java中用于操控一个小窗口而封装的类 于是我去了解一下这个类 然后写了一个非常简陋的窗口 publi
  • 紫外光刻胶 AR-N 4400/电子束光刻胶 AR-N7700/AR-P617 电子束光刻胶

    光刻胶又称抗蚀剂 是指通过紫外光 电子束 离子束 射线等的照射或辐射 其性质发生变化的耐蚀刻薄膜材料 按曝光光源和辐射源的不同 又分为紫外光刻胶 包括紫外正性光刻胶 紫外负性光刻胶 深紫外光刻胶 电子束胶 射线胶 离子束胶等 AR N 44
  • 微信小程序框架——uni-app

    文章目录 uni app介绍 1 什么是uni app 2 上线的产品 3 uni app的社区和规模 uni app基础 1 uni app初体验 2 项目结构介绍 3 样式和sass 4 基本语法 5 事件 6 组件 7 生命周期 补充
  • python笔记:数组的一些操作

    目录 1 对数组求指数和对数 2 数组的最值及其索引 3 按照行或者列求均值 求和 最大值 最小值 标准差 方差 4 取对角线元素 5 取两个数组对应的最大或最小值 6 对数组重新排列 1 对数组求指数和对数 参考 指数 math exp
  • React.lazy懒加载组件

    1 React lazy的用法 React lazy方法可以异步加载组件文件 const Foo React lazy gt import componets ChildComponent React lazy不能单独使用 需要配合Reac
  • mysql关于mysql.server

    1 mysql server服务端工具 主要作用就是为了方便启动和关闭mysql服务 这个脚本中调用mysqld safe来启动mysqld 2 RPM包安装时 发现 etc rc d init d mysql和 usr share mys
  • 使用pip安装package的时候,如何不使用cache的文件,重新下载(防止package之间版本不匹配)

    我们在使用pip安装某一个package的时候 如果安装的有问题向卸载之后重新安装 卸载 pip uninstall mediapipe 重新安装 pip install mediapipe 但是 执行命令之后发现使用了cached的whe
  • CSerialPort教程4.3.x (2) - CSerialPort源码简介

    CSerialPort教程4 3 x 2 CSerialPort源码简介 前言 CSerialPort项目是一个基于C C 的轻量级开源跨平台串口类库 可以轻松实现跨平台多操作系统的串口读写 同时还支持C Java Python Node
  • 位运算符介绍(二):Java位运算符

    Java语言提供了7个位操作运算符 这些运算符只能用于整型操作数 这些整数操作数包括long int short char和byte 这里注意 相对于C C Java多了一个位运算符 gt gt gt 整型操作数也多了一个byte类型 C

随机推荐

  • 【建议收藏】机器学习模型构建(一)——建模调参(内附代码)

    引言 在前一阶段的学习中 我们完成了数据预处理等上游操作 接下来就要开始进行模型的构建 构建模型 sklearn中提供各种机器学习模型的类供我们使用 我们要根据我们的业务逻辑进行相关的筛选进行构建调参 在本例中我将使用sklearn内置的数
  • 机器学习--特征选择(Python代码实现)

    转自 每日一Python 微信公众号 特征选择就是从原始特征中选取一些最有效的特征来降低维度 提高模型泛化能力减低过拟合的过程 主要目的是剔除掉无关特征和冗余特征 选出最优特征子集 常见的特征选择方法可以分为3类 过滤式 filter 包裹
  • 重磅:Kafka 迎来 1.0.0 版本,正式告别四位数版本号!

    Kafka 从首次发布之日起 已经走过了七个年头 从最开始的大规模消息系统 发展成为功能完善的分布式流式处理平台 用于发布和订阅 存储及实时地处理大规模流数据 来自世界各地的数千家公司在使用 Kafka 包括三分之一的 500 强公司 Ka
  • OpenCV中基于LBP算法的人脸检测测试代码

    下面是OpenCV 3 3中基于CascadeClassifier类的LBP算法实现的人脸检测 从结果上看 不如其它开源库效果好 如libfacedetection 可参考 https blog csdn net fengbingchun
  • 自动控制原理-频率特性 G(jw ) 定义

    目录 预先的知识点 正题 定义一 物理定义 定义二 定义三 理解即可 不要求掌握 运用 预先的知识点 1 复数 一般定义
  • 超高频RFID读写器构建医疗化验全程RFID跟踪管理系统

    1 背景 Ambient ID发布了超高频UHF Gen 2 RFID系统的解决方案 使用Trimble旗下Thingmagic超高频RFID读写器 用来跟踪那些从医院到化验室里进行诊断测试的标本瓶 标本瓶里盛有人体组织或血液 这个方案可以
  • dnsmasq安装

    一 dnsmasq下载 下载地址 Index of dnsmasq 二 dnsmasq配置 决定dnsmasq支持什么功能是通过修改src config h 需要的XX功能通过 define XX make时 XX功能编译到dnsmasq命
  • JavaScript中的iterable

    遍历Array可以采用下标循环 遍历Map和Set就无法使用下标 为了统一集合类型 ES6标准引入了新的iterable类型 Array Map和Set都属于iterable类型 具有iterable类型的集合可以通过新的for of循环来
  • Laravel初探——安装

    安装Composer 1 curl sS https getcomposer org installer php 2 mv composer phar usr local bin composer 3 composer install 安装
  • Java之美[从菜鸟到高手演变]之设计模式二

    在阅读过程中有任何问题 请及时联系 egg 邮箱 xtfggef gmail com 微博 http weibo com xtfggef 如有转载 请说明出处 http blog csdn net zhangerqing 我们接着讨论设计模
  • 变量的声明和定义

    1 声明和定义的区别 变量声明规定了变量的类型和名字 而定义是在声明的基础上还开辟了存储空间 可能还会为变量初始化一个初始值 2 c 为什么要将声明和定义分开 c 支持分离式编译机制 允许将程序分割为若干个文件 每个文件可被独立编译 而为了
  • 华为云云耀云服务器L实例评测

    目录 引出 起因 si因 解决报错 诶嘿 连上了 不出意外 就出意外了 打开数据库 what 找华为云求助 教训 备份 教训 密码 解决 1 改密码 2 新建一个MySQL 密码设置复杂一点 3 开启 binlog备份 MySQL的binl
  • Java二维数组静态以及动态初始化方法

    import java util Random public class test2 public static void main String args 二维数组静态初始化 int arr 1 2 3 4 5 6 7 8 9 Syste
  • java8 函数式接口与 Lambda 表达式

    函数式接口与 Lambda 表达式 1 函数式接口 举例复习接口的匿名实现 函数式接口 2 Lambda表达式 什么是Lambda Lambda的几种编写规则解释示例 Lambda 的方法引用与构造器引用 方法引用的解释与编写 方法引用示例
  • Winform实现ComboBox模糊查询

    1 新增项目 using System using System Collections Generic using System ComponentModel using System Data using System Drawing
  • 【Web3 系列开发教程——创建你的第一个 NFT(7)】创建一个 NFT DApp,给你的 NFT 赋予属性,例如图片

    在本文中 你将构建一个 NFT 铸币机 并学习如何通过使用 Metamask 和 Web3 工具将你的智能合约连接到 React 前端 来创建一个NFT dApp 我认为 对于具备 Web2 开发背景的开发者来说 最大的挑战之一是弄清楚如何
  • 故障诊断专家系统研究之五-----推理机制及可信度算法

    推理机制及可信度算法 在第三章和第四章中讨论了如何表示燃气轮机专家的知识以及如何把这些知识存储到知识库之中 即关于知识表示和知识库的问题 而故障诊断专家系统的另一个核心组件就是基于知识的诊断推理机 本章在前两章讨论的知识表示和知识库的基础之
  • 计算机专业大学生如何规划大学四年?

    首先必须学好计算机专业四大核心课程 数据结构 计算机网络 计算机组成原理 计算机操作系统 在此之前呢 建议学习一门面向过程和一门面向对象的语言 对我们进一步学习计算机大有裨益 比如C语言程序设计 Java程序设计 文末有福利 一 计算机专业
  • Mybatis中的StatementType

    原文 http luoyu ds iteye com blog 1517607 要实现动态传入表名 列名 需要做如下修改 添加属性statementType STATEMENT 同时sql里的属有变量取值都改成 xxxx 而不是 xxx
  • 雅可比(Jacobi)计算特征值和特征向量

    雅可比迭代法法 在图形图像中很多地方用到求矩阵的特征值和特征向量 比如主成分分析 OBB包围盒等 编程时一般都是用数值分析的方法来计算 这里介绍一下雅可比迭代法求解特征值和特征向量 雅可比迭代法的原理 网上资料很多 详细可见参考资料1 这里