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
自動化和腳本回覆:VConcat 將多個矩陣連接在一起我沒有時間去檢查這個想法,但連接列表然後將最終列表轉換為矩陣可能會更快。
回覆:VConcat 將多個矩陣連接在一起這可能包含一些關於矩陣的提示, 腳本指南>高效腳本>使用矩陣
回覆: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);
);回覆:VConcat 將多個矩陣連接在一起如果要連接 50 個或更多,您可能不想使用循環一次連接一個。如果您已經有要連接的墊子列表,則可以將該列表轉換為 vconcat 函數,如下所示:
Substitute Into( OutputList, {}, Expr( vconcat ) ); // convert {a,b,c} -> vconcat(a,b,c)
result2 = Eval( OutputList ); // evaluate the expression
eval 比循環快 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
);
回覆:VConcat 將多個矩陣連接在一起謝謝 !這就是我需要的「神奇醬汁」。
同意循環迭代對於較大的數字會減慢速度,這是一個很好的證明。
我一直缺少的是「Substitute Into()」語法
回覆:VConcat 將多個矩陣連接在一起我重新製作了圖表以查看 O(N) 行為,並添加了同樣實作 O(N) 行為的 jsl 迴圈。紅色、綠色和藍色曲線現在測量每個連接行的時間。紅色和綠色曲線穩定在每行 0.3µs 左右,但對於越來越大的問題,藍色曲線每行複製的速度越來越慢,因為藍色循環為添加到結果中的每個墊子重新複製所有先前複製的數據(並重新分配矩陣)。最後一個藍點是 180µs * 3.8M 行,或 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
);