PDL::Threadingp - 클라우드에서의 온라인

이것은 Ubuntu Online, Fedora Online, Windows 온라인 에뮬레이터 또는 MAC OS 온라인 에뮬레이터와 같은 여러 무료 온라인 워크스테이션 중 하나를 사용하여 OnWorks 무료 호스팅 제공업체에서 실행할 수 있는 PDL::Threadingp 명령입니다.

프로그램:

이름


PDL::Threading - PDL의 스레딩 기능에 대한 튜토리얼

소개


PDL의 가장 강력한 기능 중 하나는 스레딩, 이는 매우 컴팩트하고
C 및 BASIC 사용자가 사용할 수 있는 여러 중첩 for 루프를 방지하여 매우 빠른 PDL 코드
익숙하다. 문제는 익숙해지는 데 시간이 좀 걸릴 수 있고, 신규 사용자가 그렇지 않을 수도 있다는 것입니다.
스레딩의 이점을 높이 평가합니다.

MATLAB과 같은 다른 벡터 기반 언어는 스레딩 기술의 하위 집합을 사용하지만
PDL은 모든 종류의 벡터 기반 응용 프로그램에 대해 완전히 일반화되어 빛을 발합니다.

술어: 피들


MATLAB은 일반적으로 벡터, 행렬, 배열을 나타냅니다. Perl에는 이미 배열이 있으며
"벡터" 및 "행렬"이라는 용어는 일반적으로 XNUMX차원 및 XNUMX차원 집합을 나타냅니다.
데이터. 객체를 설명할 적절한 용어가 없어서 PDL 개발자는 이 용어를 만들었습니다.
"피들" 데이터 유형에 이름을 지정합니다.

A 피들 N 차원 데이터 세트로 구성된 일련의 숫자로 구성됩니다. 피들
대규모 N차원 행렬의 효율적인 저장 및 빠른 계산을 제공합니다. 그들은
수치 작업에 매우 최적화되어 있습니다.

생각 IN 조건 OF 스레딩


이미 PDL을 사용해 본 적이 있다면, PDL을 사용하지 않고 스레딩을 사용했을 수도 있습니다.
그것을 깨닫는 것. PDL 셸을 시작합니다(터미널에 "perldl" 또는 "pdl2" 입력). 대부분의 예
이 튜토리얼에서는 PDL 쉘을 사용합니다. PDL::NiceSlice 및 PDL::AutoLoader가 다음과 같은지 확인하세요.
활성화되었습니다. 예를 들어:

% pdl2
perlDL 쉘 v1.352
...
ReadLines, NiceSlice, MultiLines 활성화
...
참고: AutoLoader가 활성화되지 않았습니다('PDL::AutoLoader' 사용을 권장함).

pdl>

이 예에서는 NiceSlice가 자동으로 활성화되었지만 AutoLoader는 활성화되지 않았습니다. 사용하려면
그런 다음 "PDL::AutoLoader 사용"을 입력하세요.

XNUMX차원부터 시작해보자 피들:

pdl> $a = 시퀀스(11,9)
pdl> p $a
[
[0 1 2 3 4 5 6 7 8 9 10]
[11 12 13 14 15 16 17 18 19 20 21]
[22 23 24 25 26 27 28 29 30 31 32]
[33 34 35 36 37 38 39 40 41 42 43]
[44 45 46 47 48 49 50 51 52 53 54]
[55 56 57 58 59 60 61 62 63 64 65]
[66 67 68 69 70 71 72 73 74 75 76]
[77 78 79 80 81 82 83 84 85 86 87]
[88 89 90 91 92 93 94 95 96 97 98]
]

"info" 메소드는 특정 항목에 대한 기본 정보를 제공합니다. 피들:

pdl> p $a->정보
PDL: 더블 D [11,9]

이는 $a가 11 x 9임을 알려줍니다. 피들 배정밀도 숫자로 구성됩니다. 만약 우리가
"nxm" 피들의 모든 요소에 3을 추가하고 싶었지만 기존 언어에서는 XNUMX를 사용합니다.
중첩된 for 루프:

# 의사 코드. 배열에 3을 추가하는 전통적인 방법입니다.
(x=0; x < n; x++) {
(y=0; y < m; y++) {
a(x,y) = a(x,y) + 3
}
}

