# Symmetric matrix from a vector

There is a function VectorToSymmetricMatrix that does the following:

StatisticsLibraryVectorToSymmetricMatrix[{1, 2, 3}, {5, 6, 7}, 3] // MatrixForm


$$\left( \begin{array}{ccc} 5 & 1 & 2 \\ 1 & 6 & 3 \\ 2 & 3 & 7 \\ \end{array} \right)$$

I find it quite inconvenient to use because my data is differently ordered:

v={5, 1, 6, 2, 3, 7}


I am searching for a simple way to convert this vector to a symmetric matrix shown above.

There are similar posts, however, I could not find one addressing my problem. Please, try to provide a solution as simple and pedagogical as possible. I prefer to use documented functions even if the solution is slower.

A test case could be:

v = RandomReal[{0, 1}, {100, 75 (75 + 1)/2}];
m = Table[UnpackUpTrg[vi], {vi, v}];


My current implementation is

ind[i_, j_] := If[i < j, i + j (j - 1)/2, j + i (i - 1)/2]
UnpackUpTrg[v_] := Module[{k},
k = 1/2 (-1 + Sqrt[1 + 8 Length[v]]);
Table[v[[ind[i, j]]], {i, k}, {j, k}]
]


but it is a bit slow and procedural.

• v1=v[[{2, 4, 5, 1, 3, 6}]] gives he Order you want. and StatisticsLibraryVectorToSymmetricMatrix[v1[[1 ;; 3]], v1[[4 ;; 6]], 3] creates the matrix. Jun 23, 2021 at 20:40
• @DanielHuber Yes, but this was just an example of how results should look like. But the intended use case is given below. Jun 23, 2021 at 20:42

toSymmetricMat = Transpose[LowerTriangularize[#, -1]] + # & @
PadRight[TakeList[#, Range[1/2 (-1 + Sqrt[1 + 8 Length[#]])]]] &;


Examples:

toSymmetricMat[{5, 1, 6, 2, 3, 7}] // MatrixForm // TeXForm


$$\left( \begin{array}{ccc} 5 & 1 & 2 \\ 1 & 6 & 3 \\ 2 & 3 & 7 \\ \end{array} \right)$$

toSymmetricMat[{5, 1, 6, 2, 4, 7, 3, 5, 6, 8}] // MatrixForm // TeXForm


$$\left( \begin{array}{cccc} 5 & 1 & 2 & 3 \\ 1 & 6 & 4 & 5 \\ 2 & 4 & 7 & 6 \\ 3 & 5 & 6 & 8 \\ \end{array} \right)$$

SeedRandom[1]
rvec = RandomInteger[10, 7 (7 + 1)/2];
toSymmetricMat[rvec] // MatrixForm // TeXForm


$$\left( \begin{array}{ccccccc} 1 & 4 & 7 & 8 & 1 & 1 & 0 \\ 4 & 0 & 0 & 6 & 8 & 3 & 2 \\ 7 & 0 & 0 & 0 & 5 & 2 & 6 \\ 8 & 6 & 0 & 4 & 1 & 10 & 4 \\ 1 & 8 & 5 & 1 & 1 & 1 & 5 \\ 1 & 3 & 2 & 10 & 1 & 6 & 4 \\ 0 & 2 & 6 & 4 & 5 & 4 & 3 \\ \end{array} \right)$$

Update: For versions 11.1 and older, replace TakeList with InternalPartitionRagged:

toSymmetricMat2 = Transpose[LowerTriangularize[#, -1]] + # &@
PadRight[InternalPartitionRagged[#, Range[1/2 (-1 + Sqrt[1 + 8 Length[#]])]]] &;

And @@ (toSymmetricMat2[#] == toSymmetricMat[#] & /@
{{5, 1, 6, 2, 3, 7}, {5, 1, 6, 2, 4, 7, 3, 5, 6, 8}, rvec})

True

• Thank you! I wanted to try your code, but I found that I do not have the TakeList function. It was introduced in MA11.2, but I have MA11.1.1. Can you maybe suggest a solution using older functions? Jun 24, 2021 at 12:05
• @yarchik, please see the update.
– kglr
Jun 24, 2021 at 13:38
• Thank you, it is actually 10 times faster than my code and 3 times faster than my compiled code :). I will wait a little bit with accepting the answer, maybe someone will come up with a function that does not use undocumented functions, as explicitly asked in OP. Jun 24, 2021 at 14:55