VConcat 여러 행렬을 함께루프에서 행렬을 연결하면 루프 반복으로 인해 속도가 느려집니다.
예를 들어 다음 의사코드는 다음과 같습니다.
OutputM = [];
for( i=1, i<=N, i++,
// do some calculations, generate a matrix of results, call it, ThisM
OutputM |/ = ThisM
);
위의 작업을 수행하면 N이 증가함에 따라 VConcat 선은 반복할 때마다 점점 더 느려집니다.
각 반복에서 열의 개수는 같지만 행의 개수는 가변적인 행렬이 생성됩니다.
이렇게 하면 훨씬 더 빨라집니다.
OutputList = {}; // will be a list of matrices
for( i=1, i<=N, i++,
// do some calculations, generate a matrix of results, call it, ThisM
insertinto(OutputList, ThisM)
);
이제 우리는 생성한 행렬 목록을 연결하고 싶습니다.
문제는 어떻게?
//This doesn't work:
VConcat(OutputMList);
// Neither does this :
VConat(Eval List(OutputMList);
// Nor this:
VConcat(Eval list(Eval(OutputMList);
// I know I can concat multiple matrices, for example this works:
VConat(OutputMList[1],OutputMList[2], OutputMList[3]);
// But the desire is to generalize this
자동화 및 스크립팅Re: VConcat 여러 행렬을 함께이 아이디어를 확인할 시간은 없지만, 목록을 연결한 다음 최종 목록을 행렬로 변환하는 것이 더 빠를 수도 있습니다.
Re: VConcat 여러 행렬을 함께여기에는 행렬에 관한 몇 가지 팁이 포함될 수 있습니다. 스크립팅 가이드 > 효율적인 스크립트 > 행렬 사용
Re: VConcat 여러 행렬을 함께이게 나한테는 빨리 효과가 있는 것 같아
OutputList = {}; // will be a list of matrices
n=50;
for( i=1, i<=N, i++,
// do some calculations, generate a matrix of results, call it, ThisM
ThisM = [1,2,3];
insertinto(OutputList, ThisM)
);
OutputM = [];
for each({l},OutputList,
OutputM = OutputM |/ matrix(l);
);Re: VConcat 여러 행렬을 함께50개 이상을 연결하는 경우 루프를 사용하여 한 번에 하나씩 연결하는 것은 바람직하지 않을 수 있습니다. 연결할 mat 목록이 이미 있는 경우, 다음과 같이 목록을 vconcat 함수로 변환할 수 있습니다.
Substitute Into( OutputList, {}, Expr( vconcat ) ); // convert {a,b,c} -> vconcat(a,b,c)
result2 = Eval( OutputList ); // evaluate the expression
평가는 루프보다 10배 더 빠를 수 있습니다.

그래프를 만드는 JSL:
dt = New Table( "timecat", New Column( "nmats" ), New Column( "timeloop" ), New Column( "timeeval" ) );
dt << Graph Builder( Size( 534, 456 ), Show Control Panel( 0 ),
Variables( X( :nmats ), Y( :timeloop ), Y( :timeeval, Position( 1 ) ) ),
Elements( Points( X, Y( 1 ), Y( 2 ), Legend( 3 ) ) ),
SendToReport( Dispatch( {}, "timeloop", ScaleBox,
{Scale( "Log" ), Format( "Engineering SI", 9, 0 ), Min( 10 ), Max( 1e7 ), Inc( 1 ), Minor Ticks( 1 ),
Add Ref Line( 1e5, "Solid", "Black", "1/10 second", 1 ), Add Ref Line( 1e6, "Solid", "Black", "one second", 1 ),
Label Row( Show Minor Labels( 0 ) )} ),
Dispatch( {}, "graph title", TextEditBox, {Set Text( "smaller is better" )} ),
Dispatch( {}, "X title", TextEditBox, {Set Text( "number of vconcats" )} ),
Dispatch( {}, "Y title", TextEditBox, {Set Text( "microseconds" )} )
)
);
For( N = 1, N < 550, N = Ceiling( n * 1.2 ), // build a bunch of test sets of bigger and bigger sizes
OutputList = {}; // will be a list of matrices
For( i = 1, i <= N + 1, i++,
// do some calculations, generate a matrix of results, call it, ThisM
ThisM = J( i, 30, i ); // rows, cols, initial value.
Insert Into( OutputList, ThisM );
);
// loop is slower ... blue in graph
start = HP Time();
result1 = OutputList[1];
For( i = 2, i <= N Items( OutputList ), i += 1,
result1 |/= OutputList[i]; // this is the vconcat into operator
);
t1 = HP Time() - start;
// eval is faster ... red in graph
start = HP Time();
Substitute Into( OutputList, {}, Expr( vconcat ) ); // convert {a,b,c} -> vconcat(a,b,c)
result2 = Eval( OutputList ); // evaluate the expression
t2 = HP Time() - start;
// capture the timings
dt << addrows( 1 );
dt:nmats[N Rows( dt )] = N;
dt:timeloop[N Rows( dt )] = t1;
dt:timeeval[N Rows( dt )] = t2;
If( !All( result1 == result2 ),
Throw( "bug?" ) // they should be identical
);
Wait( .1 ); // watch the graph grow
);
Re: VConcat 여러 행렬을 함께고맙습니다! 제가 원하던 "마법의 소스"였어요.
숫자가 클수록 루프 반복이 느려진다는 데 동의합니다. 이를 잘 보여주는 사례입니다.
'Substitute Into()' 구문은 내가 놓친 것입니다.
Re: VConcat 여러 행렬을 함께O(N) 동작을 확인하기 위해 그래프를 수정하고, O(N) 동작을 달성하는 jsl 루프를 추가했습니다. 빨간색, 초록색, 파란색 곡선은 연결된 행당 시간을 측정합니다. 빨간색과 초록색 곡선은 행당 약 0.3µs로 안정되지만, 파란색 곡선은 더 큰 문제에 대해 행당 점점 더 느려지고 있습니다. 파란색 루프가 결과에 추가된 각 행렬에 대해 이전에 복사된 모든 데이터를 다시 복사하고 행렬을 재할당하기 때문입니다. 마지막 파란색 점은 180µs * 380만 행, 즉 11분입니다. 빨간색과 초록색 점은 약 200배 더 빠릅니다.

dt = New Table( "timecat", New Column( "nmats" ), New Column( "loop" ), New Column( "eval" ), New Column( "copy" ) );
dt << Graph Builder( Size( 1000, 500 ), Show Control Panel( 0 ), Legend Position( "Inside Left" ),
Variables( X( :nmats ), Y( :loop ), Y( :eval, Position( 1 ) ), Y( :copy, Position( 1 ) ) ),
Elements( Points( X, Y( 1 ), Y( 2 ), Y( 3 ), Legend( 3 ) ) ),
SendToReport( Dispatch( {}, "loop", ScaleBox,
{Scale( "Log" ), Format( "Best", 6 ), Min( 0.1 ), Max( 100 ), Inc( 1 ), Minor Ticks( 1 ), Add Ref Line( 0.2, "Solid", "Black", ".2", 1 ),
Add Ref Line( 0.4, "Solid", "Black", ".4", 1 ), Label Row( Show Minor Labels( 0 ) )} ),
Dispatch( {}, "graph title", TextEditBox, {Set Text( "smaller is better" )} ),
Dispatch( {}, "X title", TextEditBox, {Set Text( "number of concats" )} ),
Dispatch( {}, "Y title", TextEditBox, {Set Text( "microseconds / row" )} ) ) );
For( N = 1, N < 3000, N = Ceiling( n * 1.2 ), // build a bunch of test sets of bigger and bigger sizes
result1 = result2 = result3 = .; // clear previous run memory, if any
OutputList = {}; // will be a list of matrices
For( i = 1, i <= N + 1, i++,
// do some calculations, generate a matrix of results, call it, ThisM
ThisM = J( i, 30, i ); // rows, cols, initial value. 30 makes this demo run in a reasonable time.
Insert Into( OutputList, ThisM );
);
// copy... fastest, green in graph, O(N) behavior. Use the red eval below because it is simpler?
start = HP Time();
// find total rows and pre-allocate
nr = 0;
nc = N Cols( OutputList[1] );
For( i = 1, i <= N Items( OutputList ), i += 1,
nr += N Rows( OutputList[i] );
If( nc != N Cols( OutputList[i] ),
Throw( "bad cols" )
);
);
result3 = J( nr, nc, . ); // allocate the result, exactly one time
nr = 0;
For( i = 1, i <= N Items( OutputList ), i += 1,
result3[nr + 1 :: nr + N Rows( OutputList[i] ), 0] = OutputList[i]; // copy pieces into the pre-allocated result
nr += N Rows( OutputList[i] ); // position the next piece after this one
);
t3 = HP Time() - start;
// loop is slower ... blue in graph. This exhibits terrible O(N^2) behavior--reallocates the result bigger and bigger
start = HP Time();
result1 = OutputList[1];
For( i = 2, i <= N Items( OutputList ), i += 1,
result1 |/= OutputList[i]; // this is the vconcat into operator. copies all the previous data into a bigger mat, each time.
);
t1 = HP Time() - start;
// eval is faster ... red in graph ... last, because OutputList is modified. Easier than the green copy and same O(N) result.
start = HP Time();
Substitute Into( OutputList, {}, Expr( vconcat ) ); // convert {a,b,c} -> vconcat(a,b,c)
result2 = Eval( OutputList ); // evaluate the expression
t2 = HP Time() - start;
// capture the timings
dt << addrows( 1 );
dt:nmats[N Rows( dt )] = N;
dt:loop[N Rows( dt )] = t1 / N Rows( result1 );
dt:eval[N Rows( dt )] = t2 / N Rows( result2 );
dt:copy[N Rows( dt )] = t3 / N Rows( result3 );
If( !All( result1 == result2 ) | !All( result1 == result3 ) | !(N Rows( result1 ) == N Rows( result2 ) == N Rows( result3 )),
Throw( "bug?" ) // they should be identical
);
Wait( .1 ); // watch the graph grow
);