주의 사항: 인덱스는 Perl, C 및 Java에서와 같이(MATLAB 및 IDL과는 달리) 0부터 시작합니다.

하지만 PDL을 사용하면 다음과 같이 작성할 수 있습니다.

pdl> $b = $a + 3
pdl> 피 $b
[
[3 4 5 6 7 8 9 10 11 12 13]
[14 15 16 17 18 19 20 21 22 23 24]
[25 26 27 28 29 30 31 32 33 34 35]
[36 37 38 39 40 41 42 43 44 45 46]
[47 48 49 50 51 52 53 54 55 56 57]
[58 59 60 61 62 63 64 65 66 67 68]
[69 70 71 72 73 74 75 76 77 78 79]
[80 81 82 83 84 85 86 87 88 89 90]
[91 92 93 94 95 96 97 98 99 100 101]
]

이것은 스레딩의 가장 간단한 예이며 모든 수치 소프트웨어에서 사용되는 것입니다.
도구는 그렇습니다. "+ 3" 연산은 XNUMX차원을 따라 자동으로 적용되었습니다. 이제 가정해보자
$a의 모든 행에서 한 줄을 빼고 싶습니다.

pdl> $line = 순서(11)
pdl> p $line
[0 1 2 3 4 5 6 7 8 9 10]
pdl> $c = $a - $line
pdl> p $c
[
[0 0 0 0 0 0 0 0 0 0 0]
[11 11 11 11 11 11 11 11 11 11 11]
[22 22 22 22 22 22 22 22 22 22 22]
[33 33 33 33 33 33 33 33 33 33 33]
[44 44 44 44 44 44 44 44 44 44 44]
[55 55 55 55 55 55 55 55 55 55 55]
[66 66 66 66 66 66 66 66 66 66 66]
[77 77 77 77 77 77 77 77 77 77 77]
[88 88 88 88 88 88 88 88 88 88 88]
]

여기서 주목해야 할 두 가지 사항: 첫째, $a의 값은 여전히 ​​동일합니다. 확인하려면 "p $a"를 시도해 보세요.
둘째, PDL은 $a의 각 행에서 $line을 자동으로 뺍니다. 왜 그랬나요? 하자
$a, $line 및 $c의 크기를 살펴보세요.

pdl> p $line->info => PDL: 더블 D [11]
pdl> p $a->info => PDL: 더블 D [11,9]
pdl> p $c->info => PDL: 더블 D [11,9]

따라서 $a와 $line은 모두 0차원에서 동일한 수의 요소를 갖습니다! 그렇다면 어떤 PDL입니까?
$a의 더 높은 차원을 스레드로 처리하고 동일한 작업을 9번 반복하여
$a의 모든 행. 이것은 실제 PDL 스레딩입니다.

$a의 첫 번째 줄에서만 $line을 빼고 싶다면 어떻게 해야 할까요? 당신은 그렇게 할 수 있습니다
라인을 명시적으로 지정:

pdl> $a(:,0) -= $line
pdl> p $a
[
[0 0 0 0 0 0 0 0 0 0 0]
[11 12 13 14 15 16 17 18 19 20 21]
[22 23 24 25 26 27 28 29 30 31 32]
[33 34 35 36 37 38 39 40 41 42 43]
[44 45 46 47 48 49 50 51 52 53 54]
[55 56 57 58 59 60 61 62 63 64 65]
[66 67 68 69 70 71 72 73 74 75 76]
[77 78 79 80 81 82 83 84 85 86 87]
[88 89 90 91 92 93 94 95 96 97 98]
]

piddle에서 하위 집합을 지정하는 방법에 대한 자세한 내용은 PDL::Indexing 및 PDL::NiceSlice를 참조하세요.

스레딩의 진정한 힘은 피들이 여러 개의 스레드를 가질 수 있다는 것을 깨달을 때 나옵니다.
치수! 4차원 피들을 만들어 봅시다:

pdl> $piddle_4D = 시퀀스(11,3,7,2)
pdl> $c = $piddle_4D - $line

이제 $c는 $piddle_4D와 동일한 차원의 피들입니다.

pdl> p $piddle_4D->info => PDL: 더블 D [11,3,7,2]
pdl> p $c->info => PDL: 더블 D [11,3,7,2]

