In a matrix, a canonical column refers to a column that contains a canonical vector. A canonical vector is a vector that has a single element equal to 1 and all other elements equal to 0.
Given this list, leave only the columns that have a canonical vector.
matrix = [['X1', 'X2', 'X3', 'X4', 'X5', 'U1', 'U2', 'B'], [2.0, 1.0, -1.0, 0, 0, 1.0, 0, 8], [1.0, 1.0, 0, 1.0, 0, 0, 0, 2], [1.0, 2.0, 0, 0, -1.0, 0, 1.0, 8]]
That is, this should be the result in this exercise:
matrix = [['X4', 'U1', 'U2'], [0, 1.0, 0], [1.0, 0, 0], [0, 0, 1.0]]
Here is my code but it is failing, I don't know what I should modify anymore:
matrix = [['X1', 'X2', 'X3', 'X4', 'X5', 'U1', 'U2', 'B'], [2.0, 1.0, -1.0, 0, 0, 1.0, 0, 8], [1.0, 1.0, 0, 1.0, 0, 0, 0, 2], [1.0, 2.0, 0, 0, -1.0, 0, 1.0, 8]]
# Get the indices of the columns that contain a canonical vector (value 1.0 in a single position)
columnas_canonicas = [i for i, columna in enumerate(zip(*matrix[1:])) if sum(1 for elemento in columna if elemento == 1.0) == 1]
# We filter the columns that contain a canonical vector
matrix_aux = [[fila[0]] + [fila[i+1] for i in columnas_canonicas] for fila in matrix]
print(matrix_aux) #the output matrix
I've tried this code but it doesn't work, and it throws me this wrong array(matrix) that doesn't contain the columns with the canonical vectors.
[['X1', 'X5', 'U2', 'B'], [2.0, 0, 0, 8], [1.0, 0, 0, 2], [1.0, -1.0, 1.0, 8]]
None of the column vectors obtained with my code are canonical column vectors
def get_canonical_vectors(matrix):
M = matrix[1:]
m, n = len(M), len(M[0])
indices = []
matrix_aux = [[] for i in range(m+1)]
for j in range(n):
column = [M[i][j] for i in range(m)]
if column.count(1) == 1 and column.count(0) == m - 1:
indices.append(j)
matrix_aux[0].append(matrix[0][j])
for i in range(m):
matrix_aux[i+1].append(column[i])
return indices, matrix_aux
matrix = [['X1', 'X2', 'X3', 'X4', 'X5', 'U1', 'U2', 'B'], [2.0, 1.0, -1.0, 0, 0, 1.0, 0, 8], [1.0, 1.0, 0, 1.0, 0, 0, 0, 2], [1.0, 2.0, 0, 0, -1.0, 0, 1.0, 8]]
indices, matrix_aux = get_canonical_vectors(matrix)
print(indices)
print(matrix_aux)
prints
[3, 5, 6]
[['X4', 'U1', 'U2'], [0, 1.0, 0], [1.0, 0, 0], [0, 0, 1.0]]
Edit: actually, you can write this much shorter, close to what you did, by replacing
matrix_aux = [[fila[0]] + [fila[i+1] for i in columnas_canonicas] for fila in matrix]
with
matrix_aux = list(map(list, zip(*[c for i, c in enumerate(zip(*matrix)) if i in columnas_canonicas])))
However: this would also require updating the way the indices are retrieved. Currently, with
columnas_canonicas = [i for i, columna in enumerate(zip(*matrix[1:])) if sum(1 for elemento in columna if elemento == 1.0) == 1]
you could get false positives, e.g. a column [-2, 1, 2] would incorrectly get identified as a canonical column. You could use this instead to avoid this issue:
columnas_canonicas = [i for i, columna in enumerate(zip(*matrix[1:])) if columna.count(1) == 1 and columna.count(0) == len(columna) - 1]