Python Forum

Full Version: Triangular matrix
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi everyone

I want to fill the lower part of a matrix with an input vector but i got problems

for i in range(1,len(variable)):
    for j in range(i):
        tableau[i,j] = coef[j+i-1]
i get
[[ 0.  0.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.]
 [ 2.  3.  0.  0.  0.]
 [ 3.  4.  5.  0.  0.]
 [ 4.  5.  6.  7.  0.]]
but i want to get
[[ 0  0  0  0  0]
 [ 1  0  0  0  0]
 [ 2  3  0  0  0]
 [ 4  5  6  0  0]
 [ 7  8  9 10  0]]
do you haver any idea ?

Thank you !
Try this:

def make_tril(v):
    from math import sqrt
    import sys
    n = 0.5 * (1 + sqrt(1 + 8 * len(v)))
    if abs(n - int(n)) <= 2 * int(n) * sys.float_info.epsilon:
        n = int(n)
        result = [[0 for i in range(n)] for j in range(n)]
        ind = 0
        for i in range(n):
            for j in range(i):
                result[i][j] = v[ind]
                ind += 1
    else:
        raise Exception('Non-consistent length of the input vector.')
    return result

make_tril([1,2,3,4,5,6,7,8,9,10])
Output:
[[0, 0, 0, 0, 0], [1, 0, 0, 0, 0], [2, 3, 0, 0, 0], [4, 5, 6, 0, 0], [7, 8, 9, 10, 0]]
In any case, loops (as well nested loops) are quite slow in Python. So, it would be better to use
numpy package, see numpy.tril_indices for that.
what's all that extra math for to fill part of a matrix?
(Jun-14-2018, 12:20 AM)Skaperen Wrote: [ -> ]what's all that extra math for to fill part of a matrix?

n = 0.5 * (1 + sqrt(1 + 8 * len(v))) is solution of the equation n*(n-1)/2 = len(v), where n -- size of the matrix to be filled by elements of v.

Improvement:
It is better to use round instead of int, when performing conversion to integer type:
...
if abs(n - round(n)) <= 2 * round(n) * sys.float_info.epsilon:
        n = round(n)
        ....
One gonna love itertools

Math is not my forte, but things you can do with itertools Heart and some simple logic ...
def triangle(size):
    source = itertools.count(1)
    return [[next(source) if col < row else 0 for col in range(size)] 
            for row in range(size)]
And the result is
Output:
In [3]: triangle(5) Out[3]: [[0, 0, 0, 0, 0], [1, 0, 0, 0, 0], [2, 3, 0, 0, 0], [4, 5, 6, 0, 0], [7, 8, 9, 10, 0]]
you can't figure out the size by running an incrementor through the input vector to figure out the diagonal to add to 2x the vector and stay in integer arithmetic? oh, you wanted to avoid the loop.