Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言

相关介绍

点击查看wiki百科详细介绍
在线性代数中,如果内积空间上的一组向量能够组成一个子空间,那么这一组向量就称为这个子空间的一个基。Gram-Schmidt正交化提供了一种方法,能够通过这一子空间上的一个基得出子空间的一个正交基,并可进一步求出对应的标准正交基。
这种正交化方法以约尔根·佩德森·格拉姆和艾哈德·施密特命名,然而比他们更早的拉普拉斯(Laplace)和柯西(Cauchy)已经发现了这一方法。在李群分解中,这种方法被推广为岩泽分解(Iwasawa decomposition)。
在数值计算中,Gram-Schmidt正交化是数值不稳定的,计算中累积的舍入误差会使最终结果的正交性变得很差。因此在实际应用中通常使用豪斯霍尔德变换或Givens旋转进行正交化。

算法流程

Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言_第1张图片
注意本博客V_i的划分方式。
Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言_第2张图片
Prove that v 2 ∗ · v 1 ∗ = 0, v 3 ∗ · v 1 ∗ = 0, and v 3 ∗ · v 2 ∗ = 0
例题一:
Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言_第3张图片例题二:
Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言_第4张图片
本人不才,计算上面例题的时候花了不少时间,第二天第一次就算对了,所以你也不要气馁,加油。
对于例题二手动过程如下:
在这里插入图片描述
Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言_第5张图片
Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言_第6张图片
最后结果如下:
Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言_第7张图片
作业:
Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言_第8张图片
Gram-Schmidt orthogonalization/斯密特正交化代码实现-Go语言_第9张图片

// Gram-Schimit.go
package main

import (
	"fmt"
)

var ExampleOne = [][]float32{ /*课本例题一*/
	{3, -1},
	{-5, 2}}

var ExampleTwo = [][]float32{ /*课本例题二*/
	{1, 0, 0},
	{4, 2, 15},
	{0, 0, 3}}

var TestOne = [][]float32{ /*待求数据一*/
	{1, 2, 3},
	{4, 1, -2},
	{-2, 1, 3}}

var TestTwo = [][]float32{ /*待求数据二*/
	{4, 1, 3, -1},
	{2, 1, -3, 4},
	{1, 0, -2, 7}}

func GramSchimit(GramOne [][]float32) { /*GramSchimit正交算法*/
	//var GramOne = make([][]float32, len(ParaTest)) /*len(ParaTest)的返回结果为切片的行数*/
	var VNumber int = len(GramOne)     /*将V_*的个数存入VNumber,len(GramOne)的返回结果为切片的行数*/
	var Miu = make([]float32, VNumber) /*开辟切片Miu用于存储计算出来的Miu,随着行数的增加,使用到的Miu也会增加*/
	var MiuIndex int = 0               /*Miu切片的下标*/
	var SumUp float32 = 0              /*Miu计算公式中的分子*/
	var SumDown float32 = 0            /*Miu计算公式中的分母*/
	/*for i := range ParaTest {
		GramOne[i] = ParaTest[i]
	}
	for i := range GramOne {
		fmt.Println(GramOne[i])
	}
	fmt.Println(GramOne)/*			/*此处注释为编写代码时用于数据校对使用*/
	for i := range GramOne {
		if i == 0 { /*第一行数据不参与运算*/
			continue
		}
		if MiuIndex < VNumber {
			for k := 0; k < i; k++ { /*k表示将i之前的V_*都参与计算*/
				for j := range GramOne[i] {
					/*
						Miu的计算公式为 SUM((V_i)*(V_j_*)/(V_j_*)*(V_j_*))
						SUM(GramOne[i][j]*GramOne[i-1][j])/SUM(GramOne[i-1][j]*GramOne[i-1][j])
					*/
					SumUp = SumUp + GramOne[k][j]*GramOne[i][j]
					SumDown = SumDown + GramOne[k][j]*GramOne[k][j]
					/*fmt.Println(GramOne[i-1][j] * GramOne[i-1][j])
					fmt.Println(GramOne[i-1][j])*/ /*此处注释为编写代码时用于数据校对使用*/
				}
				Miu[MiuIndex] = SumUp / SumDown /* Miu=SumUp/SumDown */
				//fmt.Println(SumUp, SumDown, MiuIndex, Miu[MiuIndex]) /*此处注释为编写代码时用于数据校对使用*/
				SumUp = 0
				SumDown = 0 /*Sum重置为0*/
				MiuIndex++  /*下标+1,为一次计算Miu做准备*/
			}
			/*VNumber是行数,Miu的个数为VNumber-2个,仅使用0至VNumber-2即可完全表示。
			如由三行V_*,则只需进行两次计算,仅使用0,1(0至3-2=1)下标即可。*/
			if i == 1 { /*第一行,使用第一个Miu(Miu[0])即可*/
				for j := range GramOne[i] {
					//fmt.Println(GramOne)
					GramOne[i][j] = GramOne[i][j] - Miu[0]*GramOne[i-1][j]
					//fmt.Println(GramOne[i][j], Miu[0])
				}
			}
			if i == 2 { /*第二行,使用第二个和第三个Miu即可(Miu[1]和Miu[2])*/
				for m := 1; m < 3; m++ {
					/* m=1时,表示第一个Miu与第一行相乘,此时行数的下标为0
					   m=2时,表示第二个Miu与第二行相乘,此时行数的下标为1 */
					for j := range GramOne[i] {
						GramOne[i][j] = GramOne[i][j] - Miu[m]*GramOne[m-1][j] /* Miu[m]*V_m-1_* */
						/*fmt.Println(GramOne[m-1][j], Miu[m])     /*此处注释为编写代码时用于数据校对使用*/
					}
				}
			}
		}
		/*fmt.Println(MiuIndex)   /*此处注释为编写代码时用于数据校对使用*/
	}
	/*fmt.Println(Miu)     /*此处注释为编写代码时用于数据校对使用*/
	fmt.Println(GramOne)
}
func main() {
	fmt.Println("helloworld")
	//GramSchimit(ExampleOne)
	//GramSchimit(ExampleTwo)
	GramSchimit(TestOne)
	//GramSchimit(TestTwo)
}

你可能感兴趣的:(安全)