c++实现矩阵运算的加减法乘法以及测试用例

Posted Hero_HL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++实现矩阵运算的加减法乘法以及测试用例相关的知识,希望对你有一定的参考价值。

1.引言

最近在看图像AI相关的知识,在此记录一个自己思考的代码用例。
关于矩阵的应用在AI中应用还是很广泛,尤其是深度学习的特征值这块中。
这里先简单记录上自己简单的基础矩阵算法的类,后续学习中会不断丰富这个类。
参考opencv3.4.0源码中libjasper模块中的jas_seq.c本例中增加了加减乘运算,
缩减和扩充了一些自己的理解

2.矩阵基本运算

我就是典型的:上课不听讲,考试混及格。书到用时方恨少!!
看到的同学们一定要好好的认真的学习大学知识,我现在才觉得大学学习的知识真的太有用了。
当然忘记了或者没学过的可以像我一样参考以下的视频进行学习
bilibili考研课程《线性代数》 https://www.bilibili.com/video/BV1aW411Q7x1?p=9

2.1 矩阵加减法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

主要记住以下几个点:
	1.同型矩阵指的是两个矩阵的行数和列数相等。
	2.两矩阵对应元素相加减(前提必须是同型矩阵)
	3.矩阵相乘满足:中间相等取两头

3.代码实现

	对于矩阵的赋值都采用了调用类创建矩阵时赋值或不赋值(默认参数)处理,
和接口设置所有元素为一个数,具体见如下代码。
matrix.h 矩阵类的定义
/*******************************
*	file:	matrix.h
*	author:	hehl
*	time:	2021/7/9
*******************************/
#pragma once
#include <iostream>
#include <vector>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
using namespace std;

typedef int INT;

// 基本的二维矩阵结构体
typedef struct matix_s
{
	INT	s_nRowsNums;	// 矩阵的行数
	INT	s_nColsNums;	// 矩阵的列数
	INT**	s_pRows;	// 指向矩阵每行开头的指针的指针(保存s_pData中每行的指针数组)
	INT	s_nRowsSize;	// 行数组分配大小
	INT*	s_pData;	// 矩阵的数据
	INT	s_nDataSize;	// 数据数组分配大小
	matix_s()
	{
		s_nRowsNums = 0;
		s_nColsNums = 0;
		s_pRows = nullptr;
		s_nRowsSize = 0;
		s_pData = nullptr;
		s_nDataSize = 0;
	}
} matrix_t;

class Matrix
{
public:
	// 单例
	static Matrix* GetInstance();
	// 创建矩阵,返回创建成功后矩阵的指针,失败返回nullptr  可以直接输入对应参数进行创建.仅仅用于测试
	matrix_t* matrix_create(INT nRows, INT nCols, bool bSet = false, ...);
	// 释放矩阵,释放内存
	void matrix_destroy(matrix_t* pMatrix_t);
	// 将矩阵的所有元素设置为指定值
	void matrix_setall(matrix_t* pMatrix_t, INT nValue);
	// 打印矩阵中的值
	void matrix_printf(matrix_t* pMatrix_t);
	// 两个矩阵相加
	bool two_matrix_add(matrix_t* pMatSrcA, matrix_t* pMatSrcB, matrix_t* pMatDes);
	// 两个矩阵相减
	bool two_matrix_subtrac(matrix_t* pMatSrcA, matrix_t* pMatSrcB, matrix_t* pMatDes);
	// 两个矩阵相乘
	bool two_matrix_multiply(matrix_t* pMatSrcA, matrix_t* pMatSrcB, matrix_t* pMatDes);
	// 当前有多少未释放内存的矩阵
	INT get_matix_objects_nums(void);
	// 释放当前所有未释放矩阵的内存
	void destory_all_matrix_objects(void);
private:
	// 构造函数,用于初始化
	Matrix();
	// 析构函数,用于释放内存
	~Matrix();
	// 获取矩阵行数
	INT matrix_getrows(matrix_t* pMatrix_t);
	// 获取矩阵列数
	INT matrix_getcols(matrix_t* pMatrix_t);
	// 获取矩阵数据大小
	INT matrix_get_data_size(matrix_t* pMatrix_t);

private:
	vector<matrix_t*> m_vpMatrix_t;
	static Matrix* m_pInstance;
};

matrix.cpp 具体实现矩阵类
/*******************************
*	file:	matrix.cpp
*	author:	hehl
*	time:	2021/7/9
*******************************/
#include "matrix.h"

Matrix* Matrix::m_pInstance = new Matrix();
Matrix* Matrix::GetInstance()
{
	if (m_pInstance == nullptr)
	{
		m_pInstance = new Matrix();
	}
	return m_pInstance;
}

Matrix::Matrix()
{

}

Matrix::~Matrix()
{
	destory_all_matrix_objects();
	delete m_pInstance;
	m_pInstance = nullptr;
}

