20년간 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');