(번역) MATLAB의 과거와 오늘 - 처리 능력의 진화를 시각화 해보았다.
본 포스트의 원문은 아래의 URL에서 확인하실 수 있습니다. 본 포스트는 원작자에게 동의를 구한 뒤 한국어로 번역하였습니다.
1. 시작하기
Windows 3.1 시대에 숫자 계산을 하던 BASIC에서 갑자기 MATLAB의 놀라움을 보여주는 순간을 절대 잊지 못합니다. 그 이후로 계속 MATLAB에 의지하고 있지만, 잊을 수 없는 것은 감동뿐만이 아닙니다. 그 때 혼자서 깨달았던 “사용상의 지침”도 기억에 남아, 아직도 그 영향에서 벗어나지 못하고 있습니다. 그 지침 중 하나는 “실용적인 행렬의 크기 제한은 최대 250행 × 250열 정도“라는 것입니다. 다른 누구에게 감화된 것도 아니고, 이 정도 크기의 행렬을 다루면서, 계산 결과가 쉽게 나오지 않아서 체념하면서 느낀 노하우입니다. 그 이후로 큰 행렬을 다루는 기회가 많이 오지 않아, 이 선입견을 바로잡을 기회가 없었고 현재까지 이런 생각에 갇혀있습니다.
그런데 최신 버전인 (비교적 오래된) R2019a를 사용하여 아래 명령을 실행해 본 결과, 3000행 × 3000열의 대규모 행렬 연산이 2초도 걸리지 않고 완료되었으며, $|A^{-1}||A|{=}1$을 증명하는 고정밀이고 타당한 답을 제공해주었습니다. 계산 자체는 간단하게 공식집을 참고하여 답을 얻은 것 아니냐고 의심할 정도의 속도입니다. 그러나 약간의 오차가 포함되어 있다는 점을 보면, 하나하나의 요소를 귀중히 여기고 철저히 계산한 결과임은 분명합니다. 언제부터 이렇게까지 처리 능력이 향상된 걸까요?
>> tic; A=rand(3000)/10; [det(inv(A))*det(A) toc]
ans =
1.000000000002983e+00 1.415134600000000e+00
…그래서, 신규 및 이전 버전의 처리 능력(실행 시간 및 처리 가능한 크기 등)을 비교해보기로 결심하고, 다양한 실험을 해보았습니다.
2. 평가 방법
2.1 사용한 MATLAB 버전
다음 4가지 버전을 사용했습니다. Windows 3.1 시대의 MATLAB도 함께 포함하고 싶지만, 당시 근무한 회사가 구입한 것이므로 소유하고 있지 않습니다. 설치용 미디어는 수십 장의 3.5인치 플로피 디스크였으므로, 남아있다고 하더라도 과거 환경을 재현하는 데 상당한 어려움이 있었을 것입니다.
- R2019a Home
- R2007b Education
위 버전을 실행시키는 컴퓨터(FMVU75B3B)는 다음과 같습니다.
Windows 10 Home, 64bit, Core i5-8250U, 1.6GHz, RAM 4GB, SSD
LCD 13.3인치 와이드 1920×1080, 확대율 150% 사용(1280×720에 해당), 무게 1.0kg
- ver7.1(R14SP3) Education
- ver5.3(R11) Student
위 버전을 실행시키는 컴퓨터(FMVNB70ET)는 다음과 같습니다. Windows XP Home Edition, 32bit, Pentium4-M, 2.2GHz, RAM 768MB, HDD LCD 15인치 XGA 1024×768, 무게 4.0kg(포함: AC 어댑터, 0.2kg 정밀 체중계 사용)
위의 Windows 10 컴퓨터는 성능보다 휴대성을 우선시하여 구입한 것입니다. 스타벅스에서 멋지게 사용하며, 젊은이들에게 뒤지지 않는다는 것을 자랑하고 싶은 사악한 마음에서입니다. MATLAB로부터는 “이 수준의 컴퓨터를 사용하여 수행한 것을, 마치 성능 한계인 것처럼 선전되면 곤란하다!”라고 꾸짖음을 받을 것 같습니다. 그러나 이것은 일시적인 사용자에 의한 개인적이고 독특한 평가에 지나지 않으므로 양해 부탁드립니다.
후자의 XP 컴퓨터는 우리 집의 4세대 이전의 빈티지 제품입니다. 먼지에 덮여 있던 것을 꺼내왔습니다. LCD 화면은 일부 표시가 누락되었고 키보드의 문자도 사라져갔지만, 평가에 필요한 기능은 어떻게든 확보할 수 있었습니다. 내장 타이머가 초기화된 채로 MATLAB이 실행되지 않거나, 평가 중에 HDD에서 고장나는 소리가 들려 불안에 빠지기도 했지만…
위에서 언급한 대로, MATLAB의 처리 능력은 버전만으로 결정되는 것은 아니고 컴퓨터의 사양에도 크게 영향을 받습니다. 이 관점에서 MATLAB 각 버전의 발표 시기를 조사해보면, 당시 가장 가능성이 있는 컴퓨터와의 조합은 다음과 같을 것으로 생각됩니다.
MATLAB 버전 | 동시대의 컴퓨터 |
---|---|
R2019a(2019) | Windows10(2015/7) |
R2007b(2007) | WindowsVista(2006/11) or XP(2001/9) |
ver7.1(2005) | WindowsXP(2001/9) |
ver5.3(1999) | Windows98(1998/7) or 95(1995/11) |
??? | Windows3.1(1993/5) |
이에 따르면, 사용한 MATLAB 중 R2007b와 ver5.3은 사용한 컴퓨터가 당시의 것보다 최신 모델입니다. 이 경우, 당시에 체감했던 처리 능력보다 더 좋은 평가 결과가 나올 수 있습니다. 따라서 이러한 결과에 대해서는 약간의 할인이 필요한 평가를 하는 것이 좋을 것입니다. 그러나 동시대의 컴퓨터라 하더라도 가격에 따라 성능은 천차만별입니다. 세세한 사항을 언급하기 시작하면 제어할 수 없을 정도로 복잡해질 것 같으므로 이 정도로 마치겠습니다.
2. 2 평가 대상 연산 처리
계산 규모가 크고 시간이 오래 걸릴 것으로 예상되는 처리에 대해, 다양한 행렬 연산과 메시그리드 응용 계산에 대해 조사하려고 합니다.
2. 2. 1 행렬 연산
연산 대상 행렬 생성
행렬 연산으로는 행렬식 (det), 곱셈 (*, mtimes), 역행렬 (inv), 고유값 (eig)의 연산 능력에 대해 조사합니다. 구체적으로는 행렬의 크기를 점차적으로 크게하여 이러한 처리에 소요되는 시간을 측정할 것입니다.
이를 위해서는 먼저, 연산 대상이 될 거대한 행렬을 생성해야 합니다. 가장 간편한 방법은 난수를 사용하는 것입니다. 그러나 해결해야 할 문제가 하나 있습니다. “처음에” 설명된 명령줄 입력에서는 A=rand(3000)으로 0부터 1까지의 범위에서 난수를 요소로 하는 크기가 3000×3000인 행렬을 생성하고 있습니다. 그러나, 이렇게만 해결하면 행렬식이 오버플로되어 ±Inf로 변해버리기 때문에 모든 요소의 값을 1/10으로 줄여 이 문제를 피하고 있습니다.
하지만, 이 제수(나누는 수)의 값은 항상 10으로 고정해야 하는 것은 아닙니다. 상당한 자유도가 있지만, 행렬의 크기에 맞게 제대로 조정하지 않으면 결과가 오버플로 또는 언더플로되어 평가가 불가능해집니다. 그래서 먼저 최적의 제수(나누는 수)를 결정하기 위한 실험을 진행했습니다. “최적”의 정의는 제멋대로 정했습니다. 행렬식의 값이 오버플로나 언더플로에서 가장 멀어지는 상태, 즉 거의 e+00 오더가 되는 것으로 가정합니다.
왜 행렬식의 값을 그렇게 중요하게 여기는지 의문을 가질 수도 있습니다. 이유는 다음과 같습니다. 이 실험에서는 수고로운 처리 시간을 측정해도 연산 결과가 잘못된다면 의미가 없습니다. 먼저 연산 결과가 올바른지 확인해야 합니다. 그러나 연산 결과의 거대한 크기의 행렬 요소를 하나씩 확인하는 것은 불가능합니다. 따라서 행렬식이 가지는 성질을 이용하여 대략적으로 올바르거나 잘못되었는지를 판단합니다. 따라서 행렬식의 값이 모든 판단 기준이 되게 됩니다. 이를 제대로 표현할 수 없다면 연산 결과의 평가도 할 수 없습니다.
아래의 명령줄에서 $n$ 값으로 행렬의 크기를 설정하고, 제수(나누는 수) $K$ 값을 조금씩 변경하면서 출력된 $|A|$ 값이 거의 e+00 오더가 되는 지점을 찾습니다.
K=10; n=3000; disp(datestr(now,'dd-mmm-yyyy HH:MM:SS')), pause(0.5); A=rand(n)/K; disp(det(A))
이 결과로 얻어진 것은 그림 1의 파란 동그라미 플롯입니다. 이 플롯은 행렬 크기에 따른 최적의 제수(나누는 수)와의 관계를 보여주는 것입니다. 놀랍게도, $\pmb{K{=}0.175\sqrt{n}}$의 빨간색 선 위에 깔끔하게 위치하고 있음을 알 수 있습니다. 따라서, 이 실험에서는 다음의 식을 사용하여 대상 행렬을 생성하기로 합니다.
A=rand(n)/(0.175\*sqrt(n));
이러한 간단한 관계식이라면, 분석적으로 쉽게 유도할 수 있을 것 같지만 아직 달성하지 못했습니다. 또한, 그림 1에는 최적의 $K$ (Kbest)뿐만 아니라 언더플로 직전의 Kmax와 오버플로 직전의 Kmin 곡선도 함께 표시되어 있습니다. Kmin ~ Kmax로 둘러싸인 영역이 정상적인 $|A|$를 출력할 수 있는 범위가 됩니다. 많은 자유도가 있지만, n이 매우 커지면 K 값의 허용 범위가 점점 좁아지게 됩니다.
ver5.3의 Kmax 곡선은 최적 K 선을 점진적으로 따라 오르는 직선입니다. 그러나 이보다 더 최신 다른 버전들(그림에서는 R2019a를 대표로 함)은 압축된 비자연스러운 모양을 갖고 있는 것이 걱정됩니다. 이들은 행렬식의 계산 방법이나 난수 생성 알고리즘이 다른 것일까요? 이로 인해 이 실험에서 최적 K 선을 기준으로 한다면, 연산 가능한 행렬의 크기는 새로운 버전에서 낮아지는 경향이 있습니다.
그런데, 이러한 데이터 수집에는 엄청난 시간이 소요되어 실망했습니다. 아무리 한가한 노인이라 할지라도, 이러한 작업은 이제 진저리가 나네요.
연산 결과의 옳고 그름 판단
아래 표의 왼쪽 열의 각 연산 결과에 대해, 오른쪽 열의 식을 만족시키는 것으로서 옳은 답임을 확인합니다. 옳지 않은 경우에는 처리 시간을 측정해도 의미가 없으므로 측정 대상에서 제외합니다.
판정 대상 | 옳고 그름 판정 기준 |
---|---|
행렬식 $|A|$ | $|A^{\mathrm{T}}|/|A|{=}1$ |
행렬곱 $AA$ | $|AA|/|A|^2{=}1$ |
역행렬 $A^{-1}$ | $|A^{-1}||A|{=}1$ |
고유값 $\lambda_i$ | $(\prod_{i=1}^{n}\lambda_i)/|A|{=}1$ |
잘못된 답변인 경우, 옳고 그름 판정 값이 1에서 멀어진 값(±Inf, 0, NaN, 4.5e-123 등)이 되기 때문에 판단에 혼란이 없습니다. 대부분은 1.000000 수준에서 1을 만족하지만, 일부는 1.000099가 되는 경우도 있었습니다. 이 경우에도 옳은 답변으로 처리합니다(ver7.1에서 n=4000의 행렬곱).
처리 가능한 행렬 크기의 추정
특히 오래된 버전에서는, 일련의 데이터 수집에는 엄청나게 긴 시간이 소요됩니다. 데이터 수집 프로그램을 그냥 실행하면 중간에 멈추고 강제 종료되어 처음부터 다시 시작해야 합니다. …그래서 각 버전마다 사전에 처리 가능한 행렬 크기의 범위를 미리 파악해야 합니다. 이를 위해 다음의 커맨드 문자열을 직접 명령줄에서 조작했습니다. 데이터 수집 프로그램에서 지시하는 “처리해야 할 행렬 크기” 범위는 이러한 결과를 바탕으로 결정하였습니다.
% 성능 한계의 사전 확인 (행렬식 계산)
n=1000; disp(datestr(now,'dd-mmm-yyyy HH:MM:SS')), pause(0.5); A=rand(n)/(0.175*sqrt(n)); detA=det(A); B=A'; tic; ansA=det(B); ta=toc; jg=ansA/detA; tb=toc; disp([ta jg tb])
% 성능 한계의 사전 확인 (행렬곱 계산)
n=1000; disp(datestr(now,'dd-mmm-yyyy HH:MM:SS')), pause(0.5); A=rand(n)/(0.175*sqrt(n)); detA=det(A); tic; ansA=A*A; ta=toc; jg=det(ansA)/detA^2; tb=toc; disp([ta jg tb])
% 성능 한계의 사전 확인 (역행렬 계산)
n=1000; disp(datestr(now,'dd-mmm-yyyy HH:MM:SS')), pause(0.5); A=rand(n)/(0.175*sqrt(n)); detA=det(A); tic; ansA=inv(A); ta=toc; jg=det(ansA)*detA; tb=toc; disp([ta jg tb])
% 성능 한계의 사전 확인 (고윳값 계산)
n=1000; disp(datestr(now,'dd-mmm-yyyy HH:MM:SS')), pause(0.5); A=rand(n)/(0.175*sqrt(n)); detA=det(A); tic; ansA=eig(A); ta=toc; jg=abs(prod(ansA)/detA); tb=toc; disp([ta jg tb])
평가용 프로그램
위 내용을 바탕으로, 맨 아래의 “프로그램” 섹션에 첨부된 데이터 수집용 프로그램을 만들었습니다. 사용하는 어떤 MATLAB 버전에서도 작동할 수 있도록 조정되어 있습니다. 오래된 MATLAB에서는 받아들여주지 않는 명령도 많기 때문에, 공유를 위해 예전을 회상하며 조정하는 데 상당한 노력을 기울였습니다. 인터넷에서는 예전 버전에 대한 정보를 얻기 어렵기 때문에, 명령 창에서만 해당 버전의 사용 방법을 알 수 있는 도움말 명령어는 큰 도움이 됩니다.
특히 오래된 버전에서 가장 불편한 점은 R2007b를 포함하여 이전 버전에서는 스크립트 내에서 로컬 함수를 정의할 수 없는 점입니다. 처리 능력을 평가하기 위해서는 데이터 규모나 처리 시간뿐만 아니라 이러한 편의 기능도 고려하는 것이 중요하다고 느꼈습니다.
자, 계산할 때마다 실행 시간은 약간씩 변동합니다. 이러한 변동의 경향도 파악하기 위해 완전히 동일한 계산을 5번 실행시킵니다. 이를 통해 평균 시간과 최단 및 최장 시간을 구하고 그래프로 표시하기로 합니다.
데이터 수집용 프로그램을 실행하는 동안 다른 프로그램과의 간섭을 피하기 위해 주의하였습니다. 그러나 편의를 위해 대기 상태인 탐색기와 Editor 창은 열어두기로 결정했습니다. 또한, ver5.3에서 프로그램 실행 중에 명령 창을 클릭하면 “응답 없음”이 표시되며, 강제 종료 이외의 조작은 받아들이지 않게 됩니다. 결과가 궁금해서 유혹에 빠져 클릭하는 일이 종종 있을 수 있지만, 프로그램이 완료될 때까지 참을성을 가지고 기다려야 합니다.
2.2.2 Meshgrid의 응용 계산
등고선 그리기
처리 능력을 평가하기 위해 contour 명령을 사용하여 그림 2와 같은 등고선을 그립니다. 등고선은 메시를 더 세밀하게 분할할수록 매끄러워집니다. 일반적으로 한 변을 100~200 등분 정도로 설정하면 충분한 매끄러움을 얻을 수 있습니다. 그 이상으로 세분화해도 차이를 알아챌 수 없습니다. 5000 등분까지 평가하는 것이 어떤 이점이 있는지 의문이 남지만, 처리 능력을 이해하기 위한 시련으로 간주하여 강행했습니다.
그려지는 등고선의 수는 처리 시간에 직접적인 영향을 미칠 것입니다. 하지만 이번에는 해당 관계에 대해 깊이 고민하지 않았습니다. 특별한 이유는 없으며, 적당한 수로 8개 레벨을 선택했습니다.
평가용 프로그램
기본적인 처리 내용은 명령 창에서도 조작할 수 있는 다음과 같습니다.
n=1000; x=linspace(-1,1,n+1); [X,Y]=meshgrid(x,x); Z=X.^2.*(1-X.^2)-Y.^2; tic; [c,h]=contour(X,Y,Z,[-0.5:0.1:0.2]); toc
위의 [c,h]=contour(…) 부분을 단순히 contour(…)로 작성해도 등고선을 그릴 수 있습니다. 그러나 toc에서 얻은 처리 시간이 너무 짧다고 느껴졌습니다. 뭔가 contour만으로는 반환 값이 존재하지 않아 메인 루틴이 contour에 인수를 전달하는 단계에서 처리 완료를 선언하는 것은 아닌지 의심이 들었습니다. 반환 값을 강제로 가져오기 위해 [c,h]=를 추가하고 실행해보니, 처리 시간이 합리적으로 늘어났기 때문에 이 방법을 채택하였습니다.
평가용 프로그램에서는 위와 동일한 작업을 meshgrid의 분할 수를 점점 늘리면서 반복합니다. 행렬 연산 평가와 마찬가지로 완전히 동일한 계산을 5번 실행하여 처리 시간의 평균값과 최소/최대값을 구합니다.
3. 평가 결과
3.1 연산 능력
정보를 정리하기 위해 데이터 수집 프로그램에서 얻은 정보를 활용하여 다음 연속된 그래프를 만들었습니다. 그림 3은 상단에는 행렬식, 하단에는 행렬 곱셈에 대한 그래프이며, 그림 4는 상단에는 역행렬, 하단에는 고유값에 대한 그래프입니다. 각각 행렬의 크기와 처리 시간의 관계를 보여줍니다. 또한, 그림 5는 등고선 그리기에 대한 메시 분할 수와 그리기 시간의 관계를 보여줍니다.
전반적으로, MATLAB의 버전이 최신화될수록 처리 시간이 짧아지는 것을 잘 알 수 있습니다. 또한, 로그 스케일을 사용하지 않으면 표현할 수 없을 정도로 큰 발전이 있었습니다. 일부 경우에는 최대 3개 주문(약 1000배) 가량의 가속화가 이루어졌습니다. Windows 3.1 시절의 MATLAB에 대한 평가가 타당한 것인지는 확실하지 않지만, 애매하게 알려져 있던 신·구 성능 차이를 명확히 확인할 수 있었습니다.
그러나, 처리할 수 있는 행렬의 크기는 가장 오래된 ver5.3이 더 크며, 등고선의 처리 시간은 한 단계 이전 버전이 더 짧다는 것은 놀랍습니다. 또한, 행렬의 크기 $n$과 처리 시간 $t$의 관계는 대략 $t=an^3$으로 표현될 수 있으며, 영역의 분할 수 $n$과 등고선 그리기 시간 $t$의 관계는 대략 $t=an^2+b$로 나타낼 수 있음을 알 수 있었습니다.
동일한 조건에서 5회 반복한 결과를 보여주고 있으나, 옅은 색으로 채워진 영역은 그리 넓지 않으며, 대부분의 경우에 변동성이 놀랍게도 적어 보입니다. 그러나, 다시 동일한 데이터를 수집해보면 그림의 형태가 꽤 변화한다는 것이 실제 상황입니다. 처리 속도의 순서가 바뀌는 정도까지는 없지만, 여기에 표시된 내용이 불변의 데이터라고 인식하는 것은 삼가야 합니다.
3.2 시각화 능력
처리 능력의 일부로 다루기 적합한지 여부는 알 수 없지만, 일련의 작업 중에서 알아차린 것은 figure의 표현력에 영향을 주는 버전 차이입니다.
그림 6~11은 각 MATLAB 버전의 figure를 스크린샷하고, 그대로의 픽셀로 png로 변환한 것입니다. 또한, R2019a와 R2007b에 대해서는 확대 비율을 지정할 수 있는 컴퓨터에서 작동시켜 각각 100%와 150%의 두 가지 조건으로 그렸습니다. 또한, R2019a에서는 그림 2의 색상이 기본값이지만, 이전 버전과 조건을 맞추기 위해 설정을 변경했습니다.
gcf에서 얻은 Position 정보에 따르면, 모든 figure의 너비는 560px이고 높이는 420px로 버전 간 차이가 없습니다. 또한, gca의 Position 정보에서도 figure 내의 축의 배치는 모두 동일합니다. 즉, figure를 그리기 위해 사용 가능한 픽셀 수는 버전 간 차이가 없습니다. 그러나 이미지의 표현력에는 차이가 있습니다.
구 버전을 사용한 그림 8~11은 모두 비슷하며, 비트맵 느낌이 강하고 아름다움이 부족합니다. 그러나, R2019a를 사용한 그림 6, 7에서는 선이나 문자가 매우 섬세하게 그려져 표현력이 한층 높아졌습니다. 특히, 확대 비율 150%로 그린 그림 6이 탁월합니다. 사실상 1.5의 제곱으로 픽셀 수가 증가하여 그림에 효과적으로 활용되는 것으로 보입니다. 또한, R2007b에는 표현력 개선을 위해 확대 비율을 활용하는 기능이 없어서, 100%와 150%의 그림에 큰 차이가 보이지 않습니다.
여기서 인식해주셨으면 하는 점은, 구 버전이라도 print 명령을 사용하여 종이에 인쇄하거나 다양한 이미지 형식으로 변환하면 화면 상의 그림보다 해상도가 높고 아름다운 그림을 얻을 수 있다는 것입니다. 화면 상의 표현력만으로 모든 것을 평가하려고 하는 것은 적절하지 않습니다. 그러나 인쇄된 그림이 화면에서 상상한 것과 약간 다르기 때문에 납득이 가지 않고, 그 수정을 위해 프로그램을 반복적으로 수정하기도 했습니다. 역시 화면 상의 그림과 인쇄 결과가 WYSIWYG(화면에 보이는 그대로 인쇄됨) 관계에 있는 것이 이상적입니다.
이 점에서 R2019a의 figure 표현력 향상은 매우 평가할 만한 것입니다. 최근에는 최종 결과물로 인쇄본보다 스크린 캡처를 직접 사용하는 경우가 많아졌습니다. 제 Qiita 게시물도 MATLAB 관련 그림은 모두 이 방식을 통해 작성되었습니다. 화면에 표시된 그대로 최종 결과물로 사용할 수 있는 현재의 상태가 저에게는 궁극적인 표현 형태라고 생각합니다.
4. 결론
이로써 신버전과 구버전 MATLAB의 능력 비교는 마무리되었지만, 제 환경에서는 확인할 수 없는 다음 성능에 대해서도 흥미가 생겼습니다. 관련된 흥미로운 정보를 가지고 계신 분이 계시다면 알려주시기 바랍니다.
- 최신의 R2023a와 고성능 컴퓨터를 사용한 처리 능력
- 슈퍼컴퓨터에서 작동하는 MATLAB의 처리 능력
마지막으로, 이 글을 작성하는 과정에서 마주친 납득하기 어려운 현상에 대해 소개하겠습니다. 이 현상을 어떻게 해석해야 일관성이 맞을까요?
이미 언급한 행렬 곱셈 평가에서는 A*A라는 연산을 대상으로 4000×4000 크기의 행렬까지 정답을 얻었다고 언급되어 있습니다. 그러나 처음에는 이를 변형한 A*A’로 생각하고 있었는데, 정답을 얻을 수 있는 행렬의 크기가 1500×1500까지밖에 되지 않았습니다. 그런데, A*A’의 경우에도 ver5.3만은 이보다 큰 크기에서도 정상 작동했습니다. 또한, A*flipud(A), A*fliplr(A)의 경우는 어떤 버전에서도 잘 작동했습니다. 확실히, A*A’의 경우에는 동일한 행렬의 행들 간에 내적을 수행하므로 특수한 조건이 됩니다. 그러나 균일한 난수라면 조건에 관계없이 정답을 얻어야 할 것입니다. 그림 1의 Kmax 그래프에서 ver5.3을 제외한 다른 버전이 직관적인 형태가 아니었던 점과 어떤 관련이 있는지 궁금합니다.
참고: |A*flipud(A)|=|A|^2, |A*fliplr(A)|=|A|^2은 행렬 A의 크기가 n×n이고 n=4N or n=4N+1 (N=1,2,3,…)인 경우에만 성립하는 관계입니다. 이 글에서는 n을 100의 배수 (또는 4의 배수)로 설정했기 때문에 우연히 성립한 것뿐입니다.
5. 프로그램
5.1 데이터를 얻기 위한 프로그램 (행렬계산)
% testMatrix03.m
% MATLAB의 행렬 계산 능력의 측정
% "데이터를 얻기 위한 프로그램"
% 평가 대상 함수: det, *(mtimes), inv, eig
clear
close all
testrep=5; % 테스트를 반복할 횟수
thisfile='testMatrix03.m';
% ■■■ 선택 필요 ■■■ ==========================
% 테스트할 매트랩의 버전을 번호로 선택
mat_ver=2; % 1:R2019a, 2:R2007b, 3:MATLAB7.1, 4:MATLAB5.3
% ===============================================
switch mat_ver
case 1
mat_name='R2019a';
case 2
mat_name='R2007b';
case 3
mat_name='ver7.1';
case 4
mat_name='ver5.3';
end
% 평가할 행렬의 크기 전체 보기
% R2019a용
nm11=[1 2 4 6 8 [10:5:40]]*100; % det용 n=4500에서 오답
nm12=[1 2 4 6 8 [10:5:40]]*100; % 행렬곱용 n=4500에서 오답
nm13=[1 2 4 6 8 [10:5:40]]*100; % 역행렬용 n=4500에서 오답
nm14=[1 2 4 6 8 [10:5:35]]*100; % 고유값용 n=4000에서 오답
% R2007b용
nm21=[1 2 4 6 8 [10:5:40]]*100; % det용 n=4500에서 오답
nm22=[1 2 4 6 8 [10:5:40]]*100; % 행렬곱용 n=4500에서 오답
nm23=[1 2 4 6 8 [10:5:40]]*100; % 역행렬용 n=4500에서 오답
nm24=[1 2 4 6 8 [10:5:35]]*100; % 고유값용 n=4000에서 오답
% MATLAB7.1용
nm31=[1 2 4 6 8 [10:5:40]]*100; % det용 n=4500에서 오답
nm32=[1 2 4 6 8 [10:5:40]]*100; % 행렬곱용 n=4500에서 오답
nm33=[1 2 4 6 8 [10:5:40]]*100; % 역행렬용 n=4500에서 오답
nm34=[1 2 4 6 8 [10:5:35]]*100; % 고유값용 n=4000에서 오답
% MATLAB5.3용 (n>5000은 조사하지 않음. 알 수 없음)
nm41=[1 2 4 6 8 [10:5:50]]*100; % det용 n=5000도 OK.
nm42=[1 2 4 6 8 [10:5:45]]*100; % 행렬곱용 n=5000에서 "메모리가 부족합니다."
nm43=[1 2 4 6 8 [10:5:50]]*100; % 역행렬용 n=5000도 OK.
nm44=[1 2 4 6 8 [10:5:30]]*100; % 고유값용 n=3500도 정답
% 1.5시간이 걸림.
% n=3000으로 중단.
nM={ nm11 nm12 nm13 nm14 ; ...
nm21 nm22 nm23 nm24 ; ...
nm31 nm32 nm33 nm34 ; ...
nm41 nm42 nm43 nm44 };
% 데이터 기록용 변수
size_vs_time=[];
% 중간에 프리즈되어도 데이터가 유지되도록 파일에 순차적으로 기록.
% 그것을 위한 파일 준비
Date=datestr(now,'dd-mmm-yyyy HH:MM:SS');
Date=strrep(strrep(strrep(Date,'-','_'),':','_'),' ','_');
fid=fopen(['xx_size_vs_time_' Date '.txt'],'w+');
fprintf(fid,['xx_size_vs_time_' Date '.txt']);
fprintf(fid,'\n');
fprintf(fid,'Ver Com Size Time_ave Time_min Time_max');
fprintf(fid,'\n');
fclose(fid);
com=[1 2 3 4]; % 테스트할 명령어 종류 목록
% 1:det, 2:mtimes, 3:inv, 4:eig
for nc=com; % 각각의 명령어에 대해 반복
switch nc
case 1
com_name='행렬식'; % 테스트할 기능명
nmat=nM{mat_ver,1}; % 계산해야 할 행렬 크기 목록
command='B=transpose(A); tic; ansA=det(B); te=toc;';
% 실행 시간 측정용 명령어
% R2007b에서는 문자열 ""는 사용할 수 없고 ''만 가능합니다.
% 따라서 문자열 내에서 전치를 '와 함께 사용할 수 없습니다.
% 그래서 transpose를 사용합니다.
judge='Jg=ansA/detA;'; % 정오 판단값 (1.0이면 정상)
case 2
com_name='행렬곱';
nmat=nM{mat_ver,2};
command='tic; ansA=A*A; te=toc;';
judge='Jg=det(ansA)/(detA^2);';
case 3
com_name='역행렬';
nmat=nM{mat_ver,3};
command='tic; ansA=inv(A); te=toc;';
judge='Jg=det(ansA)*detA;';
case 4
com_name='고유값';
nmat=nM{mat_ver,4};
command='tic; ansA=eig(A); te=toc;';
judge='Jg=abs(prod(ansA)/detA);';
end
for nm=nmat; % 각각의 행렬 크기에 대해 반복
A=rand(nm)/(0.175*sqrt(nm)); % 작업 대상 행렬 생성
detA=det(A); % 계산이 폭주하지 않는지 검증하는 기준
timedata=[]; % 매번 연산 실행 시간을 기록하는 행 벡터
for ne=1:testrep % 분산의 평균화를 위한 반복 처리
eval(command); % det, *, inv, eig, tic, toc를 포함하는
% 명령어 문자열 실행
if ne==1; % 1회만 실행. 2회부터는 동일한 값이어야 하므로 바이패스하여 시간을 절약합니다.
eval(judge); % 정오 판단값 생성
% 명령어 문자열 실행 (Jg 생성)
end
% 정오 판단값이 거의 1.000이면 정확하며, 실행 시간의 경향을
% 시각적으로 확인하기 위해 명령 줄에 매번 출력합니다.
disp([mat_name ' ' com_name ' ' ...
sprintf('%4s',num2str(nm)) '×' ...
sprintf('%4s',num2str(nm)) ...
' 정오 판단 ' num2str(Jg,'%8.6f') ...
' 처리 시간 ' num2str(te) ' 초'])
timedata=[timedata te]; % 매번 실행 시간을 모두 기록
end
% 반복 실행 결과로부터 평균, 최단, 최장 시간 계산 및 표시
t_ave=sum(timedata)/testrep; % 평균 시간
t_min=min(timedata); % 최단 시간
t_max=max(timedata); % 최장 시간
disp(' ')
disp([' 평균 시간: ' num2str(t_ave,'%11.5f') ...
' 최단 시간: ' num2str(t_min,'%11.5f') ...
' 최장 시간: ' num2str(t_max,'%11.5f')]);
disp(' ')
% 데이터 기록용 변수에 측정 결과 추가
% (MATLAB 버전, 명령어, 행렬 크기, 각 시간)
size_vs_time=[size_vs_time; ...
mat_ver nc nm t_ave t_min t_max];
% 중간에 프리즈되어도 데이터가 유지되도록 파일에도 순차적으로 기록
% ver5.3에서는 '%d'와 같이 명확히 지정하지 않으면 오류가 발생합니다.
fid=fopen(['xx_size_vs_time_' Date '.txt'],'a');
fprintf(fid,'%3s',num2str(mat_ver,'%1d'));
fprintf(fid,'%3s',num2str(nc,'%1d'));
fprintf(fid,'%6s',num2str(nm,'%4d'));
fprintf(fid,'%12s',num2str(t_ave,'%11.5f'));
fprintf(fid,'%12s',num2str(t_min,'%11.5f'));
fprintf(fid,'%12s',num2str(t_max,'%11.5f'));
fprintf(fid,'\n');
fclose(fid);
end
end
% 측정결과를 커맨드 라인에 문자 부호로 찍어내기
disp(datestr(now,'dd-mmm-yyyy HH:MM:SS'));
disp( [' created by ' thisfile ' on ' mat_name]);
disp('Ver Com Size Time_ave Time_min Time_max');
B=size_vs_time;
for n=1:size(B,1)
disp([sprintf('%3s',num2str(B(n,1),'%1d')) ...
sprintf('%3s',num2str(B(n,2),'%1d')) ...
sprintf('%6s',num2str(B(n,3),'%4d')) ...
sprintf('%12s',num2str(B(n,4),'%11.5f')) ...
sprintf('%12s',num2str(B(n,5),'%11.5f')) ...
sprintf('%12s',num2str(B(n,6),'%11.5f'))])
end
5.2 데이터 수집용 프로그램 (등고선 그리기)
% testMatrix06.m
% MATLAB의 등고선 그리기 능력 측정
% "데이터 수집용 프로그램"
clear
close all
testrep=5; % 테스트 반복 횟수
thisfile='testMatrix06.m';
% ■■■ 선택 필요 ■■■ ==========================
% 테스트할 MATLAB 버전을 번호로 선택
mat_ver=1; % 1: R2019a, 2: R2007b, 3: MATLAB7.1, 4: MATLAB5.3
% ===============================================
switch mat_ver
case 1
mat_name='R2019a';
case 2
mat_name='R2007b';
case 3
mat_name='ver7.1';
case 4
mat_name='ver5.3';
end
% 평가할 분할 수의 목록
% R2019a용
nd1=[1 2 4 6 8 [10:5:50]]*100; % n=5500은 확인하지 않음
% R2007b용
nd2=[1 2 4 6 8 [10:5:50]]*100; % n=5500은 확인하지 않음
% MATLAB7.1용
nd3=[1 2 4 6 8 [10:5:35]]*100; % n=4000에서 이상 동작
% MATLAB5.3용
nd4=[1 2 4 6 8 [10:5:35]]*100; % n=4000에서 이상 동작
nD={ nd1 nd2 nd3 nd4 };
% 데이터 기록용 변수
div_vs_time=[];
% 중간에 프리즈되어도 데이터가 유지되도록 파일에도 순차적으로 기록
% 그것을 위한 파일 준비
Date=datestr(now,'dd-mmm-yyyy HH:MM:SS');
Date=strrep(strrep(strrep(Date,'-','_'),':','_'),' ','_');
fid=fopen(['xx_div_vs_time_' Date '.txt'],'w+');
fprintf(fid,['xx_div_vs_time_' Date '.txt']);
fprintf(fid,'\n');
fprintf(fid,'Ver Com Div Time_ave Time_min Time_max');
fprintf(fid,'\n');
fclose(fid);
com=5; % 테스트할 명령어 종류
% 5:contour
com_name='등고선';
ndiv=nD{mat_ver}; % 분할 수 목록
for nd=ndiv; % 각각의 분할 수에 대해 반복
x=linspace(-1,1,nd+1); % -1부터 1까지를 nd분할한다.
y=x;
[X,Y]=meshgrid(x,y); % x,y 평면을 nd×nd로 분할한 메쉬
Z=X.^2.*(1-X.^2)-Y.^2; % 곡면 Z(X,Y)
timedata=[]; % 매번 연산 실행 시간을 기록하는 행 벡터
for ne=1:testrep % 변동성의 평균화를 위한 반복 처리
tic; % 시간 측정 시작
[dc,hc]=contour(X,Y,Z,[-0.5:0.1:0.2]); % 등고선 계산
te=toc; % 소요 시간 기록
% 실행 시간의 경향을 시각적으로 확인하기 위해 매번 콘솔에 출력
disp([mat_name ' ' com_name ' ' ...
sprintf('%4s',num2str(nd)) '×' ...
sprintf('%4s',num2str(nd)) ...
' 처리 시간 ' num2str(te) ' 초'])
timedata=[timedata te]; % 매번 실행 시간을 모두 기록
drawnow; % 그림 그리기 유도
pause(2); % 그림 결과를 확인하기 위해 2초간만 표시
close all; % 첫 번째 그림과 조건 맞춤을 위해
end
% 반복 실행의 결과로부터 평균, 최단, 최장 시간을 계산하고 출력
t_ave=sum(timedata)/testrep; % 평균 시간
t_min=min(timedata); % 최단 시간
t_max=max(timedata); % 최장 시간
disp(' ')
disp([' 평균 시간:' num2str(t_ave,'%11.5f') ...
' 최단 시간:' num2str(t_min,'%11.5f') ...
' 최장 시간:' num2str(t_max,'%11.5f')]);
disp(' ')
% 데이터 기록용 변수에 측정 결과 추가
% (MATLAB 버전, 명령어, 분할 수, 여러 시간)
div_vs_time=[div_vs_time; ...
mat_ver com nd t_ave t_min t_max];
% 중간에 프리즈되어도 데이터가 유지되도록 파일에도 순차적으로 기록
% ver5.3에서는 모호하게 '%d'로는 불가능. 자릿수를 명시하지 않으면 오류.
fid=fopen(['xx_div_vs_time_' Date '.txt'],'a');
fprintf(fid,'%3s',num2str(mat_ver,'%1d'));
fprintf(fid,'%3s',num2str(com,'%1d'));
fprintf(fid,'%6s',num2str(nd,'%4d'));
fprintf(fid,'%12s',num2str(t_ave,'%11.5f'));
fprintf(fid,'%12s',num2str(t_min,'%11.5f'));
fprintf(fid,'%12s',num2str(t_max,'%11.5f'));
fprintf(fid,'\n');
fclose(fid);
end
% 측정결과를 커맨드 라인에 문자 부호로 찍어내기
disp(datestr(now,'dd-mmm-yyyy HH:MM:SS'));
disp( [' created by ' thisfile ' on ' mat_name]);
disp('Ver Com Div Time_ave Time_min Time_max');
B=div_vs_time;
for n=1:size(B,1)
disp([sprintf('%3s',num2str(B(n,1),'%1d')) ...
sprintf('%3s',num2str(B(n,2),'%1d')) ...
sprintf('%6s',num2str(B(n,3),'%4d')) ...
sprintf('%12s',num2str(B(n,4),'%11.5f')) ...
sprintf('%12s',num2str(B(n,5),'%11.5f')) ...
sprintf('%12s',num2str(B(n,6),'%11.5f'))])
end
5.3 데이터의 그래프화 프로그램
최종적으로 채택한 측정 수치가 명시되어 있으므로, 안심을 위해 게시합니다.
사용자 정의 함수 make_axes_tidily
를 사용하고 있습니다.
(【MATLAB 사용자 정의 함수】자유도가 높은 “subplot의 변종”)
% testMatrix07.m
% MATLAB의 행렬 계산 능력, 등고선 계산 능력 측정 결과를 그래프로 나타냅니다.
clear
close all
% 측정 결과 (testMatric03.m, testMatric06.m에 의한)
% 1열: 1:R2019a, 2:R2007b, 3:ver7.1, 4:ver5.3
% 2열: 1:행렬식, 2:행렬곱, 3:역행렬, 4:고유값, 5:등고선
% 3열: 행렬 크기, 분할 수
% 4열: 평균 처리 시간 [초]
% 5열: 최단 처리 시간 [초]
% 6열: 최장 처리 시간 [초]
% MATLAB R2019a의 측정 결과
data01=[
1 1 100 0.00229 0.00054 0.00480
1 1 200 0.00091 0.00078 0.00118
1 1 400 0.00240 0.00184 0.00386
1 1 600 0.00741 0.00340 0.01272
1 1 800 0.01265 0.00887 0.01765
1 1 1000 0.02539 0.01786 0.03267
1 1 1500 0.06241 0.05843 0.07142
1 1 2000 0.09998 0.09678 0.10558
1 1 2500 0.16163 0.15030 0.18691
1 1 3000 0.29388 0.25771 0.33068
1 1 3500 0.41446 0.37204 0.44449
1 1 4000 0.61044 0.55276 0.69935
1 2 100 0.00130 0.00016 0.00344
1 2 200 0.00052 0.00034 0.00070
1 2 400 0.00303 0.00224 0.00368
1 2 600 0.00885 0.00681 0.01207
1 2 800 0.01956 0.01260 0.02503
1 2 1000 0.03461 0.02382 0.03907
1 2 1500 0.08758 0.08034 0.09270
1 2 2000 0.19124 0.15106 0.22087
1 2 2500 0.31125 0.28061 0.35784
1 2 3000 0.54782 0.45339 0.62738
1 2 3500 0.86390 0.76462 0.94933
1 2 4000 1.20136 1.12973 1.37760
1 3 100 0.00660 0.00052 0.02969
1 3 200 0.00216 0.00095 0.00622
1 3 400 0.00796 0.00570 0.01080
1 3 600 0.01694 0.01346 0.01912
1 3 800 0.02830 0.02311 0.03417
1 3 1000 0.05378 0.05067 0.06332
1 3 1500 0.13477 0.12015 0.16201
1 3 2000 0.27424 0.26614 0.28695
1 3 2500 0.50273 0.48888 0.51644
1 3 3000 0.80817 0.76344 0.83770
1 3 3500 1.35569 1.27317 1.44354
1 3 4000 1.87069 1.83551 1.92074
1 4 100 0.01440 0.00402 0.05400
1 4 200 0.02349 0.02117 0.02777
1 4 400 0.07628 0.07195 0.09006
1 4 600 0.22723 0.21886 0.24064
1 4 800 0.35808 0.34878 0.37077
1 4 1000 0.57684 0.55290 0.58788
1 4 1500 1.55741 1.53836 1.57451
1 4 2000 3.45890 3.43195 3.53665
1 4 2500 6.59489 6.56158 6.61371
1 4 3000 11.66058 11.53541 11.75744
1 4 3500 17.74509 17.57694 18.11189
1 5 100 0.09018 0.06668 0.11260
1 5 200 0.10157 0.09928 0.10434
1 5 400 0.14529 0.14058 0.15164
1 5 600 0.21915 0.21437 0.22513
1 5 800 0.29538 0.28526 0.30494
1 5 1000 0.41234 0.40947 0.41646
1 5 1500 0.82213 0.81714 0.82565
1 5 2000 1.46583 1.43961 1.52399
1 5 2500 2.28179 2.23877 2.33725
1 5 3000 3.25969 3.22792 3.31430
1 5 3500 4.40113 4.34763 4.47549
1 5 4000 5.81969 5.77652 5.92862
1 5 4500 7.32599 7.16071 7.62689
1 5 5000 9.38206 8.91221 9.80008];
% MATLAB R2007b의 측정 결과
data02=[
2 1 100 0.00021 0.00016 0.00027
2 1 200 0.00081 0.00075 0.00092
2 1 400 0.00725 0.00558 0.00943
2 1 600 0.01737 0.01550 0.01909
2 1 800 0.03563 0.03304 0.03692
2 1 1000 0.06679 0.06561 0.06792
2 1 1500 0.21936 0.21639 0.22419
2 1 2000 0.50645 0.50120 0.51059
2 1 2500 0.96557 0.95803 0.97042
2 1 3000 1.63351 1.62234 1.64124
2 1 3500 2.55805 2.54849 2.57340
2 1 4000 3.76943 3.75093 3.78148
2 2 100 0.00190 0.00020 0.00796
2 2 200 0.00191 0.00145 0.00242
2 2 400 0.01235 0.01109 0.01380
2 2 600 0.03692 0.03560 0.03789
2 2 800 0.08474 0.08313 0.08558
2 2 1000 0.16265 0.16159 0.16379
2 2 1500 0.59976 0.52985 0.63757
2 2 2000 1.37499 1.32621 1.43914
2 2 2500 2.73006 2.64790 2.81836
2 2 3000 4.24834 4.15515 4.53684
2 2 3500 6.66432 6.59504 6.77264
2 2 4000 9.84562 9.82265 9.88438
2 3 100 0.00649 0.00039 0.03086
2 3 200 0.00287 0.00238 0.00385
2 3 400 0.01665 0.01475 0.01827
2 3 600 0.04610 0.04334 0.04745
2 3 800 0.10424 0.09864 0.10840
2 3 1000 0.19463 0.19100 0.19821
2 3 1500 0.63645 0.63124 0.64269
2 3 2000 1.47813 1.47590 1.48018
2 3 2500 2.90117 2.85418 3.04439
2 3 3000 4.90081 4.88524 4.91227
2 3 3500 7.70092 7.68362 7.72392
2 3 4000 11.41932 11.39077 11.44221
2 4 100 0.01035 0.00381 0.03483
2 4 200 0.02477 0.02341 0.02847
2 4 400 0.11796 0.11756 0.11858
2 4 600 0.38650 0.38588 0.38752
2 4 800 0.68896 0.67834 0.70601
2 4 1000 1.11384 1.10799 1.12115
2 4 1500 3.11351 3.10732 3.13447
2 4 2000 6.76006 6.73526 6.77717
2 4 2500 12.74787 12.69403 12.92670
2 4 3000 20.21341 20.13866 20.28293
2 4 3500 30.33170 30.24185 30.38879
2 5 100 0.08335 0.04799 0.11860
2 5 200 0.11303 0.09013 0.17929
2 5 400 0.12802 0.11861 0.13658
2 5 600 0.17055 0.14985 0.18171
2 5 800 0.22761 0.19060 0.28158
2 5 1000 0.29125 0.27005 0.30682
2 5 1500 0.52285 0.49355 0.54245
2 5 2000 0.84889 0.83426 0.87938
2 5 2500 1.26317 1.22916 1.31744
2 5 3000 1.74134 1.72806 1.75393
2 5 3500 2.34496 2.31857 2.36714
2 5 4000 3.03385 3.01381 3.05601
2 5 4500 3.84646 3.79442 3.96145
2 5 5000 4.73073 4.65457 4.78454];
% MATLAB ver7.1의 측정 결과
data03=[
3 1 100 0.00127 0.00121 0.00141
3 1 200 0.00643 0.00616 0.00719
3 1 400 0.04904 0.04460 0.06494
3 1 600 0.12576 0.12271 0.12849
3 1 800 0.25747 0.25283 0.26485
3 1 1000 0.47301 0.46722 0.48090
3 1 1500 1.46980 1.42981 1.53355
3 1 2000 3.20180 3.16059 3.23868
3 1 2500 5.95840 5.88513 6.02364
3 1 3000 9.73500 9.67580 9.79549
3 1 3500 17.47936 17.22252 17.68559
3 1 4000 22.15679 21.25188 24.53420
3 2 100 0.09726 0.00108 0.48192
3 2 200 0.01445 0.00691 0.04423
3 2 400 0.07857 0.04869 0.09058
3 2 600 0.18564 0.15302 0.22108
3 2 800 0.37529 0.35730 0.38196
3 2 1000 0.66245 0.64896 0.68863
3 2 1500 2.15878 2.08352 2.25796
3 2 2000 4.88904 4.83850 4.94647
3 2 2500 9.76765 9.64881 9.87365
3 2 3000 16.92031 16.30056 17.70760
3 2 3500 29.39530 27.54045 32.75164
3 2 4000 47.33367 46.02548 48.61029
3 3 100 0.21919 0.00286 1.08436
3 3 200 0.20068 0.01369 0.93799
3 3 400 0.28501 0.13389 0.78561
3 3 600 0.36959 0.33940 0.42750
3 3 800 0.73782 0.71540 0.75283
3 3 1000 1.31694 1.28087 1.37239
3 3 1500 3.92831 3.85538 4.06811
3 3 2000 8.72406 8.40220 9.17784
3 3 2500 15.95907 15.91925 16.00671
3 3 3000 26.45950 26.42847 26.52666
3 3 3500 41.50427 41.40494 41.69957
3 3 4000 59.58553 59.39745 59.94225
3 4 100 0.06946 0.01901 0.25213
3 4 200 0.16241 0.12322 0.19546
3 4 400 1.32765 1.29709 1.34607
3 4 600 4.61600 4.59640 4.64813
3 4 800 10.68325 10.61664 10.75417
3 4 1000 20.35686 20.31969 20.42164
3 4 1500 73.34735 70.19733 76.82302
3 4 2000 166.99092 166.53052 167.43886
3 4 2500 407.40939 360.27411 420.39288
3 4 3000 721.54401 720.45538 722.05789
3 4 3500 1418.72562 1407.31936 1439.20624
3 5 100 1.06960 0.44859 2.34288
3 5 200 0.86968 0.55586 1.20123
3 5 400 1.17377 0.87546 1.88831
3 5 600 1.23008 1.18047 1.31700
3 5 800 1.68130 1.62462 1.76356
3 5 1000 2.26599 2.15029 2.45652
3 5 1500 4.16328 4.12798 4.20845
3 5 2000 6.91324 6.80712 6.98531
3 5 2500 10.28977 10.19799 10.39823
3 5 3000 14.76414 14.70922 14.86422
3 5 3500 36.66370 21.48734 51.33949];
% MATLAB ver5.3의 측정 결과
data04=[
4 1 100 0.00200 0.00000 0.01000
4 1 200 0.01000 0.01000 0.01000
4 1 400 0.40260 0.39000 0.41100
4 1 600 1.45200 1.40200 1.48200
4 1 800 3.70340 3.55500 3.79600
4 1 1000 6.91800 6.88000 6.97000
4 1 1500 23.64820 23.26400 24.29500
4 1 2000 54.83040 54.60800 55.03900
4 1 2500 107.97120 105.55200 116.42700
4 1 3000 212.24080 184.10500 269.91800
4 1 3500 289.54240 287.56300 291.86000
4 1 4000 429.14680 427.20400 432.72200
4 1 4500 619.80320 609.27600 626.07000
4 1 5000 892.76560 848.74000 1052.77400
4 2 100 0.00800 0.00000 0.01000
4 2 200 0.02000 0.02000 0.02000
4 2 400 0.74540 0.74100 0.76100
4 2 600 2.38520 2.36300 2.43300
4 2 800 5.87440 5.83800 5.91800
4 2 1000 10.73340 10.65500 10.79500
4 2 1500 34.69000 34.63000 34.74000
4 2 2000 80.72420 80.63600 80.83700
4 2 2500 157.97300 157.85700 158.22700
4 2 3000 270.51480 270.32800 270.81000
4 2 3500 427.68500 424.63000 434.55500
4 2 4000 659.19580 647.12000 677.38400
4 2 4500 906.63760 905.34200 909.18700
4 3 100 0.01200 0.00000 0.03000
4 3 200 0.03400 0.03000 0.04000
4 3 400 0.76520 0.75100 0.78100
4 3 600 3.31480 3.25500 3.42500
4 3 800 7.89300 7.78100 7.99100
4 3 1000 16.32760 15.76300 17.17400
4 3 1500 52.63580 51.49400 53.75800
4 3 2000 128.40840 122.53600 134.69300
4 3 2500 239.24800 238.04200 240.15500
4 3 3000 406.95520 406.13400 407.90600
4 3 3500 655.38040 645.58900 677.36400
4 3 4000 968.09220 950.82800 982.79300
4 3 4500 1387.02240 1371.95300 1401.71500
4 3 5000 1952.38780 1867.45500 2097.83700
4 4 100 0.04400 0.03000 0.07000
4 4 200 0.25040 0.25000 0.25100
4 4 400 3.22440 3.17500 3.26500
4 4 600 13.08700 12.91900 13.17900
4 4 800 32.50880 32.10600 33.15800
4 4 1000 64.41860 62.57000 69.97100
4 4 1500 227.06860 219.56600 239.10400
4 4 2000 537.15420 526.91700 552.50400
4 4 2500 1460.32360 1438.17800 1493.33700
4 4 3000 2308.87600 2297.12300 2333.61600
4 5 100 0.63500 0.53100 0.70100
4 5 200 0.64280 0.61100 0.69100
4 5 400 0.94140 0.82200 1.03100
4 5 600 1.40000 1.32200 1.50200
4 5 800 1.93060 1.89300 1.99300
4 5 1000 2.65980 2.60300 2.78400
4 5 1500 5.01920 4.97700 5.09700
4 5 2000 8.12000 8.04200 8.20200
4 5 2500 12.34780 12.20700 12.68800
4 5 3000 17.82580 17.60500 18.40700
4 5 3500 24.31860 24.08400 24.71500];
DD={data01,data02,data03,data04};
for nc=[1:5] % 각 명령에 대해 반복합니다.
if nc==1||nc==3||nc==5
% 그래프 용지 준비
[hax,hsp,h_number] = make_axes_tidily ...
('A4','land',[2 1],[250 75],[30 24 30 10]);
delete(h_number); % 불필요한 주석을 삭제합니다.
axes(hsp(1))
if nc==1||nc==3
text(0,10,'MATLAB의 처리 능력 개선(행렬 크기와 처리 시간)','FontSize',16, ...
'HorizontalAlign','center')
else
text(0,10,'MATLAB의 처리 능력 개선(분할 수와 처리 시간)','FontSize',16, ...
'HorizontalAlign','center')
end
if nc==1
text(-140,10,'그림 3','FontSize',20)
elseif nc==3
text(-140,10,'그림 4','FontSize',20)
elseif nc==5
text(-140,10,'그림 5','FontSize',20)
end
axes(hax(1))
ax=gca;
lincol=ax.ColorOrder; % 표준 선 색상(7가지)을 가져옵니다.
end
for nv=[1:4] % MATLAB의 각 버전에 대해 반복합니다.
D=DD{nv};
data=D(D(:,2)==nc,:);
data(1,:)=[]; % 100×100은 오차가 너무 크므로 삭제합니다.
col=lincol(nv,:);
if nc==1||nc==2
hf=hax(nc);
elseif nc==3||nc==4
hf=hax(nc-2);
else
hf=hax(nc-4);
end
[hl(nv)]=plot_data(data,col,hf); % 선 그래프 작성 (로컬 함수 호출)
end
xlim([0.0001 10000])
ylim([80 6000])
grid on
if nc==5
ylabel('분할 수 (n×n의 n)')
else
ylabel('행렬 크기 (n×n의 n)')
end
aa=gca;
aa.XAxis.FontSize=9.5;
aa.YAxis.FontSize=9.5;
aa.GridColor='k';
aa.GridAlpha=1;
aa.MinorGridColor='k';
aa.MinorGridAlpha=0.3;
aa.MinorGridLineStyle='-';
aa.LabelFontSizeMultiplier=1.3;
legend(hl,'MATLAB R2019a','MATLAB R2007b', ...
'MATLAB ver7.1','MATLAB ver5.3','Location','southeast')
if nc==1||nc==3
xticklabels('')
else
xlabel('처리 시간 [초]')
end
switch nc
case 1
text(1.5e-4,3.5e3,'행렬식','FontSize',16);
case 2
text(1.5e-4,3.5e3,'행렬 곱','FontSize',16);
case 3
text(1.5e-4,3.5e3,'역행렬','FontSize',16);
case 4
text(1.5e-4,3.5e3,'고유값','FontSize',16);
case 5
text(1.5e-4,3.5e3,'등고선 (8단계)','FontSize',16);
end
if nc==5
axes(hax(2));
axis off;
end
end
% =================================================
function [hl]=plot_data(data,col,hf)
nn=data(:,3); % 크기 (열 벡터)
av=data(:,4); % 평균 시간
mn=data(:,5); % 최단 시간
mx=data(:,6); % 최장 시간
axes(hf);
% 최단 시간과 최장 시간 그래프
loglog(mn,nn,'.-','Color',col,'LineWidth',0.5);
hold on
loglog(mx,nn,'.-','Color',col,'LineWidth',0.5);
% 최단 시간과 최장 시간으로 둘러싸인 영역을 투명하게 채움
fill([mn;flipud(mx)],[nn;flipud(nn)],col,'FaceAlpha',0.3,'EdgeColor',col);
% 평균 시간 그래프
hl=loglog(av,nn,'o-','Color',col,'LineWidth',2);
end
5.4 적절한 K 값의 그래프
최종 측정 값이 명시되어 있으므로, 안심을 위해 게시합니다.
% testMatrix05.m
% n×n 크기의 대형 행렬 A=rand(n)/K를 생성할 때,
% 행렬 크기 n과 다음의 K 값과의 관계를 그래프로 나타냅니다.
% 데이터는 다음 명령을 명령창에서 입력하고 K와 n 값을 변경하면서
% 인내심을 가지고 얻은 결과를 그대로 사용합니다.
% K=10; n=3000; disp(datestr(now,'dd-mmm-yyyy HH:MM:SS')),...
% pause(0.5); A=rand(n)/K; disp(det(A))
%
% 최적 K 값 Kbest : |A| 값이 대략적으로 e+00 순서가 되는 K 값
% 허용 최소 K 값 Kmin : |A| 값이 절대로 ±Inf가 되지 않는 K 값의 하한
% 허용 최대 K 값 Kmax : |A| 값이 절대로 0 (underflow)이 되지 않는 K 값의 상한
clear all
close all
% 측정 결과 데이터 (귀중하고 중요합니다. 데이터 수집에 상당한 시간이 소요되었습니다.)
% A=rand(n)/K로 설정한 경우, 최적 K(Kbest) 및
% 하한과 상한 K(Kmin, Kmax ... MATLAB R2019a 및 다른 버전의 Kmin5, Kmax5)입니다.
n = [100 200 300 400 500 700 1000 1500 2000 3000 4000 5000];
Kbest = [1.78 2.49 3.04 3.51 3.94 4.64 5.55 6.79 7.83 9.59 11.08 NaN];
Kmin = [0.00153 0.0733 0.290 0.602 0.958 1.692 2.74 4.24 5.51 7.59 9.29 NaN];
Kmax = [3039 102 36.1 22.4 17.3 13.41 11.65 11.15 11.51 11.54 11.84 NaN];
Kmin5 = [NaN NaN NaN NaN NaN NaN 2.74 4.24 5.51 7.59 9.29 10.76];
Kmax5 = [NaN NaN NaN NaN NaN NaN 11.65 11.15 11.34 12.27 13.33 14.36];
figure(1)
h1 = loglog(n, Kbest, 'o', 'LineWidth', 2);
hold on
grid on
xlim([50 12000])
ylim([0.9 15])
h2 = loglog([1 10000],[0.1 10]*1.75,'LineWidth',2);
h3=loglog(n,Kmin,'o-','LineWidth',1);
h4=loglog(n,Kmax,'o-','LineWidth',1);
h5=loglog(n,Kmin5,'.-','LineWidth',1,'MarkerSize',14);
h6=loglog(n,Kmax5,'.-','LineWidth',1,'MarkerSize',14);
aa=gca;
aa.GridColor='k';
aa.GridAlpha=1;
aa.MinorGridColor='k';
aa.MinorGridAlpha=0.3;
aa.MinorGridLineStyle='-';
text(32, 15.5, 'Figure 1', 'FontSize', 20);
text(60, 10^0.95, 'Kbest .... |A| 값의 지수부가 대략적으로 e+00이 되는 K');
text(60, 10^0.90, 'Kmin .... |A| 값이 절대로 ±Inf가 되지 않는 K');
text(60, 10^0.85, 'Kmax ... |A| 값이 0 (underflow)이 되지 않는 K');
title([' 난수 행렬 A=rand(n)/K에 대한' ...
' |A|을 매개변수로 한 n과 K의 관계'], 'FontSize', 11);
xlabel('행렬 크기 n (정방 행렬의 한 변)');
ylabel('K');
legend([h1 h2 h3 h4 h5 h6], ...
{'Kbest' 'K=0.175*sqrt(n)' 'Kmin(R2019a)' 'Kmax(R2019a)'...
'Kmin(ver5.3)' 'Kmax(ver5.3)'}, 'Location', 'southeast');