2
\$\begingroup\$

I am looking a good way to fill up the elements of a lower triangular matrix from a list.

I currently have this:

PadRight[#, s] & /@ 
 Prepend[Take[elems, # + {1, 0}] & /@ 
   Partition[Accumulate[Range[0, s - 1]], 2, 1], {}]

where elems is the elements-list and s is its length.

Perhaps the best way is preallocation plus a clear, procedural Do-loop. What do you think?

You can test the above with:

s = 5
elems = Range[s(s-1)/2]
\$\endgroup\$
  • \$\begingroup\$ Lonely over here, isn't it? I have to remember to visit this site more often. The code doesn't appear to be working as I expect. Would you please include a full, directly executable example? \$\endgroup\$ – Mr.Wizard Oct 16 '11 at 11:13
  • \$\begingroup\$ @Mr.Wizard Lonely indeed, but the question was not really suitable for SO. I added sample values for s and elems. If you run the code with these and look at the MatrixForm of the result, you'll see what I am trying to get: a triangular matrix filled up with the elements from elems. \$\endgroup\$ – Szabolcs Oct 17 '11 at 14:32
  • \$\begingroup\$ I see now. What is your priority? That is, efficiency, transparent code, terse code, etc.? Honestly what you have looks OK to me just by eye, but clearly you are unhappy with it, so I wonder what you are after. \$\endgroup\$ – Mr.Wizard Oct 17 '11 at 14:47
  • \$\begingroup\$ @Mr.Wizard It looked a bit complicated to me. Could you tell what that piece of code is doing just by looking at it? (Without a lot of hard thinking.) There's the procedural alternative along the lines of Do[ matrix[[i,j]] = ... , {i, 1, s}, {j, 1, i-1}]. I was wondering if there's something easy to understand which is less procedural. Speed is not a priority, my matrices are smaller than 200 by 200. \$\endgroup\$ – Szabolcs Oct 17 '11 at 18:23
  • \$\begingroup\$ Let me think about that. I agree that the code is not particularly understandable. I think it may be hard to beat the procedural method for transparency. What you have now though is fast; it is related to my "Dynamic Partition" code, and I tried many forms before settling on that one. Your code can be made a little faster by using Part in place of Take but that is about all I can find speed wise. \$\endgroup\$ – Mr.Wizard Oct 17 '11 at 20:10
3
\$\begingroup\$

Here are a few methods for your consideration and feedback.


This one uses the core of my "Dynamic Partition" function. It is the fastest method I know for this problem. Also, perhaps refactoring the code like this makes it more intelligible.

dynP[l_, p_] := 
 MapThread[l[[# ;; #2]] &, {{0}~Join~Most@# + 1, #} &@Accumulate@p]

#~PadRight~s & /@ {{}} ~Join~ dynP[elems, Range[s-1]]

This one is slightly shorter, using a different way to construct the indices, but also slightly slower, and perhaps less transparent.

#~PadRight~s & /@ 
 Prepend[
   elems~Take~# & /@ 
     Array[{1 + # (# - 1)/2, # (# + 1)/2} &, s - 1],
   {}
 ]

This one is terse, but slow. Legibility is debatable.

SparseArray[Join @@ Table[{i, j}, {i, s}, {j, i - 1}] -> elems, s] // MatrixForm

Here is one I just came up with, and I am quite pleased with it. I think it may be more understandable than most of the ones above.

Take[FoldList[RotateLeft, elems, Range[0, s - 1]] ~LowerTriangularize~ -1, All, s + 1]
\$\endgroup\$
  • \$\begingroup\$ Thanks! I'm a bit slow these days ... I find the last one quite legible, but the "good" solution for me in this case is really to use a function like your Dynamic Partitions and just pass the lengths. \$\endgroup\$ – Szabolcs Oct 18 '11 at 18:54
  • \$\begingroup\$ @Szabolcs, please see the FoldList solution I just added. I like this one best so far, other than possibly the one leveraging dynamicPartition. \$\endgroup\$ – Mr.Wizard Oct 18 '11 at 20:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.