#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Musterlösung für Aufgabe 33

import numpy as np


# Vorwärtssubstitution

def vorwaerts(L, b):
    n = L.shape[0]
    
    assert (n == L.shape[1] and n == b.shape[0] and b.shape[1] == 1),\
        "Dimensionen passen nicht."
    
    assert np.prod(L.diagonal()), "L ist nicht invertierbar."
    # alternativ:
    #assert (not(any(np.diag(L) == 0))), "L ist nicht invertierbar."
    # oder:
    # Die Überprüfung geht natürlich auch in der Schleife, in dem jedes
    # Diagonalelement überprüft wird.
    
    x = np.zeros_like(b, dtype=float)
    x[0] = b[0]/L[0, 0]
    for i in range(1, n):
        x[i] = (b[i] - L[i, :i] @ x[:i])/L[i, i]
        
    return x



# Rückwärtssubstitution

def rueckwaerts(R, b):
    n = R.shape[0]
    
    assert (n == R.shape[1] and n == b.shape[0] and b.shape[1] == 1),\
        "Dimensionen passen nicht."
    
    assert np.prod(R.diagonal()), "R ist nicht invertierbar."
    
    x = np.zeros_like(b, dtype=float)
    x[n-1] = b[n-1]/R[n-1, n-1]
    for i in range(n-2, -1, -1):
        x[i] = (b[i] - R[i, i+1:] @ x[i+1:])/R[i, i]
        
    return x