matrix_t* Matrix::matrix_create(INT nRows, INT nCols, bool bSet, ...)
{
	matrix_t* matrix = new matrix_t;
	if (nullptr == matrix)
	{
		return nullptr;
	}
	matrix->s_nRowsNums = nRows;
	matrix->s_nColsNums = nCols;
	matrix->s_nRowsSize = nRows;
	matrix->s_nDataSize = nRows * nCols;

	if (matrix->s_nRowsSize > 0 && matrix->s_nColsNums > 0)
	{
		matrix->s_pRows = new INT * [matrix->s_nRowsSize];
		if (nullptr == matrix->s_pRows)
		{
			matrix_destroy(matrix);
			return nullptr;
		}
	}

	if (matrix->s_nDataSize > 0)
	{
		matrix->s_pData = new INT[matrix->s_nDataSize];
		if (nullptr == matrix->s_pData)
		{
			matrix_destroy(matrix);
			return nullptr;
		}

		if (bSet)
		{
			va_list ap;
			va_start(ap, bSet);
			for (INT i = 0; i < matrix->s_nDataSize; i++)
			{
				matrix->s_pData[i] = va_arg(ap, INT);
			}
			va_end(ap);
		}
		else
		{
			memset(matrix->s_pData, 0, matrix->s_nDataSize * sizeof(INT));
		}
	}

	for (INT i = 0; i < nRows; i++)
	{
		matrix->s_pRows[i] = &matrix->s_pData[i * matrix->s_nColsNums];
	}

	m_vpMatrix_t.push_back(matrix);
	return matrix;
}

void Matrix::matrix_destroy(matrix_t* pMatrix_t)
{
	if (pMatrix_t)
	{
		for (auto it = m_vpMatrix_t.begin(); it != m_vpMatrix_t.end(); it++)
		{
			if (*it == pMatrix_t)
			{
				m_vpMatrix_t.erase(it);
				break;
			}
		}

		if (pMatrix_t->s_pRows)
		{
			delete[]pMatrix_t->s_pRows;
			pMatrix_t->s_pRows = nullptr;
		}
		if (pMatrix_t->s_pData)
		{
			delete[]pMatrix_t->s_pData;
			pMatrix_t->s_pData = nullptr;
		}
		delete pMatrix_t;
		pMatrix_t = nullptr;
	}
}

void Matrix::matrix_setall(matrix_t* pMatrix_t, INT nValue)
{
	if (nullptr == pMatrix_t)
	{
		cout << "matrix_setall:matrix is nullptr" << endl;
		return;
	}
	for (INT nRows = 0; nRows < matrix_getrows(pMatrix_t); nRows++)
	{
		for (INT nCols = 0; nCols < matrix_getcols(pMatrix_t); nCols++)
		{
			pMatrix_t->s_pRows[nRows][nCols] = nValue;
		}
	}

	return;
}

void Matrix::matrix_printf(matrix_t* pMatrix_t)
{
	if (nullptr == pMatrix_t)
	{
		cout << "matrix_printf:matrix is nullptr" << endl;
		return;
	}
	for (INT nRows = 0; nRows < matrix_getrows(pMatrix_t); nRows++)
	{
		for (INT nCols = 0; nCols < matrix_getcols(pMatrix_t); nCols++)
		{
			printf("%-5d", pMatrix_t->s_pRows[nRows][nCols]);
		}
		cout << endl;
	}

	return;
}

INT Matrix::matrix_getrows(matrix_t* pMatrix_t)
{
	if (nullptr == pMatrix_t)
	{
		return 0;
	}
	return pMatrix_t->s_nRowsNums;
}

INT Matrix::matrix_getcols(matrix_t* pMatrix_t)
{
	if (nullptr == pMatrix_t)
	{
		return 0;
	}
	return pMatrix_t->s_nColsNums;
}

INT Matrix::matrix_get_data_size(matrix_t* pMatrix_t)
{
	if (nullptr == pMatrix_t)
	{
		return 0;
	}
	return pMatrix_t->s_nDataSize;
}

bool Matrix::two_matrix_add(matrix_t* pMatSrcA, matrix_t* pMatSrcB, matrix_t* pMatDes)
{
	if (nullptr == pMatSrcA || nullptr == pMatSrcB || nullptr == pMatDes)
	{
		return false;
	}
	if (!(pMatSrcA->s_nColsNums == pMatSrcB->s_nColsNums && pMatSrcA->s_nColsNums == pMatDes->s_nColsNums))
	{
		return false;
	}
	if (!(pMatSrcA->s_nRowsNums == pMatSrcB->s_nRowsNums && pMatSrcA->s_nRowsNums == pMatDes->s_nRowsNums))
	{
		return false;
	}

	for (INT nRows = 0; nRows < matrix_getrows(pMatDes); nRows++)
	{
		for (INT nCols = 0; nCols < matrix_getcols(pMatDes); nCols++)
		{
			pMatDes->s_pRows[nRows][nCols] = pMatSrcA->s_pRows[nRows][nCols] + pMatSrcB->s_pRows[nRows][nCols];
		}
	}
	return true;
}

