MyMathLib系列(行列式计算2)
/// <summary>
/// 行列式计算,本程序属于MyMathLib的一部分。欢迎使用,參考,提意见。
/// 有时间用函数语言改写,做自己得MathLib,里面的算法经过验证,但没经过
/// 严格測试,如需參考,请谨慎.
/// </summary>
public static partial class LinearAlgebra
{ /// <summary>
/// 获取指定i,j的余子式
/// </summary>
/// <param name="Determinants">N阶行列式</param>
/// <param name="i">第i行</param>
/// <param name="j">第j列</param>
/// <returns>计算结果</returns>
public static T[,] GetDeterminantMij<T>(T[,] Determinants, int i, int j)
{
var theN = Determinants.GetLength(0);
var theNewDeter = new T[theN - 1, theN - 1];
int theI = -1; for (int k = 0; k < theN; k++)
{
if (k == i - 1)
{
continue;
}
theI++;
int theJ = -1;
for (int l = 0; l < theN; l++)
{
if (l == j - 1)
{
continue;
}
theJ++;
theNewDeter[theI, theJ] = Determinants[k, l];
}
}
return theNewDeter;
}
/// <summary>
/// 获取指定i,j的余子式
/// </summary>
/// <param name="Determinants">N阶行列式</param>
/// <param name="Rows">要取得行</param>
/// <param name="Cols">要取得列</param>
/// <returns>计算结果</returns>
public static T[,] GetDeterminantMij<T>(T[,] Determinants, int[] Rows, int[] Cols)
{
if (Rows.Length != Cols.Length)
{
throw new Exception("所取行数和列数必须相等!");
}
var theN = Determinants.GetLength(0);
var theNewN = theN - Rows.Length;
var theNewDeter = new T[theNewN, theNewN];
int theI = -1; for (int k = 0; k < theN; k++)
{
if (Rows.Contains(k + 1))
{
continue;
}
theI++;
int theJ = -1;
for (int l = 0; l < theN; l++)
{
if (Cols.Contains(l + 1))
{
continue;
}
theJ++;
theNewDeter[theI, theJ] = Determinants[k, l];
}
}
return theNewDeter;
}
/// <summary>
/// 获取指定k阶子式N
/// </summary>
/// <param name="Determinants">N阶行列式</param>
/// <param name="Rows">要取得行</param>
/// <param name="Cols">要取得列</param>
/// <returns>计算结果</returns>
public static T[,] GetDeterminantKN<T>(T[,] Determinants, int[] Rows, int[] Cols)
{
if (Rows.Length != Cols.Length)
{
throw new Exception("所取行数和列数必须相等!");
}
var theNewN = Rows.Length;
var theNewDeter = new T[theNewN, theNewN];
for (int k = 0; k < Rows.Length; k++)
{
for (int l = 0; l < Cols.Length; l++)
{
theNewDeter[k, l] = Determinants[Rows[k] - 1, Cols[l] - 1];
}
}
return theNewDeter;
}
/// <summary>
/// 计算余子式的符号。 /// </summary>
/// <param name="i"></param>
/// <param name="j"></param>
/// <returns></returns>
public static int CalcDeterMijSign(int i, int j)
{
int theSign = 1;
if ((i + j) % 2 == 1)
{
theSign = -1;
}
return theSign;
}
/// <summary>
/// 计算余子式的符号。
/// </summary>
/// <param name="i"></param>
/// <param name="j"></param>
/// <returns></returns>
public static int CalcDeterMijSign(int[] Rows, int[] Cols)
{
int theSign = 1;
var theSum = Rows.Sum() + Cols.Sum();
if (theSum % 2 == 1)
{
theSign = -1;
}
return theSign;
}
/// <summary>
/// 降阶法计算行列式
/// </summary>
/// <param name="Determinants">N阶行列式</param>
/// <param name="ZeroOptimization">是否0优化</param>
/// <returns>计算结果</returns>
public static decimal CalcDeterminantAij(decimal[,] Determinants, bool ZeroOptimization = false)
{
var theN = Determinants.GetLength(0);
//假设为2阶,直接计算
if (theN == 2)
{
return Determinants[0, 0] * Determinants[1, 1] - Determinants[0, 1] * Determinants[1, 0];
}
if (ZeroOptimization)
{
//找0最多的行
int theRowIndex = 0;
int theMaxZeroCountR = -1;
for (int i = 0; i < theN; i++)
{
int theZeroNum = 0;
for (int j = 0; j < theN; j++)
{
if (Determinants[i, j] == 0)
{
theZeroNum++;
}
}
if (theZeroNum > theMaxZeroCountR)
{
theRowIndex = i;
theMaxZeroCountR = theZeroNum;
}
}
//找0最多的列
int theColIndex = 0;
int theMaxZeroCountC = -1;
for (int i = 0; i < theN; i++)
{
int theZeroNum = 0;
for (int j = 0; j < theN; j++)
{
if (Determinants[j, i] == 0)
{
theZeroNum++;
}
}
if (theZeroNum > theMaxZeroCountC)
{
theColIndex = i;
theMaxZeroCountC = theZeroNum;
}
}
if (theMaxZeroCountR >= theMaxZeroCountC)
{
decimal theRetDec = 0;
//第i=theRowIndex+1行展开
int i = theRowIndex + 1;
for (int j = 1; j <= theN; j++)
{
var theSign = CalcDeterMijSign(i, j);
var theNewMij = GetDeterminantMij(Determinants, i, j);
theRetDec += theSign * Determinants[i - 1, j - 1] * CalcDeterminantAij(theNewMij, ZeroOptimization);
}
return theRetDec;
}
else
{
decimal theRetDec = 0;
//第j=theColIndex+1列展开
int j = theColIndex + 1;
for (int i = 1; i <= theN; i++)
{
var theSign = CalcDeterMijSign(i, j);
var theNewMij = GetDeterminantMij(Determinants, i, j);
theRetDec += theSign * Determinants[i, j] * CalcDeterminantAij(theNewMij, ZeroOptimization);
}
return theRetDec;
}
}
else
{
//採用随机法展开一行
var i = new Random().Next(1, theN);
decimal theRetDec = 0;
for (int j = 1; j <= theN; j++)
{
var theSign = CalcDeterMijSign(i, j);
var theNewMij = GetDeterminantMij(Determinants, i, j);
theRetDec += theSign * Determinants[i-1, j-1] * CalcDeterminantAij(theNewMij, ZeroOptimization);
}
return theRetDec;
}
} /// <summary>
/// 计算范德蒙行列式
/// </summary>
/// <param name="Determinants">范德蒙行列式简记序列</param>
/// <returns>计算结果</returns>
public static decimal CalcVanDerModeDeter(decimal[] VanDerModeDeter)
{
var theN = VanDerModeDeter.Length;
if (theN == 1)
{
return 1;
}
decimal theRetDec = 1;
for (int i = 0; i < theN; i++)
{
for (int j = i + 1; j < theN; j++)
{
theRetDec *= (VanDerModeDeter[j] - VanDerModeDeter[i]);
}
}
return theRetDec;
}
/// <summary>
/// 获取奇数序列
/// </summary>
/// <param name="N"></param>
/// <returns></returns>
private static int[] GetLaplaceRowsOdd(int N)
{
var theRet = new List<int>();
for (int i = 0; i < N; i = i + 2)
{
theRet.Add(i + 1);
}
return theRet.ToArray();
} /// <summary>
/// 依据拉普拉斯定理计算行列式值。 /// </summary>
/// <param name="Determinants">N阶行列式</param>
/// <param name="Rows">初始展开行,里面採用奇数行展开</param>
/// <returns>计算结果</returns>
public static decimal CalcDeterByLaplaceLaw(decimal[,] Determinants, int[] Rows)
{
var n = Determinants.GetLength(0);
var k = Rows.Length;
//假设阶数小于3,则不是必需採用拉普拉斯展开
if (n <= 3)
{
return CalcDeterminantAij(Determinants, false);
}
//从P(theN,theK)
var theRetList = GetCombination(n, k);
decimal theRetDec = 0;
foreach (var theCols in theRetList)
{
var theSign = CalcDeterMijSign(Rows, theCols.ToArray());
var theKN = GetDeterminantKN(Determinants, Rows, theCols.ToArray());
var theN = GetDeterminantMij(Determinants, Rows, theCols.ToArray());
decimal theRetKN = 0;
//假设剩余阶数>4则採用随机半数处理.
if (n - k >= 4)
{
var theRows = GetLaplaceRowsOdd(n - k);
theRetKN = CalcDeterByLaplaceLaw(theKN, theRows);
}
else
{
theRetKN = CalcDeterminantAij(theKN);
}
decimal theRetAk = 0;
if (k >= 4)
{
var theRows = GetLaplaceRowsOdd(k);
theRetAk = CalcDeterByLaplaceLaw(theN, theRows);
}
else
{
theRetAk = CalcDeterminantAij(theN);
}
theRetDec += theSign * theRetKN * theRetAk;
}
return theRetDec;
}
/// <summary>
/// 从N个数中取k个数的组合结果。考虑到组合数没有顺序区分,因此仅仅要考虑从小
/// 到大的排列下的组合情况就可以,另外,假设组合也不用考虑元素反复的
/// 问题。假设有反复数,仅仅要除重就可以。 /// </summary>
/// <param name="N">N个数1-N</param>
/// <param name="k">取K个</param>
/// <returns></returns>
public static List<List<int>> GetCombination(int N, int k)
{
var theList = new List<int>();
for (int i = 1; i <= N; i++)
{
theList.Add(i);
}
return GetCombination(theList, k);
}
/// <summary>
/// 从N个中取k个数,算法原理C(N,k)=C(N-1,k)+ (a + C(Na-1,k-1));当中Na是N中去掉a后的集合.
/// </summary>
/// <param name="N">元素总个数</param>
/// <param name="k">取k个</param>
/// <returns></returns>
public static List<List<int>> GetCombination(List<int> N, int k)
{
if (k==0)
{
return null;
}
if (N.Count < k)
{
return null;
}
if (k == 1)
{
var theResultsList = new List<List<int>>();
foreach (var theN in N)
{
var theList = new List<int>();
theList.Add(theN);
theResultsList.Add(theList);
}
return theResultsList;
}
if (N.Count == k)
{
var theResultsList = new List<List<int>>();
var theList = new List<int>();
theList.AddRange(N);
theResultsList.Add(theList);
return theResultsList;
}
var theRet3 = new List<List<int>>();
int theLeft = N[0];
var theRight = new List<int>();
theRight.AddRange(N);
theRight.Remove(N[0]); var theRet2 = GetCombination(theRight, k);
theRet3.AddRange(theRet2); theRet2 = GetCombination(theRight, k - 1);
for (int n = 0; n < theRet2.Count; n++)
{
var theList = new List<int>();
theList.Add(theLeft);
theList.AddRange(theRet2[n]);
theRet3.Add(theList);
}
return theRet3;
}
}
}
MyMathLib系列(行列式计算2)的更多相关文章
- MyMathLib系列(行列式计算)
靠人不如靠己,准备做自己得MathLib,在学校的时候,就想过把数学数理的东西都计算机化.但一直没有时间去做这件事情,如今认为空余 时间比較闲,就做做这件事情,先从线性代数開始,毕竟这里面的非常多算法 ...
- 行列式计算(C#)
最近几天学习高等代数老师说要写个程序算行列式的结果,闲来无事就简单写了一下. 不多说了,上代码 using System; using System.Collections.Generic; usin ...
- n阶行列式计算----c语言实现(完结)
花了半天时间,写了这个n阶行列式计算的程序,应该算是比较优美吧,有很多地方多次做了优化,程序占用内存不是很大,要是说小吧,也不合适,因为里边有一个递归,而且递归的深度还比较深.时间复杂度具体没有细看, ...
- Java实现行列式计算
前天我看线代书,看到行列式,发现是个递归的式子,恰巧又正在学java,产生写程序实现的想法.写了两个小时,觉得实现了,写了个行列式放进去测试,我放的是 这个行列式,经过程序计算后发现结果是0.我以为我 ...
- 辛巴学院-Unity-剑英陪你零基础学c#系列(三)计算与类型
辛巴学院:正大光明的不务正业. 中秋节快乐,每逢佳节倍思亲,尤其是那素未谋面的老婆,对吧,屌丝们. 今天我们来探索一下C#里面奇怪的计算,奇怪的类型. 奇怪的计算 当我刚刚接触计算机编程的时候,一 ...
- JavaScript系列:计算一个结果为30的加法智力题
用下面这段JavaScript代码可以计算出来 function findTheThreeNum(numFix) { var a = ["1", "3", &q ...
- Vue.js系列之四计算属性和观察者
一.计算属性 1.模版内的表达式非常便利,但是设计它们的初衷是用于简单计算的.在模版中放入太多的逻辑运算会让模版过重且难以维护,例如如下代码: <div id="example&quo ...
- python 行列式计算
N= #声明2x2的数组arr并将所有元素赋值为 None arr=[[None] * N for row in range(N)] print('|a1 b1|') print('|a2 b2|') ...
- HDU 5852 Intersection is not allowed! ( 2016多校9、不相交路径的方案、LGV定理、行列式计算 )
题目链接 题意 : 给定方格中第一行的各个起点.再给定最后一行与起点相对应的终点.问你从这些起点出发到各自的终点.不相交的路径有多少条.移动方向只能向下或向右 分析 : 首先对于多起点和多终点的不相交 ...
随机推荐
- 贰、js的基础(三)数组
JS中数组的操作 1.数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长 ...
- matlab 中语句 a(b)的意思
a=[1 2; 3, 4; 5, 6]; b=[1 3 2 1; 1 2 4 2]; c=a(b) c = 1 5 3 1 1 3 ...
- 05004_Linux的其他命令和权限命令
1.其他命令 (1)显示当前所在位置 命令:pwd (2)搜索命令 a.命令:grep 要搜索的字符串 要搜索的文件 示例:搜索/etc/sudu.conf文件中包含字符串to的行 b.搜索/etc/ ...
- Linux学习总结(12)——Linux必须学会的60个命令
Linux系统信息存放在文件里,文件与普通的公务文件类似.每个文件都有自己的名字.内容.存放地址及其它一些管理信息,如文件的用户.文件的大小等. 文件可以是一封信.一个通讯录,或者是程序的源语句.程序 ...
- 现代C++ 基于范围的for和for_each语句
现代C++中强调,使用基于范围的 for 循环(Visual studio 2012之后的),相比于旧版的 for 循环更整洁和易于使用,并且不容易发生意外错误.让我们一睹为快. 当然,使用前需要包含 ...
- 集团公司(嵌入ETL工具)財务报表系统解决方式
集团公司(嵌入ETL工具)財务报表系统解决方式 一.项目背景: 某集团公司是一家拥有100多家子公司的大型集团公司,旗下子公司涉及各行各业,包含:金矿.铜矿.房产.化纤等.因为子公司在业务上的差异.子 ...
- 架构设计--用户端全http參数接口具体说明v1
1. 用户端全http參数接口具体说明v1.doc 1 2. change histor 1 3. 接口通用參数说明 1 4. 函数注冊接口(规划中) 3 5. 用户权限模块 3 5.1. 用户注冊接 ...
- [数位dp] bzoj 3209 花神的数论题
题意:中文题. 思路:和普通数位dp一样,这里转换成二进制,然后记录有几个一. 统计的时候乘起来就好了. 代码: #include"cstdlib" #include"c ...
- 又见关系并查集 以POJ 1182 食物链为例
简单的关系并查集一般非常easy依据给出的关系搞出一个有向的环,那么两者之间的关系就变成了两者之间的距离. 对于此题: 若u.v不在一个集合内,则显然此条语句会合法(暂且忽略后两条.下同). 那么将f ...
- mDNS原理的简单理解——每个进入局域网的主机,如果开启了mDNS服务的话,都会向局域网内的所有主机组播一个消息,我是谁,和我的IP地址是多少。然后其他也有该服务的主机就会响应,也会告诉你,它是谁,它的IP地址是多少
MDNS协议介绍 mDNS multicast DNS , 使用5353端口,组播地址 224.0.0.251.在一个没有常规DNS服务器的小型网络内,可以使用mDNS来实现类似DNS的编程接口.包格 ...