이번에는 PDL이 자동으로 세 개의 더 높은 차원에 걸쳐 스레드되어 $line을 뺍니다.
모든 방법.

그러나 행(차원 0)에서 빼기를 원하지 않고 열에서 빼기를 원할 수도 있습니다.
(차원 1). $a의 각 열에서 숫자 열을 어떻게 빼나요?

pdl> $cols = 순서(9)
pdl> p $a->info => PDL: 더블 D [11,9]
pdl> p $cols->info => PDL: 더블 D [9]

당연히 "$a - $cols"만 입력할 수는 없습니다. 치수가 일치하지 않습니다:

pdl> p $a - $cols
PDL: PDL::Ops::minus(a,b,c): 매개변수 'b'
PDL: 일치하지 않는 암시적 스레드 차원 0: 11이어야 하고 9입니다.

대신 차원 1에서 빼기를 원한다고 PDL에 어떻게 알릴 수 있나요?

조작 치수


PDL 배열의 크기를 재배열할 수 있는 PDL 함수가 많이 있습니다. 그들은
대부분 PDL::Slices에서 다룹니다. 가장 일반적인 세 ​​가지는 다음과 같습니다.

xchg
mv
순서

방법 : "xchg"
"xchg" 방법 "교환" 한 덩어리의 두 차원:

pdl> $a = 시퀀스(6,7,8,9)
pdl> $a_xchg = $a->xchg(0,3)

pdl> p $a->info => PDL: 더블 D [6,7,8,9]
pdl> p $a_xchg->info => PDL: 더블 D [9,7,8,6]
| |
VV
(어두움 0) (어두움 3)

차원 0과 3은 다른 차원에 영향을 주지 않고 교환되었습니다.
또한 "xchg"는 $a를 변경하지 않는다는 점에 유의하세요. 원래 변수 $a는 그대로 유지됩니다.

방법 : "MV"
"mv" 방법 "이동" 한 차원은 수수께끼로 다른 차원을 다음과 같이 이동시킵니다.
필요한.

pdl> $a = 시퀀스(6,7,8,9) (어두운 0)
pdl> $a_mv = $a->mv(0,3) |
pdl> 뷔 _____
pdl> p $a->info => PDL: 더블 D [6,7,8,9]
pdl> p $a_mv->info => PDL: 더블 D [7,8,9,6]
----- |
V
(어두움 3)

차원 0이 위치 3으로 이동하면 다른 모든 차원도 변경되어야 합니다.
마찬가지로 옮겼습니다. 또한 "mv"는 $a를 변경하지 않는다는 점에 유의하세요. 원래 변수 $a는 그대로 유지됩니다.
손대지 않은.

방법 : "재 주문"
"재정렬" 방법은 "xchg" 및 "mv" 방법을 일반화한 것입니다. 그것 "재주문"
다음과 같은 방식으로 치수를 지정합니다.

pdl> $a = 시퀀스(6,7,8,9)
pdl> $a_reorder = $a->재주문(3,0,2,1)
pdl>
pdl> p $a->info => PDL: 더블 D [6,7,8,9]
pdl> p $a_reorder->info => PDL: 더블 D [9,6,8,7]
| | | |
VV 대 V
크기: 0 1 2 3

무슨 일이 일어났는지 주목하세요. "reorder(3,0,2,1)"를 작성할 때 PDL에 다음을 지시했습니다.

* 차원 3을 먼저 입력하세요.
* 다음에 차원 0을 입력합니다.
* 다음에 차원 2을 입력합니다.
* 다음에 차원 1을 입력합니다.

"재정렬" 방법을 사용하면 모든 차원이 섞입니다. "재주문"에 주목하세요
$a를 변경하지 않습니다. 원래 변수 $a는 그대로 유지됩니다.

알아냈어: 연결 VS 할당


연결
기본적으로 피들은 다음과 같습니다. 연결 함께 변경사항이 다시 적용되어 다음에 영향을 미치게 됩니다.
실물 as .

pdl> $a = 시퀀스(4,5)
pdl> $a_xchg = $a->xchg(1,0)

여기, $a_xchg is 지원 a 별도의 대상. 그것은 단지 $a를 보는 다른 방식일 뿐입니다. 어느
$a_xchg의 변경 사항은 $a에도 나타납니다.

