C#计算矩阵的秩实例分析

时间:2022-01-06 08:15:31

本文实例讲述了C#计算矩阵的秩的方法。分享给大家供大家参考。具体如下:

1.代码思路

计算矩阵的秩,即把矩阵进行行初等变换,得出的行最简矩阵的非零行数。过程如下
1)将矩阵各行按第一个非零元素出现的位置升序排列(Operation1函数)
2)查看矩阵是否为行最简矩阵(isFinished函数),是则到第6步,不是则到第3步
3)如果有两行第一个非零元素出现的位置相同,则做消法变换,让下面行的第一个非零元素位置后移(Operation2函数)
4)将矩阵各行按第一个非零元素出现的位置升序排列(Operation1函数)
5)返回第2步
6)判断误差,对趋近与0的元素(如1E-5)按0处理,以免在第7步误判(Operation3函数)
7)统计非零行的数目(Operation4函数),即为矩阵的秩

2.函数代码

(注:本段代码只实现了一个思路,可能并不是该问题的最优解)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/// <summary>
/// 计算矩阵的秩
/// </summary>
/// <param name="matrix">矩阵</param>
/// <returns></returns>
private static int Rank(double[][] matrix)
{
  //matrix为空则直接默认已经是最简形式
  if (matrix == null || matrix.Length == 0) return 0;
  //复制一个matrix到copy,之后因计算需要改动矩阵时并不改动matrix本身
  double[][] copy = new double[matrix.Length][];
  for (int i = 0; i < copy.Length; i++)
  {
    copy[i] = new double[matrix[i].Length];
  }
  for (int i = 0; i < matrix.Length; i++)
  {
    for (int j = 0; j < matrix[0].Length; j++)
    {
      copy[i][j] = matrix[i][j];
    }
  }
  //先以最左侧非零项的位置进行行排序
  Operation1(copy);
  //循环化简矩阵
  while (!isFinished(copy))
  {
    Operation2(copy);
    Operation1(copy);
  }
  //过于趋近0的项,视作0,减小误差
  Operation3(copy);
  //行最简矩阵的秩即为所求
  return Operation4(matrix);
}
/// <summary>
/// 判断矩阵是否变换到最简形式(非零行数达到最少)
/// </summary>
/// <param name="matrix"></param>
/// <returns>true:</returns>
private static bool isFinished(double[][] matrix)
{
  //统计每行第一个非零元素的出现位置
  int[] counter = new int[matrix.Length];
  for (int i = 0; i < matrix.Length; i++)
  {
    for (int j = 0; j < matrix[i].Length; j++)
    {
      if (matrix[i][j] == 0)
      {
        counter[i]++;
      }
      else break;
    }
  }
  //后面行的非零元素出现位置必须在前面行的后面,全零行除外
  for (int i = 1; i < counter.Length; i++)
  {
    if (counter[i] <= counter[i - 1] && counter[i] != matrix[0].Length)
    {
      return false;
    }
  }
  return true;
}
/// <summary>
/// 排序(按左侧最前非零位位置自上而下升序排列)
/// </summary>
/// <param name="matrix">矩阵</param>
private static void Operation1(double[][] matrix)
{
  //统计每行第一个非零元素的出现位置
  int[] counter = new int[matrix.Length];
  for (int i = 0; i < matrix.Length; i++)
  {
    for (int j = 0; j < matrix[i].Length; j++)
    {
      if (matrix[i][j] == 0)
      {
        counter[i]++;
      }
      else break;
    }
  }
  //按每行非零元素的出现位置升序排列
  for (int i = 0; i < counter.Length; i++)
  {
    for (int j = i; j < counter.Length; j++)
    {
      if(counter[i]>counter[j])
      {
        double[] dTemp = matrix[i];
        matrix[i] = matrix[j];
        matrix[j] = dTemp;
      }
    }
  }
}
/// <summary>
/// 行初等变换(左侧最前非零位位置最靠前的行,只保留一个)
/// </summary>
/// <param name="matrix">矩阵</param>
private static void Operation2(double[][] matrix)
{
  //统计每行第一个非零元素的出现位置
  int[] counter = new int[matrix.Length];
  for (int i = 0; i < matrix.Length; i++)
  {
    for (int j = 0; j < matrix[i].Length; j++)
    {
      if (matrix[i][j] == 0)
      {
        counter[i]++;
      }
      else break;
    }
  }
  for (int i = 1; i < counter.Length; i++)
  {
    if (counter[i] == counter[i - 1] && counter[i] != matrix[0].Length)
    {
      double a = matrix[i - 1][counter[i - 1]];
      double b = matrix[i][counter[i]]; //counter[i]==counter[i-1]
      matrix[i][counter[i]] = 0;
      for (int j = counter[i] + 1; j < matrix[i].Length; j++)
      {
        double c = matrix[i - 1][j];
        matrix[i][j] -= (c * b / a);
      }
      break;
    }
  }
}
/// <summary>
/// 将和0非常接近的数字视为0
/// </summary>
/// <param name="matrix"></param>
private static void Operation3(double[][] matrix)
{
  for (int i = 0; i < matrix.Length; i++)
  {
    for (int j = 0; j < matrix[0].Length; j++)
    {
      if (Math.Abs(matrix[i][j]) <= 0.00001)
      {
        matrix[i][j] = 0;
      }
    }
  }
}
/// <summary>
/// 计算行最简矩阵的秩
/// </summary>
/// <param name="matrix"></param>
/// <returns></returns>
private static int Operation4(double[][] matrix)
{
  int rank = -1;
  bool isAllZero = true;
  for (int i = 0; i < matrix.Length; i++)
  {
    isAllZero = true;
    //查看当前行有没有0
    for (int j = 0; j < matrix[0].Length; j++)
    {
      if (matrix[i][j] != 0)
      {
        isAllZero = false;
        break;
      }
    }
    //若第i行全为0,则矩阵的秩为i
    if (isAllZero)
    {
      rank = i;
      break;
    }
  }
  //满秩矩阵的情况
  if (rank == -1)
  {
    rank = matrix.Length;
  }
  return rank;
}

3.Main函数调用

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static void Main(string[] args)
{
  //示例矩阵1:秩为3
  double[][] matrix1 = new double[][]
  {
    new double[] { 1, 1, 1 },
    new double[] { 1, 1, 0 },
    new double[] { 0, 1, 1 }
  };
  Console.WriteLine(Rank(matrix1));
  //示例矩阵2:秩为3
  double[][] matrix2 = new double[][]
  {
    new double[] { 3, 2, 0, 5, 0 },
    new double[] { 3, -2, 3, 6, -1 },
    new double[] { 2, 0, 1, 5, -3 },
    new double[] { 1, 6, -4, -1, 4 }
  };
  Console.WriteLine(Rank(matrix2));
  //示例矩阵3:秩为3
  double[][] matrix3 = new double[][]
  {
    new double[] { 2, 3, 1, -3, -7 },
    new double[] { 1, 2, 0, -2, -4 },
    new double[] { 3, -2, 8, 3, 0 },
    new double[] { 2, -3, 7, 4, 3 }
  };
  Console.WriteLine(Rank(matrix3));
  Console.ReadLine();
}

4.执行结果

C#计算矩阵的秩实例分析

希望本文所述对大家的C#程序设计有所帮助。