bool Matrix::two_matrix_subtrac(matrix_t* pMatSrcA, matrix_t* pMatSrcB, matrix_t* pMatDes)
{
	if (nullptr == pMatSrcA || nullptr == pMatSrcB || nullptr == pMatDes)
	{
		return false;
	}
	if (!(pMatSrcA->s_nColsNums == pMatSrcB->s_nColsNums && pMatSrcA->s_nColsNums == pMatDes->s_nColsNums))
	{
		return false;
	}
	if (!(pMatSrcA->s_nRowsNums == pMatSrcB->s_nRowsNums && pMatSrcA->s_nRowsNums == pMatDes->s_nRowsNums))
	{
		return false;
	}
	for (INT nRows = 0; nRows < matrix_getrows(pMatDes); nRows++)
	{
		for (INT nCols = 0; nCols < matrix_getcols(pMatDes); nCols++)
		{
			pMatDes->s_pRows[nRows][nCols] = pMatSrcA->s_pRows[nRows][nCols] - pMatSrcB->s_pRows[nRows][nCols];
		}
	}
	return true;
}

bool Matrix::two_matrix_multiply(matrix_t* pMatSrcA, matrix_t* pMatSrcB, matrix_t* pMatDes)
{
	if (nullptr == pMatSrcA || nullptr == pMatSrcB || nullptr == pMatDes)
	{
		return false;
	}
	if (pMatSrcA->s_nColsNums != pMatSrcB->s_nRowsNums || pMatSrcA->s_nRowsNums != pMatDes->s_nRowsNums || pMatSrcB->s_nColsNums != pMatDes->s_nColsNums)
	{
		return false;
	}

	for (INT nRows = 0; nRows < matrix_getrows(pMatSrcA); nRows++)
	{
		for (INT nCols = 0; nCols < matrix_getcols(pMatSrcB); nCols++)
		{
			pMatDes->s_pRows[nRows][nCols] = 0;
			for (INT des = 0; des < matrix_getcols(pMatSrcA)/* or matrix_getrows(pMatSrcB) */; des++)
			{
				pMatDes->s_pRows[nRows][nCols] += pMatSrcA->s_pRows[nRows][des] * pMatSrcB->s_pRows[des][nCols];
			}
		}
	}

	return true;
}

INT Matrix::get_matix_objects_nums(void)
{
	return m_vpMatrix_t.size();
}

void Matrix::destory_all_matrix_objects(void)
{
	for (int i = 0; i < m_vpMatrix_t.size(); i++)
	{
		matrix_destroy(m_vpMatrix_t[i]);
	}
}
main.cpp 测试矩阵类的demo
/*******************************
*	file:	main.cpp
*	author:	hehl
*	time:	2021/7/9
*******************************/
#include "matrix.h"

int main()
{
	// 测试加减
	Matrix* matrixObj = Matrix::GetInstance();
	matrix_t* pMatrixA = matrixObj->matrix_create(2, 4);
	matrixObj->matrix_setall(pMatrixA, 2);
	cout << "matrixA:" << endl;
	matrixObj->matrix_printf(pMatrixA);

	matrix_t* pMatrixB = matrixObj->matrix_create(2, 4);
	matrixObj->matrix_setall(pMatrixB, 3);
	cout << "matrixB:" << endl;
	matrixObj->matrix_printf(pMatrixB);

	matrix_t* pMatrixC = matrixObj->matrix_create(2, 4);
	matrixObj->matrix_setall(pMatrixC, -5);
	cout << "matrixC:" << endl;
	matrixObj->matrix_printf(pMatrixC);

	if (matrixObj->two_matrix_add(pMatrixA, pMatrixB, pMatrixC))
	{
		cout << "matrixA + matrixB =:" << endl;
		matrixObj->matrix_printf(pMatrixC);
	}

	if (matrixObj->two_matrix_subtrac(pMatrixA, pMatrixB, pMatrixC))
	{
		cout << "matrixA - matrixB =:" << endl;
		matrixObj->matrix_printf(pMatrixC);
	}
	cout << endl << endl;


	// 测试乘法
	matrix_t* p1 = matrixObj->matrix_create(2, 3, true, 1, 2, 3, 4, 5, 6);
	cout << "matrix1:" << endl;
	matrixObj->matrix_printf(p1);

	matrix_t* p2 = matrixObj->matrix_create(3, 3, true, 1, 2, 3, 4, 5, 6, 7, 8, 9);
	cout << "matrix2:" << endl;
	matrixObj->matrix_printf(p2);

	matrix_t* p3 = matrixObj->matrix_create(2, 3);
	matrixObj->two_matrix_multiply(p1, p2, p3);
	cout << "matrix1 * matrix2:" << endl;
	matrixObj->matrix_printf(p3);

	matrixObj->destory_all_matrix_objects();
	system("pause");
	return 0;
}

4.测试结果

C++使用cuBLAS加速矩阵乘法运算

矩阵快速求幂

矩阵快速求幂

Python的Numpy库中各种矩阵基本运算的示例代码(加减乘点乘点除乘方转置等)

三维矩阵的运算规则是怎么样的? 包括加法,减法,乘法

矩阵运算