pdl> p $a
[
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[16 17 18 19]
]
pdl> $a_xchg += 3
pdl> p $a
[
[ 3 4 5 6]
[ 7 8 9 10]
[11 12 13 14]
[15 16 17 18]
[19 20 21 22]
]

할당
때로는 연결이 원하는 동작이 아닐 수도 있습니다. 피들을 만들고 싶다면
독립적인 경우 "복사" 방법을 사용하십시오.

pdl> $a = 시퀀스(4,5)
pdl> $a_xchg = $a->복사->xchg(1,0)

이제 $a와 $a_xchg는 완전히 별개의 객체입니다.

pdl> p $a
[
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[16 17 18 19]
]
pdl> $a_xchg += 3
pdl> p $a
[
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[16 17 18 19]
]
pdl> $a_xchg
[
[ 3 7 11 15 19]
[ 4 8 12 16 20]
[ 5 9 13 17 21]
[ 6 10 14 18 22]
]

퍼팅 IT 공통 함께


이제 우리는 이 전체 논의의 동기가 된 문제를 해결할 준비가 되었습니다.

pdl> $a = 시퀀스(11,9)
pdl> $cols = 순서(9)
pdl>
pdl> p $a->info => PDL: 더블 D [11,9]
pdl> p $cols->info => PDL: 더블 D [9]

차원 1 대신 차원 0을 따라 $cols를 빼도록 PDL에 어떻게 지시합니까? 그만큼
가장 간단한 방법은 "xchg" 방법을 사용하고 PDL 연결에 의존하는 것입니다.

pdl> p $a
[
[0 1 2 3 4 5 6 7 8 9 10]
[11 12 13 14 15 16 17 18 19 20 21]
[22 23 24 25 26 27 28 29 30 31 32]
[33 34 35 36 37 38 39 40 41 42 43]
[44 45 46 47 48 49 50 51 52 53 54]
[55 56 57 58 59 60 61 62 63 64 65]
[66 67 68 69 70 71 72 73 74 75 76]
[77 78 79 80 81 82 83 84 85 86 87]
[88 89 90 91 92 93 94 95 96 97 98]
]
pdl> $a->xchg(1,0) -= $cols
pdl> p $a
[
[0 1 2 3 4 5 6 7 8 9 10]
[10 11 12 13 14 15 16 17 18 19 20]
[20 21 22 23 24 25 26 27 28 29 30]
[30 31 32 33 34 35 36 37 38 39 40]
[40 41 42 43 44 45 46 47 48 49 50]
[50 51 52 53 54 55 56 57 58 59 60]
[60 61 62 63 64 65 66 67 68 69 70]
[70 71 72 73 74 75 76 77 78 79 80]
[80 81 82 83 84 85 86 87 88 89 90]
]

일반 전략:
작업하려는 차원을 피들 차원의 시작 부분으로 이동하십시오.
목록. 그런 다음 더 높은 차원에 대해 PDL 스레드를 허용합니다.

예 : 콘웨이의 게임 OF 생명


좋아요, 이론은 충분해요. 좀 더 흥미로운 것을 해보자. 콘웨이의 게임
of 생활 PDL에서 PDL이 얼마나 강력한지 확인해보세요!

The 게임 of 생활 큰 XNUMX차원 그리드에서 실행되는 시뮬레이션입니다. 그리드의 각 셀
살아 있거나 죽었을 수 있습니다(1 또는 0으로 표시). 차세대 세포는
그리드는 그 안에 있는 살아있는 세포의 수에 따라 간단한 규칙으로 계산됩니다.
바로 이웃:

1) 빈 셀에 정확히 세 개의 이웃이 있으면 살아있는 셀이 생성됩니다.

2) 살아있는 세포의 이웃이 XNUMX개 미만이면 과잉 공급으로 인해 죽습니다.

3) 살아있는 세포에 4개 이상의 이웃이 있으면 기아로 죽습니다.

프로그래머는 XNUMX세대 셀만 결정합니다. 그 후,
시뮬레이션은 이러한 규칙에 따라 완전히 실행됩니다. 다음 세대를 계산하려면
2D 필드의 각 셀을 살펴보고(두 개의 루프 필요) 셀 수를 계산해야 합니다.
이 셀에 인접한 라이브 셀(또 다른 두 개의 루프 필요)을 채우고 다음 셀을 채웁니다.
세대 그리드.

