用雅可比(Jacobi)方法求解矩阵方程(修订)


11

数学背景

设A为实数的N×N矩阵,N个实数的ba向量和xa个N个未知实数向量。矩阵方程为Ax = b。

Jacobi的方法如下:分解A = D + R,其中D是对角线矩阵,R是其余项。

如果您做出初始猜测解x0,则改进的解为x1 =逆(D)*(b-Rx),其中所有乘法都是矩阵矢量乘法,而逆(D)是矩阵逆。


问题规格

  • 输入:完整的程序应接受以下数据作为输入:矩阵A,向量b,初始猜测x0和“错误”数e。
  • 输出:程序必须输出最少的迭代次数,以使最新的解决方案与实际解决方案之间的差异最多为e。这意味着矢量的每个分量的绝对大小最多相差e。您必须使用Jacobi的方法进行迭代。

如何输入数据是您的选择 ; 它可以是您自己在命令行上的语法,也可以从文件中获取输入,无论您选择什么。

数据的输出方式是您的选择 ; 可以将其写入文件,在命令行中显示,以ASCII文字形式书写,并且只要人类可以阅读即可。

更多详情

您没有得到真正的解决方案:如何计算真正的解决方案完全取决于您自己。例如,您可以通过Cramer规则或直接计算逆来解决它。重要的是您拥有一个能够与迭代进行比较的真正解决方案。

精度是一个问题;有些人的“确切解决方案”可能会有所不同。出于该代码的目的,精确的解决方案必须为10个小数位。

绝对清楚地说,即使您当前迭代解决方案的一个组成部分比真实解决方案中的相应组成部分都增加了e,那么您需要保持迭代。

N的上限取决于您所使用的硬件以及您愿意花多少时间运行该程序。出于此代码高尔夫球的目的,假定最大值N = 50。

前提条件

调用程序时,您可以随时假设以下条件成立:

  • N> 1且N <51,即您永远不会得到标量方程,而总是矩阵方程。
  • 所有输入都在实数范围内,并且永远不会复杂。
  • 矩阵A总是使方法收敛到真正的解,这样您总是可以找到许多迭代以最小化小于或等于e的误差(如上定义)。
  • A 永远不是零矩阵或恒等矩阵,即有一个解。

测试用例

A = ((9, -2), (1, 3)), b = (3,4), x0 = (1,1), e = 0.04

真正的解决方案是(0.586,1.138)。第一次迭代得到x1 =(5/9,1),与真实解的差异至少为0.04,相差至少一个分量。再进行一次迭代,我们发现x2 =(0.555,1.148)与(0.586,1.138)相差不到0.04。因此输出是

2

A = ((2, 3), (1, 4)), b = (2, -1), x0 = (2.7, -0.7), e = 1.0

在这种情况下,真正的解决方案是(2.2,-0.8)并且初始猜测x0已经具有小于e = 1.0的误差,因此我们输出0。也就是说,每当不需要进行迭代时,您只需输出

0

提交评估

这是代码高尔夫球,此处不允许所有标准漏洞。最短的正确完整程序(或功能),即最少的字节数获胜。它鼓励要用的东西像数学其中包裹了很多必要的步骤为一体的功能,但使用任何你想要的语言。


2
您确实应该等待获得更多反馈,尤其是考虑到最近的关闭帖子。PPCG挑战通常在规范中具有相同的结构,通常使它们易于理解,而不是繁琐和模棱两可。尝试看一些合理的挑战并模仿格式。
Uriel's

@Uriel我意识到了这一点,但是我觉得我在规范中已经很详尽了,虽然格式不能完全适合大多数问题,但是可以线性阅读并相应地指导读者。该格式还应牢记问题本身的内容。
user1997744 '17

3
“最短正确的完整程序 ”听起来像您只允许程序,而不是功能。我要添加“ /功能”。
亚当

2
+1格式使我的大脑专注于一个问题的能力成败或中断
Stephen

1
@ user1997744是的,很有道理。我相信默认值是允许其他任何代码,例如其他函数或python导入,但也包括在字节数中。
斯蒂芬

Answers:


4

APL(Dyalog)78 68 65 49字节

正是为APL创建的问题类型。

-3感谢外长艾里克(Erik the Outgolfer)。-11感谢ngn

匿名中缀函数。将A作为左参数,将x作为右参数。将结果打印为STDOUT并以垂直一元格式显示,1用作提示标记,后跟0标点。这意味着即使0结果也可以看到,在1之前不存在0

{⎕←∨/e<|⍵-b⌹⊃A b e←⍺:⍺∇D+.×b-⍵+.×⍨A-⌹D←⌹A×=/¨⍳⍴A}

在线尝试!

阅读顺序说明

请注意,代码的读取方式与问题规范非常相似:

