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

# Aufgabenkontrolle11.py

# Diese Datei soll nur importiert, aber nicht bearbeitet werden.

import numpy as np
#wenn die Datei nicht imselben Ordner wie bruch.py gespeichert ist, müssen hier
#noch die folgenden beiden (auskommentierten) Befehle ausgeführt werden:
#(Der richtige Dateipfad muss natürlich noch eingegeben werden.)
# import sys
# sys.path.insert(0, '/home/MeinName/MeinOrdner/MeinUnterorder/Ordermitbruch')

from bruch import Bruch

def TestLR_Bruch(testfunktion):
    m = 10
    print(f'Ihre Funktion wird jetzt mit 3 ({m}x{m})-Matrizen getestet...');
    A = _zufallsmatINT(m)
    B = _zufallsmatBRUCH(m)
    C1 = _zufallsmatINT(m)
    C = _zufallsmatBRUCH(m)
    for i in range(m):
        for j in range(m):
            zufallsindex = np.random.randint(0,2)
            if zufallsindex == 0:
                C[i, j] = C1[i, j]
    texte = ['Matrix mit Integer-Einträgen',\
             'Matrix mit Bruch-Einträgen',\
             'Matrix mit gemischten Einträgen']
    tb = 0
    for M, text in zip([A, B, C], texte):
        print('Teste ' + text + ':')
        p, MLR = testfunktion(M)
        R = np.triu(MLR)
        L = np.eye(MLR.shape[0], dtype=int) + np.tril(MLR, -1)
        erg = np.equal(M[p,:], L@R).all()
        print(f'Das Ergebnis ist {"richtig" if erg else "falsch"}.');
        if erg:
            tb += 1;
    
    print(f'{tb} von 3 Tests erfolgreich.');

def _zufallsmatINT(m, Null = True):
    mat = np.random.randint(-20,20, m**2)
    if Null == False:
        mat[mat == 0] += 1
    return mat.reshape(m,m)

def _zufallsmatBRUCH(m):
    ZufINT1 = _zufallsmatINT(m)
    ZufINT2 = _zufallsmatINT(m, Null = False)
    MatBRUCH = np.zeros((m,m), dtype=Bruch)
    for i in range(m):
        for j in range(m):
            MatBRUCH[i,j] = Bruch(int(ZufINT1[i,j]), int(ZufINT2[i,j]))
    return MatBRUCH

####
def QRTest(A,testfunktion):
    '''QRTest(A,testfunktion) testet folgende Dinge:
    * Ist A eine m x n Matrix mit m>=n
    * Gilt Rang(A)=n
    Dann wird Q,R = testfunktion(A) berechnet und folgendes getestet:
    * Ist R eine obere Dreicksmatrix
    * Ist Q eine orthogonale Matrix
    * Gilt A=Q*R
    '''

    m,n=np.shape(A)
    assert m>=n, 'Es muss m>=n gelten'
    print('m>=n')
    assert np.linalg.matrix_rank(A)==n, 'Der Rang von A muss n sein'
    print('Rang(A)=n')
    Q,R=testfunktion(A)
    assert not (R-np.triu(R)).any(), 'R ist keine obere Dreiecksmatrix'
    print('R ist obere Dreieckmatrix')
    mq,nq=np.shape(Q)
    assert mq==nq, 'Q ist nicht quadratisch'
    print('Q ist quadratisch')
    assert np.linalg.norm(Q.T@Q-np.eye(mq),2)<10**(-10), 'Q ist keine orthogonale Matrix'
    print('Q ist orthogonal')
    assert np.linalg.norm(Q@R-A)<10**(-10), 'Q*R ist nicht A'
    print('Q*R=A')
    print('Alles super!')