고전 이행
Perl로 이 프로그램을 작성하는 고전적인 방법은 다음과 같습니다. 우리는 주소 지정에만 PDL을 사용합니다.
개별 세포.

#!/usr/빈/펄 -w
PDL 사용;
PDL::NiceSlice를 사용하십시오.

# 인생 게임을 위한 보드를 만들어 보세요.
내 $nx = 20;
내 $ny = 20;

# 현세대.
내 $a = XNUMX($nx, $ny);

# 다음 세대.
내 $n = XNUMX($nx, $ny);

# 간단한 글라이더를 넣어보세요.
$a(1:3,1:3) .= pdl ( [1,1,1],
[0,0,1],
[0,1,0] );

for (내 $i = 0; $i < 100; $i++) {
$n = XNUMX($nx, $ny);
$new_a = $a->복사;
for ($x = 0; $x < $nx; $x++) {
for ($y = 0; $y < $ny; $y++) {

# 각 셀에 대해 주변 이웃을 살펴보세요.
for ($dx = -1; $dx <= 1; $dx++) {
for ($dy = -1; $dy <= 1; $dy++) {
$px = $x + $dx;
$py = $y + $dy;

# 가장자리를 감싸주세요.
if ($px < 0) {$px = $nx-1};
if ($py < 0) {$py = $ny-1};
if ($px >= $nx) {$px = 0};
if ($py >= $ny) {$py = 0};

$n($x,$y) .= $n($x,$y) + $a($px,$py);
}
}
# 중앙 셀 자체는 세지 마세요.
$n($x,$y) -= $a($x,$y);

# 세포가 살아 있는지 죽었는지 알아보세요:
# n = 3이면 죽은 세포가 살아있습니다.
# n이 2나 3이 아니면 살아있는 세포는 죽는다
if ($a($x,$y) == 1) {
if ($n($x,$y) < 2) {$new_a($x,$y) .= 0};
if ($n($x,$y) > 3) {$new_a($x,$y) .= 0};
} 다른 {
if ($n($x,$y) == 3) {$new_a($x,$y) .= 1}
}
}
}

$a를 인쇄하세요;

$a = $new_a;
}

이것을 실행하면 작은 글라이더가 XNUMX의 그리드를 대각선으로 기어가는 것을 볼 수 있습니다.
내 컴퓨터에서는 초당 몇 세대를 인쇄합니다.

스레드 된 PDL 이행
PDL의 스레드 버전은 다음과 같습니다. PDL 코드 네 줄만 있으면 그 중 하나는 다음과 같습니다.
최신 세대를 인쇄해 보세요!

#!/usr/빈/펄 -w
PDL 사용;
PDL::NiceSlice를 사용하십시오.

내 $a = 20,20(XNUMX);

# 간단한 글라이더를 넣어보세요.
$a(1:3,1:3) .= pdl ( [1,1,1],
[0,0,1],
[0,1,0] );

내 $n;
for (내 $i = 0; $i < 100; $i++) {
# 셀당 이웃 수를 계산합니다.
$n = $a->range(ndcoords($a)-1,3,"주기적")->재주문(2,3,0,1);
$n = $n->sumover->sumover - $a;

# 다음 세대를 계산합니다.
$a = ((($n == 2) + ($n == 3))* $a) + (($n==3) * !$a);

$a를 인쇄하세요;
}

스레드 PDL 버전이 훨씬 빠릅니다.

클래식 => 32.79초.
스레드 => 0.41초.

설명
스레드 버전은 어떻게 작동하나요?

PDL 스레딩을 수행하는 데 도움이 되도록 설계된 많은 PDL 기능이 있습니다. 이에
예를 들어 주요 기능은 다음과 같습니다.

방법 : "범위"

가장 단순한 수준에서 "범위" 방법은 데이터의 일부를 선택하는 다른 방법입니다.
피들. "$a(2,3)" 표기법을 사용하는 대신 다른 표현을 사용합니다.

pdl> $a = 시퀀스(6,7)
pdl> p $a
[
[0 1 2 3 4 5]
[6 7 8 9 10 11]
[12 13 14 15 16]
[18 19 20 21 22]
[24 25 26 27 28]
[30 31 32 33 34]
[36 37 38 39 40]
]
pdl> p $a->범위( pdl [1,2] )
13
pdl> p $a(1,2)
[
[13]
]

