Doubts Python Matrices

Asked

Viewed 162 times

3

I am trying to create a function that returns the "minor complementary" matrix of any matrix. That is, given an array for example:

mat=[[1,2,3],[4,5,6],[7,8,9]]

The minor complement associated with the position element [0][0] would be the matrix with the row and column of the element [0][0] eliminated, leaving [[5,6],[8,9]].

My job is this::

def menor_complementar(M,L,C):
    #Onde: M é a matriz principal, L é o número da linha do elemento associado e C o número da coluna do elemento associado
    matriz_resultado=M[:]
    del(matriz_resultado[L])
    for linha in matriz_resultado:
        del(linha[C])
    return matriz_resultado

When I run:

menor_complementar(mat,0,0)

The output I get is exactly what I expect: ([[5,6],[8,9]])

But when I try to call this function again something unexpected occurs. For example, if I call you now with the following parameters:

menor_complementar(mat,1,1)

The exit is [[1, 3], [8]] instead of [[1,3],[7,9]] as it should.

Someone would know how to fix it?

1 answer

4


The problem is that Python doesn’t have native types of "matrix" - in general, in small programs, people invent a kind of matrix - and programs that will do stuff muting with matrices, can use the Numpy library, which yes, has a type of matrix that has dozens of specific operations possible, is quite optimized, and etc...

And, especially for those who are starting in programming, or in Python, a very common way of representing an array is like a "list list", in which each internal list represents a matrix line. From your code, we can see that this was your approach.

So your problem is that when we have a compound object in Python, if we create another reference to it, the two references are to the same object. You avoid this with your matrix itself - the list list, when writing the line matriz_resultado=M[:] - This is a Python expression that creates a "slice from the beginning to the end of a sequence", and therefore copies a list. Changes in this copy are not reflected in the original matrix.

However, you do not make copies of each row of your matrix: that is, the object list which is line 0 of its matrix matriz_resultado is the even object list which is line 0 of its matrix M.

So if you call your function with an "M1" test matrix, the result will be correct, but each row of the original matrix "M1" will be changed also, when the lines of matriz_resultado are changed within the function. (And the line that was removed from the matriz_resultado in full is not affected, of course).

A simple "print" between the calls to your function can make it very clear. In interactive mode I pasted exactly your code above, and called your function:

In [6]: a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]                                                                                  

In [7]: a                                                                                                                      
Out[7]: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

In [8]: menor_complementar(a, 0, 0)                                                                                            
Out[8]: [[5, 6], [8, 9]]

In [9]: a                                                                                                                      
Out[9]: [[1, 2, 3], [5, 6], [8, 9]]

How to solve:

This is solved by ensuring that all sub-elements of your composite object, in this case, the matrix lines, are also copied when making a copy of the matrix that will be modified.

This could be done manually with a for:

def menor_complementar(M, L, C):
     matriz_resultato = [linha[:] for linha in M]

(in case the for that copies each line is used in a "list comprehension"). But this use of for can be complicated in more complex compound objects (if the elements of their matrices were themselves lists, instead of numbers, for example, or if their matrix was a given together with others in a dictionary, etc...). The generic solution to this is the function deepcopy in the module copy from Python: it recursively copies each element of a compound object, whether its sub-elements are lists, dictionaries, sets and even instances of custom classes.

The following code is correct, using deepcopy:

from copy import deepcopy

def menor_complementar(M,L,C):
    #Onde: M é a matriz principal, L é o número da linha do elemento associado e C o número da coluna do elemento associado
    matriz_resultado = deepcopy(M)
    del(matriz_resultado[L])
    for linha in matriz_resultado:
        del(linha[C])
    return matriz_resultado
  • Genial jsbueno! Solved my problem. Mto thanks for the force!!!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.