Я выполняю проект, в котором мне нужно проверить, не является ли массив "вектор" bool линейно независимым от столбцов "матрицы". В MATLAB это можно сделать, если найти ранг расширенной матрицы [матричный вектор], используя командный ранг (gf ([матричный вектор])). 'gf', потому что матрица булева. Но как это сделать в C++. Вот что я пробовал:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
#define BUFSIZE 256
int main()
{
Engine *ep;
mxArray *M = NULL, *V = NULL, *result = NULL;
bool matrix[4][4]={1,1,1,0,0,1,1,0,0,1,0,0}, vector[4][1]={1,1,1,1};
double *rank;
if (!(ep = engOpen("\0"))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return EXIT_FAILURE;
}
V = mxCreateDoubleMatrix(4, 1, mxREAL);
M = mxCreateDoubleMatrix(4, 4, mxREAL);
memcpy((void *)mxGetPr(V), (void *)vector, sizeof(vector));
memcpy((void *)mxGetPr(M), (void *)matrix, sizeof(matrix));
engPutVariable(ep, "V", V);
engPutVariable(ep, "M", M);
engEvalString(ep, "R = rank(gf([M V]));");
result = engGetVariable(ep, "R");
engClose(ep);
rank = mxGetPr(result);
printf("%f", *rank);
printf("Done with LI\n");
mxDestroyArray(M);
mxDestroyArray(V);
mxDestroyArray(result);
engEvalString(ep, "close;");
}
Вышеприведенный код работает, и я получаю желаемые результаты. Но он работает очень медленно. Может ли кто-нибудь предложить мне способ сделать это быстро? Или предложите другой способ найти ранг булевой матрицы. Некоторые библиотеки там, но они, похоже, имеют функции только для int или double-матриц.
Вы можете найти ранг Булевой матрицы, найдя ранг в поле Галуа 2 (как вы делаете в своем коде Matlab), что по существу является арифметикой mod 2.
В приведенном ниже коде найден ранг булевой матрицы, используя ту же идею, используя исключение Гаусса с частичным поворотным элементом.
#include <iostream>
#include <vector>
using namespace std;
class BooleanMatrix{
vector< vector<bool> > mat; //boolean matrix
int n, m; //size of matrix nxm
int rank; //rank of the matrix
public:
/*Constructor
* Required Parameters:
* M ==> boolean matrix
* n ==> number of rows
* m ==> number of columns
*/
template <size_t size_m>
BooleanMatrix(bool M[][size_m], int n, int m){
this -> n = n;
this -> m = m;
for (int i = 0; i < n; i++){
vector<bool> row(m);
for (int j = 0; j < m; j++) row[j] = M[i][j];
mat.push_back(row);
}
gaussElimination();
}
/* Does Gauss Elimination with partial pivoting on the matrix */
void gaussElimination(){
rank = n;
for (int i = 0; i < n; i++){
if (!mat[i][i]){
int j;
for (j = i+1; j < n && !mat[j][i]; j++);
if (j == n){
rank--;
continue;
}
else
for (int k = i; k < m; k++){
bool t = mat[i][k];
mat[i][k] = mat[j][k];
mat[j][k] = t;
}
}
for (int j = i+1; j < n; j++){
if (mat[j][i]){
for (int k = i; k < m; k++)
mat[j][k] = mat[j][k] - mat[i][k];
}
}
}
}
/* Get the row rank of the boolean matrix
* If you require the rank of the matrix, make sure that n > m.
* i.e. if n < m, call the constructor over the transpose.
*/
int getRank(){
return rank;
}
};
int main(){
bool M1[3][3] = { {1, 0, 1},
{0, 1, 1},
{1, 1, 0} };
BooleanMatrix booleanMatrix1(M1, 3, 3);
cout << booleanMatrix1.getRank() << endl;
bool M2[4][4] = { {1,1,1,0},
{0,1,1,0},
{0,1,0,0},
{1,1,1,1} };
BooleanMatrix booleanMatrix2(M2, 4, 4);
cout << booleanMatrix2.getRank() << endl;
}
Это дает результат, как и ожидалось для обоих случаев. Алгоритм должен работать хорошо для всех практических целей. Тривиальные улучшения и конкретные изменения могут быть сделаны в соответствии с вашими требованиями.
Однако я не тестировал его полностью. Если кто-либо обнаружит ошибку, отредактируйте ответ, чтобы исправить его.
Надеюсь это поможет.
Простым решением является решение наименьшей квадратной задачи, где операторы определяются в булевом смысле:
min_x |matrix * x - vector|^2
Тогда, если vector
находится в промежутке векторов столбцов matrix
, то остаточная ошибка решения должна быть очень малой.