I would like to extract the upper triangular part of a square matrix into a flat list. I am looking for fast ways to do this. I am primarily interested in solutions that are fast for non-packed arrays as well. For packed arrays, a compiled solution will always be very fast.
Here are three successively faster implementations to get the ball rolling.
takeUpper1[mat_?SquareMatrixQ] :=
Join @@ Table[mat[[i, j]], {i, Length[mat]}, {j, i + 1, Length[mat]}];
takeUpper2[mat_?SquareMatrixQ] :=
Extract[mat, Subsets[Range@Length[mat], {2}]]
takeUpper3[mat_?SquareMatrixQ] :=
Join @@ Pick[mat, UpperTriangularize[ConstantArray[1, Dimensions[mat]], 1], 1]
(* added later, also slower than takeUpper3 *)
takeUpper4[mat_?SquareMatrixQ] :=
Join @@ Table[mat[[i, i + 1 ;;]], {i, Length[mat]}]
Benchmarks:
mat = RandomReal[1, {1000, 1000}];
mat2 = Developer`FromPackedArray[mat];
Packed:
res1 = takeUpper1[mat]; // RepeatedTiming
(* {0.218, Null} *)
res2 = takeUpper2[mat]; // RepeatedTiming
(* {0.0840, Null} *)
res3 = takeUpper3[mat]; // RepeatedTiming
(* {0.017, Null} *)
res1 == res2 == res3
(* True *)
Non-packed:
res1 = takeUpper1[mat2]; // RepeatedTiming
(* {0.839, Null} *)
res2 = takeUpper2[mat2]; // RepeatedTiming
(* {0.0949, Null} *)
res3 = takeUpper3[mat2]; // RepeatedTiming
(* {0.018, Null} *)
res1 == res2 == res3
(* True *)
You are also welcome to suggest intuitive names for such a function. The final function will work also on non-square matrices and will have a second argument similar to that of UpperTriangularize
.
UpperTriangularMatrixToVector
. $\endgroup$