import numpy as np


def switchRows(matrix, row1, row2):
    matrix[[row1, row2]] = matrix[[row2, row1]]
    return matrix

def Schenk_Brandenberger_S6_Aufg2(A, b):

    def calculateRow(A, b, row, column):
        b[row] = [b[row][0] - (A[row][column] / A[column][column]) * b[column][0]]
        A[row] = [(A[row][i] - (A[row][column] / A[column][column]) * A[column][i]) for i in range(len(A[row]))]
        return A, b

    # Erstelle obere Dreiecksmatrix
    countRowSwitch = 0
    columnsToEdit = []
    for row in range(1, len(A)):
        columnsToEdit.append(row - 1)
        for column in columnsToEdit:
            if(A[row-1][column] == 0 and (row - 1 == column)):
                rowToSwitch = row
                if(row == 1):
                    while(A[rowToSwitch][column] == 0):
                        if(len(A) > rowToSwitch + 1):
                            rowToSwitch += 1
                        else:
                            return "Matrix ist nicht regulär!"
                A = switchRows(A, row - 1, rowToSwitch)
                b = switchRows(b, row - 1, rowToSwitch)
                countRowSwitch += 1
            else:
                A, b = calculateRow(A, b, row, column)
    #print("\nObere Dreiecksmatrix A:\n", A, "\nb:\n", b)

    # Rückwärtseinsetzen
    columnsToEdit = []
    for row in range((len(A) - 2), -1, -1):
        columnsToEdit.append(row + 1)
        for column in columnsToEdit:
            A, b = calculateRow(A, b, row, column)
        row -= 1
    #print("\nA:\n", A, "\nb:\n", b)

    det = 1
    result = []
    for i in range(len(A)):
        result.append(b[i][0] / A[i][i])
        det *= A[i][i]
    if(countRowSwitch % 2 == 1):
        det *= (-1)
    return result, det



if __name__ == '__main__':
    # Zahlen von Serie 7 Aufgabe 1c
    # A = np.array([[20000.0, 30000.0, 10000.0],
    #                [10000.0, 17000.0, 6000.0],
    #                [2000.0, 3000.0, 2000.0]])
    #
    # b = np.array([[5720000.0],
    #                [3300000.0],
    #                [836000.0]])

    # Aufgabe 3c
    A = np.array([[20000.0 - 100.0, 30000.0 - 100.0, 10000.0 - 100.0],
                   [10000.0 - 100.0, 17000.0 - 100.0, 6000.0 - 100.0],
                   [2000.0 - 100.0, 3000.0 - 100.0, 2000.0 - 100.0]])

    b = np.array([[5720000.0 + 100000.0],
                   [3300000.0 + 100000.0],
                   [836000.0 + 100000.0]])

    result, det = Schenk_Brandenberger_S6_Aufg2(A, b)
    print("Ergebnis:")
    for i in range(len(result)):
        print("x" + str(i) + ": " + str(result[i]))
    print("Determinante: " + str(det))