이 시점에서 "범위" 방법은 일반 PDL 슬라이스와 매우 유사해 보입니다. 하지만
"범위" 방법이 더 일반적입니다. 예를 들어 한 번에 여러 구성요소를 선택할 수 있습니다.

pdl> $index = pdl [ [1,2],[2,3],[3,4],[4,5] ]
pdl> p $a->범위( $index )
[13 20 27 34]

추가적으로 "range"는 청크의 크기를 결정하는 두 번째 매개변수를 취합니다.
반환:

pdl> $size = 3
pdl> p $a->range( pdl([1,2]) , $size )
[
[13]
[19]
[25]
]

이를 사용하여 하나 이상의 3x3 상자를 선택할 수 있습니다.

마지막으로 "범위"는 "경계" 조건이라는 세 번째 매개변수를 사용할 수 있습니다. PDL에 알려줍니다.
요청한 크기 상자가 가장자리를 벗어나면 어떻게 해야 합니까? 우리는 가지 않을 것이다
모든 옵션에 걸쳐. "주기적" 옵션은 피들
"둘러싸기". 예를 들어:

pdl> p $a
[
[0 1 2 3 4 5]
[6 7 8 9 10 11]
[12 13 14 15 16]
[18 19 20 21 22]
[24 25 26 27 28]
[30 31 32 33 34]
[36 37 38 39 40]
]
pdl> $size = 3
pdl> p $a->range( pdl([4,2]) , $size , "주기적")
[
[16]
[22]
[28]
]
pdl> p $a->range( pdl([5,2]) , $size , "주기적")
[
[17]
[23]
[29]
]

상자가 피들 경계를 어떻게 감싸는지 확인하세요.

방법 : "ndcoords"

"ndcoords" 메소드는 열거된 목록을 반환하는 편리한 메소드입니다.
"범위" 방법과 함께 사용하기에 적합한 좌표입니다.

pdl> p $piddle = 시퀀스(3,3)
[
[0]
[3]
[6]
]
pdl> p ndcoords($piddle)
[
[
[0 0]
[1 0]
[2 0]
]
[
[0 1]
[1 1]
[2 1]
]
[
[0 2]
[1 2]
[2 2]
]
]

읽기가 조금 어려울 수 있습니다. 기본적으로 모든 좌표는
$piddle의 요소는 다음과 같이 제공됩니다.

(0,0) (1,0) (2,0)
(1,0) (1,1) (2,1)
(2,0) (2,1) (2,2)

결합 "범위" 그리고 "ndcoords"

정말 중요한 것은 "ndcoords"가 "범위"와 함께 작동하도록 설계되었다는 것입니다.
$size 매개변수를 사용하면 동일한 결과가 반환됩니다.

pdl> p $piddle
[
[0]
[3]
[6]
]
pdl> p $piddle->range( ndcoords($piddle) )
[
[0]
[3]
[6]
]

이것이 왜 유용할까요? 이제 우리는 전체에 대해 일련의 "상자"를 요청할 수 있기 때문입니다.
피들. 예를 들어 2x2 상자는 다음과 같습니다.

pdl> p $piddle->range( ndcoords($piddle) , 2 , "주기적" )

이 함수의 출력은 마지막 두 개의 "상자" 때문에 읽기 어렵습니다.
치수. 차원을 재배열하여 결과를 더 읽기 쉽게 만들 수 있습니다.