{} 在给定的A,b和e以及给定的x上,
⎕← 打印
∨/ 语句中是否存在任何真相,即
e< e小于
|⍵- x的绝对值减去
b⌹ b矩阵除以
⊃A b e A,b和b中的第一个e(即A)
←⍺ 是左引数
: ,如果是,则
  ⍺∇ 递归于
  D+.× D矩阵乘以
  b- b减
  ⍵+.×⍨ x,矩阵乘以
  A- A减去
  ⌹D D的倒数(其余项)
   ,其中D是
   A,其中 形状的 坐标
  =/¨ 相等A(即对角线)
  
  ⍴A

分步说明

从右到左的实际执行顺序:

{} 匿名函数,其中a是be和⍵是x:
A b c←⍺ 将左参数拆分为A,b和e,
 选择第一个(A)
b⌹ 矩阵除法,其中b(给出x的真值)等于x的
⍵- 当前值与 可接受的
| 绝对值之差
e<误差小于那些?
∨/ 对吗?(照亮或缩小)
⎕← 将布尔值打印到STDOUT
: ,如果是这样:
  ⍴A 形状
   为该形状的矩阵,其中每个单元格是每个单元格各自的坐标
  =/¨ ,垂直坐标和水平坐标是否相等?(对角线)
   将A的单元格与D中的那个(提取对角线)
   矩阵逆
  D← 存储相乘(对于D对角线)
  
  A- 从A
  ⍵+.×⍨ 矩阵求 逆(返回正态)减去(与点积相同,因此是.)用x
  b- 从
  D+.× D的b 矩阵乘积中减去,并
  ⍺∇ 在给定A为be的情况下应用此函数,并作为x的新值


输出应该是精度为所需的迭代次数e
Zgarb

-1:这不是解决方案。您需要x0,因为整个要点是要知道从特定起点到达到所需精度需要花费多少步骤。
user1997744 '17

@ user1997744啊,我误解了这个问题。抱歉。
亚当

@ user1997744更好吗?
亚当

1
@ user1997744不是算术运算,只是具有读取一元字符的能力,实际上0代表什么都不是
亚当

1

Python 3,132字节

f=lambda A,b,x,e:e<l.norm(x-dot(l.inv(A),b))and 1+f(A,b,dot(l.inv(d(d(A))),b-dot(A-d(d(A)),x)),e)
from numpy import*
l=linalg
d=diag

在线尝试!

使用递归解决方案。


@Adám我不确定我是否完全理解。我将其解释为f在代码块中没有名称,该名称现在已修复;但是,如果完全是一个不同的问题,则可能仍然是一个问题。
notjagan

@Adám这个答案似乎证实了我目前所拥有的;它是一个带有帮助程序代码的函数,可以在定义后作为一个单元工作。
notjagan

喔好吧。没关系。我不了解Python,所以我很好奇。做得好!
亚当

停止标准不是“这意味着向量的每个分量的绝对大小最多相差e”?基本上是max-norm,不是L2-norm。
NikoNyrh

@NikoNyrh固定。
notjagan

1

R,138字节

function(A,x,b,e){R=A-(D=diag(diag(A)))
g=solve(A,b)
if(norm(t(x-g),"M")<e)T=0
while(norm((y=solve(D)%*%(b-R%*%x))-g,"M")>e){T=T+1;x=y}
T}

在线尝试!

感谢NikoNyrh修复了错误

还值得注意的是,有一个R包,Rlinsolve其中包含一个lsolve.jacobi函数,返回带有x(解决方案)和iter(所需的迭代次数)的列表,但是我不确定它是否执行正确的计算。


停止标准不是“这意味着向量的每个分量的绝对大小最多相差e”?基本上是max-norm,不是L2-norm。
NikoNyrh

@NikoNyrh你是对的!幸运的是,该norm函数也为我提供了额外的字节数。
朱塞佩

1

Clojure中,212个 198 196字节

#(let[E(range)I(iterate(fn[X](map(fn[r b d](/(- b(apply +(map * r X)))d))(map assoc % E(repeat 0))%2(map nth % E)))%3)](count(for[x I :while(not-every?(fn[e](<(- %4)e %4))(map -(nth I 1e9)x))]x)))

在没有矩阵库的情况下实现,将过程迭代1e9次以获得正确答案。这不适用于条件太差的输入,但在实践中应该可以正常工作。

少打高尔夫球,我对Rand 的表达式感到很满意D:)第一个输入%(A)必须是向量,而不是列表,这样assoc才能使用。

(def f #(let[R(map assoc %(range)(repeat 0))
             D(map nth %(range))
             I(iterate(fn[X](map(fn[r x b d](/(- b(apply +(map * r x)))d))R(repeat X)%2 D))%3)]
          (->> I
               (take-while (fn[x](not-every?(fn[e](<(- %4)e %4))(map -(nth I 1e9)x))))
               count)))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.