수학적 배경
A를 실수의 N x N 행렬, N 실수의 ba 벡터 및 xa 벡터 N 알 수없는 실수로하자. 행렬 방정식은 Ax = b입니다.
Jacobi의 방법은 다음과 같습니다. 분해 A = D + R. 여기서 D는 대각선의 행렬이고 R은 나머지 항목입니다.
초기 추측 솔루션 x0을 만드는 경우 개선 된 솔루션은 x1 = inverse (D) * (b-Rx)입니다. 여기서 모든 곱셈은 행렬-벡터 곱셈이고 inverse (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
제출 평가
이것은 모든 표준 허점이 허용되지 않는 코드 골프입니다. 가장 짧은 정확한 완전한 프로그램 (또는 기능), 즉 가장 적은 바이트 수가 이깁니다. 그것은되는 낙담 한 함수에 필요한 많은 단계를 마무리하지만, 당신이 원하는 언어를 사용 티카 같은 사용 것들.
답변
APL (Dyalog) , 78 68 65 49 바이트
정확하게 APL이 만들어지는 문제의 유형.
-3 Outgolfer Erik에게 감사합니다 . ngn 덕분에 -11 감사합니다 .
익명의 접사 기능. A를 왼쪽 인수로 사용하고 x를 오른쪽 인수로 사용합니다. 1
탈리 마크를 사용하고 그 뒤에 0
구두점을 사용하여 결과를 STDOUT에 세로 단항으로 인쇄 합니다 . 즉, 1
앞에 0이없는 0 결과도 볼 수 있습니다 0
.
{⎕←∨/e<|⍵-b⌹⊃A b e←⍺:⍺∇D+.×b-⍵+.×⍨A-⌹D←⌹A×=/¨⍳⍴A}
읽기 순서 설명
코드가 문제 사양과 매우 유사하게 읽는 방법에 주목하십시오.
{
… }
지정된 A, B 및 E, 및 주어진 X에
⎕←
인쇄
∨/
되는 문의 모든 진리가 있는지
e<
예는보다 작은
|⍵-
절대 값이 X 뺀
b⌹
행렬 분할하여 B
⊃A b e
A, B의 제 및 E (즉, A)
←⍺
왼쪽 인자있는
:
등, 경우
⍺∇
재귀
D+.×
D 행렬 배
b-
마이너스 B
⍵+.×⍨
X는 매트릭스 승산
A-
마이너스
⌹D
D (나머지 항목)의 역
←
D가 동일있다 좌표 형상 A (즉, 대각선)
A×
=/¨
⍳
⍴A
단계별 설명
오른쪽에서 왼쪽으로 실제 실행 순서 :
{
… A가 있고 ⍵이 x 인 }
익명 함수 ⍺
:
A b c←⍺
왼쪽 인수를 A, b로 나누고 e 는 x의 현재 값과 허용 가능한 절대 값 사이 의 b (x는 실제 값 제공
⊃
)를
b⌹
갖는 첫 번째 (A) 행렬 나누기를 선택합니다. 그보다 적은 오류? 어떤 사실입니까? (lit. OR reduction) 해당 부울을 STDOUT으로 인쇄 하고 그럴 경우 : 모양 각 셀이 각 셀에 대한 고유 좌표 인 해당 모양 의 행렬은 세로 및 가로 좌표가 동일합니까? (대각선) 그 (추출 대각선)와의 곱셈 세포 역행렬 D에 저장 (용 D iagonal)
⍵-
|
e<
∨/
⎕←
:
⍴A
⍳
=/¨
A×
⌹
D←
⌹
A-
A
⍵+.×⍨
행렬 에서 역 (역으로 돌아 가기) 빼기 (점 곱과 같은 것, 따라서 .
) x 는 D의
b-
b
D+.×
행렬 곱 에서 빼고
⍺∇
주어진 A be와 함께이 함수 를 적용하고 x의 새로운 값으로 곱합니다.
답변
파이썬 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
재귀 솔루션을 사용합니다.
답변
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에게 감사합니다
함수 Rlinsolve
를 포함하고 (솔루션)과 (반복 횟수 )가 lsolve.jacobi
있는 목록을 반환 하는 R 패키지가 있다는 점도 주목할 가치가 있지만 올바른 계산을 수행하는지 확실하지 않습니다.x
iter
답변
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 회 반복합니다. 이것은 너무 좋지 않은 입력에 대해서는 작동하지 않지만 실제로는 잘 작동합니다.
이하 나는 표현에 아주 행복했다, golfed R
과 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)))