pdl> p $piddle->range( ndcoords($piddle) , 2 , "주기적" )->reorder(2,3,0,1)
[
[
[
[0 1]
[3 4]
]
[
[1 2]
[4 5]
]
...
]

여기에서 더 명확하게 알 수 있습니다.

[0 1]
[3 4]

$piddle의 (2) 요소로 시작하는 2x0,0 상자입니다.

아직 끝나지 않았습니다. 인생의 게임을 위해 우리는 $a의 3x3 상자를 원합니다:

pdl> p $a
[
[0 1 2 3 4 5]
[6 7 8 9 10 11]
[12 13 14 15 16]
[18 19 20 21 22]
[24 25 26 27 28]
[30 31 32 33 34]
[36 37 38 39 40]
]
pdl> p $a->range( ndcoords($a) , 3 , "주기적" )->reorder(2,3,0,1)
[
[
[
[0 1 2]
[6 7 8]
[12]
]
...
]

$a의 (3) 요소로 시작하는 3x0,0 상자임을 확인할 수 있습니다. 하지만 거기에는
하나의 문제입니다. 우리는 실제로 3x3 상자를 원합니다. 중심으로 (0,0)에. 그건 아니야
문제. "ndcoords($a)"의 모든 좌표에서 1을 빼면 됩니다. 기억하세요.
"주기적" 옵션은 모든 것을 감싸도록 처리합니다.

pdl> p $a->range( ndcoords($a) - 1 , 3 , "주기적" )->reorder(2,3,0,1)
[
[
[
[41]
[5 0 1]
[11]
]
[
[36]
[0 1 2]
[6 7 8]
]
...

이제 상자 중앙에 (3) 요소가 있는 3x0,0 상자가 표시됩니다.

방법 : "소모버"

"sumover" 방법은 첫 번째 차원만 추가합니다. 두 번 적용하면 이렇게 됩니다.
각 3x3 상자의 모든 요소를 ​​​​추가합니다.

pdl> $n = $a->range(ndcoords($a)-1,3,"주기적")->재주문(2,3,0,1)
pdl> 피 $n
[
[
[
[41]
[5 0 1]
[11]
]
[
[36]
[0 1 2]
[6 7 8]
]
...
pdl> p $n->sumover->sumover
[
[144 135 144 153 162]
[72 63 72 81 90 81]
[126 117 126 135 144]
[180 171 180 189 198]
[234 225 234 243 252]
[288 279 288 297 306]
[216 207 216 225 234]
]

계산기를 사용하여 144가 첫 번째 3x3 상자에 있는 모든 요소의 합인지 확인하세요.
135는 두 번째 3x3 상자에 있는 모든 요소의 합입니다.

계산 이웃

거의 다 왔어요!

3x3 상자의 모든 요소를 ​​더하는 것은 아주 우리가 원하는 것. 우리는 계산하고 싶지 않아요
센터박스. 다행히도 다음과 같이 쉽게 해결할 수 있습니다.

pdl> p $n->sumover->sumover - $a
[
[144 134 142 150 158]
[66 56 64 72 80 70]
[114 104 112 120 128]
[162 152 160 168 176]
[210 200 208 216 224]
[258 248 256 264 272]
[180 170 178 186 194]
]

Conway의 Game of Life에 적용하면 각각의 살아있는 이웃이 몇 명인지 알 수 있습니다.
셀에는 다음이 있습니다.

pdl> $a = 10,10(XNUMX)
pdl> $a(1:3,1:3) .= pdl ( [1,1,1],
..( > [0,0,1],
..( > [0,1,0] )
pdl> p $a
[
[0 0 0 0 0 0 0 0
[0 1 1 1 0 0 0 0
[0 0 0 1 0 0 0 0
[0 0 1 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
]
pdl> $n = $a->range(ndcoords($a)-1,3,"주기적")->재주문(2,3,0,1)
pdl> $n = $n->sumover->sumover - $a
pdl> 피 $n
[
[1 2 3 2 1 0 0 0
[1 1 3 2 2 0 0 0
[1 3 5 3 2 0 0 0
[0 1 1 2 1 0 0 0
[0 1 1 1 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
]

예를 들어, 셀 (0,0)에는 1개의 살아있는 이웃이 있고 셀 (2,2)에는 5개의 이웃이 있음을 알 수 있습니다.
살아있는 이웃.

계산 중 전에, 다음 것 세대

이 시점에서 변수 $n은 모든 셀에 대해 살아있는 이웃의 수를 갖습니다. 이제, 우리
다음 세대를 계산하기 위해 인생 게임의 규칙을 적용하십시오.

빈 셀에 정확히 세 개의 이웃이 있으면 살아있는 셀이 생성됩니다.
정확히 세 개의 이웃이 있는 셀 목록을 가져옵니다.

pdl> p ($n == 3)
[
[0 0 1 0 0 0 0 0
[0 0 1 0 0 0 0 0
[0 1 0 1 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
]

목록 가져오기 정확히 세 개의 이웃이 있는 셀:

pdl> p ($n == 3) * !$a

살아있는 세포의 이웃이 2개 미만이거나 3개보다 많으면 죽습니다.
정확히 2~3개의 이웃이 있는 셀 목록을 가져옵니다.

pdl> p (($n == 2) + ($n == 3))
[
[0 1 1 1 0 0 0 0
[0 0 1 1 1 0 0 0
[0 1 0 1 1 0 0 0
[0 0 0 1 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
]

목록 가져오기 생활 정확히 2~3개의 이웃이 있는 셀:

pdl> p (($n == 2) + ($n == 3)) * $a

이 모든 것을 종합하면 다음 세대는 다음과 같습니다.

pdl> $a = ((($n == 2) + ($n == 3)) * $a) + (($n == 3) * !$a)
pdl> p $a
[
[0 0 1 0 0 0 0 0
[0 0 1 1 0 0 0 0
[0 1 0 1 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
[0 0 0 0 0 0 0 0
]

보너스 특징 : 제도법!
PDL::Graphics::TriD가 설치되어 있으면 프로그램의 그래픽 버전을 만들 수 있습니다.
세 줄만 바꾸면 됩니다:

#!/usr/빈/펄
PDL 사용;
PDL::NiceSlice를 사용하십시오.
PDL::그래픽::TriD를 사용합니다.

내 $a = 20,20(XNUMX);

# 간단한 글라이더를 넣어보세요.
$a(1:3,1:3) .= pdl ( [1,1,1],
[0,0,1],
[0,1,0] );

내 $n;
for (내 $i = 0; $i < 100; $i++) {
# 셀당 이웃 수를 계산합니다.
$n = $a->range(ndcoords($a)-1,3,"주기적")->재주문(2,3,0,1);
$n = $n->sumover->sumover - $a;

# 다음 세대를 계산합니다.
$a = ((($n == 2) + ($n == 3))* $a) + (($n==3) * !$a);

# 표시하다.
nokeeptwiddling3d();
imgrgb [$a];
}

하지만 정말 흥미로운 것을 보고 싶다면 몇 가지를 더 변경해야 합니다.

1) 1과 0의 무작위 수집으로 시작합니다.

2) 그리드를 더 크게 만드십시오.

3) 게임이 더 잘 발전하는 것을 볼 수 있도록 작은 시간 제한을 추가합니다.

4) 프로그램이 필요한 만큼 오랫동안 실행될 수 있도록 while 루프를 사용하십시오.

#!/usr/빈/펄
PDL 사용;
PDL::NiceSlice를 사용하십시오.
PDL::그래픽::TriD를 사용합니다.
Time::HiRes qw(usleep) 사용;

내 $a = 무작위(100,100);
$a = ($a < 0.5);

내 $n;
동안 (1) {
# 셀당 이웃 수를 계산합니다.
$n = $a->range(ndcoords($a)-1,3,"주기적")->재주문(2,3,0,1);
$n = $n->sumover->sumover - $a;

# 다음 세대를 계산합니다.
$a = ((($n == 2) + ($n == 3))* $a) + (($n==3) * !$a);

# 표시하다.
nokeeptwiddling3d();
imgrgb [$a];

# 0.1초 동안 잔다.
잠자다(100000);
}

결론: 일반 전략


일반적인 전략은 다음과 같습니다. 무브 전에, 치수 의견을 듣고 싶습니다. 필요 운영 on 전에, 스타트 of your
피들의 치수 명부. 그때 하자 PDL 위에 전에, 더 높은 치수.

스레딩은 for 루프를 제거하고 코드를 더 효율적으로 만들 수 있는 강력한 도구입니다.
간결한. 이 튜토리얼이 왜 스레딩을 이해하는 것이 가치가 있는지 보여주었기를 바랍니다.
PDL에서.

저작권


저작권 2010 매튜 켄워시(kenworthy@strw.leidenuniv.nl) 그리고 다니엘 카레라
(dcarrera@gmail.com). 귀하는 동일한 조건에 따라 이 문서를 배포 및/또는 수정할 수 있습니다.
현재 Perl 라이센스로.

참조 : http://dev.perl.org/licenses/

onworks.net 서비스를 사용하여 PDL::Threadingp를 온라인으로 사용하세요.



최신 Linux 및 Windows 온라인 프로그램