# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'app.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets
import application
import numpy as np
from numpy.linalg import norm, solve


class MyQtApp(application.Ui_MainWindow, QtWidgets.QMainWindow):
    def __init__(self):
        super(MyQtApp, self).__init__()
        self.setupUi(self)

        self.pushButtonWczytajPliki.clicked.connect(self.zaladujMacierze)
        self.radioButtonIteration.clicked.connect(self.choosedIteracje)
        self.radioButtonTolerance.clicked.connect(self.choosedTolerancja)
        self.pushButtonOblicz.clicked.connect(self.oblicz)



    A = None
    b = None
    PLIK_WSP = './wspolczynniki.txt'
    PLIK_ROZ = './rozwiazania.txt'
    choosed_option = ''
    tol = 1E-9
    maxiter = 25
    WARNING = ''

    def wczytywanie(self, plik_wspolczynniki, plik_rozwiazania):
        size = 0
        print('\n################ MACIERZE WCZYTANE Z PLIKU ###################\n')
        with open(plik_wspolczynniki, 'r') as f:
            while f.readline() != '':
                size += 1
            A = np.ndarray((size, size))

        with open(plik_wspolczynniki, 'r') as f:
            flaga = True
            while flaga:
                for i in range(size):
                    temp = []
                    for x in (f.readline()).replace('[', '').replace(']', '').split(','):
                        # print(x)
                        temp.append(float(x.strip()))
                    print(temp)
                    A[i] = temp
                else:
                    flaga = False

        with open(plik_rozwiazania, 'r') as f:
            b = []
            for x in (f.readline()).replace('[', '').replace(']', '').split(','):
                b.append(float(x.strip()))
            b = np.array(b)
            print('\n', b)

        print('\n##############################################################\n')
        return A, b

    def jacobi(self, A, b, x0, **kwargs):
        """
        Performs Jacobi iterations to solve the line system of
        equations, Ax=b, starting from an initial guess, ``x0``.

        The program ends when the diffrence in x is less than ``tol``, or
        if ``maxiter`` [default=200] iterations have been exceeded.

        Returns 3 variables:
            1.  x, the estimated solution
            2.  rel_diff, the relative difference between last 2
                iterations for x
            3.  k, the number of iterations used.  If k=maxiter,
                then the required tolerance was not met.
        """
        n = A.shape[0]
        x = x0.copy()
        x_prev = x0.copy()
        k = 0
        rel_diff = MyQtApp.tol * 2
        isDiagonalyDominant = []

        D = np.diag(A)
        R = A - np.diagflat(D)

        # while (rel_diff > tol) and (k < maxiter):

        #     for _ in range(n):
        #         x = (b - np.dot(R,x)) / D
        #     k += 1

        #     rel_diff = norm(x - x_prev) / norm(x)
        #     print(x, rel_diff)
        #     x_prev = x.copy()

        # return x, rel_diff, k
        for i in range(n):
            row_sum = 0.0
            for j in range(n):
                if i != j:
                    row_sum += A[i][j]
            if abs(row_sum) > abs(A[i][i]):
                isDiagonalyDominant.append(False)
            else:
                isDiagonalyDominant.append(True)
        print(isDiagonalyDominant, '\t', all(isDiagonalyDominant))
        if all(isDiagonalyDominant) == False:
            print("\n-------- #WARNING# MATRIX IS NOT DIAGONALY DOMINANT TERMINATING PROGRAM #WARNING# -------\n")
            MyQtApp.WARNING = '-------- #WARNING# MATRIX IS NOT DIAGONALY DOMINANT TERMINATING PROGRAM #WARNING# -------'
            self.labelInformacje.setStyleSheet('color: red;')
            return False, False, False
        else:
            print("\n-------- #WARNING# MATRIX IS DIAGONALY DOMINANT CONTINUING PROGRAM #WARNING# -------\n")
            MyQtApp.WARNING = '-------- #WARNING# MATRIX IS DIAGONALY DOMINANT CONTINUING PROGRAM #WARNING# -------'
            self.labelInformacje.setStyleSheet('color: green;')
            if 'tol' in kwargs.keys():
                print('========PERFORMING TOLARANCE SENSITIVE ITERATION========')
                rel_diff = MyQtApp.tol * 2
                while (rel_diff > kwargs['tol']):
                    for _ in range(n):
                        x = (b - np.dot(R, x)) / D
                    k += 1

                    rel_diff = norm(x - x_prev) / norm(x)
                    print(x, rel_diff)
                    x_prev = x.copy()

                return x, rel_diff, k

            if 'iter' in kwargs.keys():
                print('========PERFORMING SPECIFIC NUMBER OF ITERATION========')
                while (k < kwargs['iter']):
                    for _ in range(n):
                        x = (b - np.dot(R, x)) / D
                    k += 1

                    rel_diff = norm(x - x_prev) / norm(x)
                    print(x, rel_diff)
                    x_prev = x.copy()

                return x, rel_diff, k

    def zaladujMacierze(self):
        MyQtApp.A, MyQtApp.b = self.wczytywanie(MyQtApp.PLIK_WSP, MyQtApp.PLIK_ROZ)
        # print(str(MyQtApp.A))
        self.labelWczytanaMacierz.setText(str(MyQtApp.A))
        temp_str = ''
        for x in MyQtApp.b:
            temp_str += '\n' + str(x) + '\n'
        self.labelWczytaneWyniki.setText(temp_str)

    def choosedIteracje(self):
        self.labelStop.setText('Iteracje')
        self.lineEditStop.setPlaceholderText('Iteracje')
        self.lineEditStop.setText(str(MyQtApp.maxiter))
        MyQtApp.choosed_option = 'iter'

    def choosedTolerancja(self):
        self.labelStop.setText('Tolerancja')
        self.lineEditStop.setPlaceholderText('Tolerancja')
        self.lineEditStop.setText(str(MyQtApp.tol))
        MyQtApp.choosed_option = 'tol'

    def oblicz(self):
        if MyQtApp.choosed_option == 'iter':
            MyQtApp.maxiter = int(self.lineEditStop.text())
            x0 = np.zeros(MyQtApp.A.shape[0])
            x, rel_diff, k = self.jacobi(MyQtApp.A, MyQtApp.b, x0, iter=MyQtApp.maxiter)
            self.labelInformacje.setText(MyQtApp.WARNING)
            self.labelNaszWynik.setText(str(x))
            self.labelWbudowanyWynik.setText(str(solve(MyQtApp.A, MyQtApp.b)))
            self.lineEditLiczbaIteracji.setText(str(k))
            self.lineEditWartoscTolerancji.setText(str(rel_diff))
        else:
            MyQtApp.tol = float(self.lineEditStop.text())
            x0 = np.zeros(MyQtApp.A.shape[0])
            x, rel_diff, k = self.jacobi(MyQtApp.A, MyQtApp.b, x0, tol=MyQtApp.tol)
            self.labelInformacje.setText(MyQtApp.WARNING)
            self.labelNaszWynik.setText(str(x))
            self.labelWbudowanyWynik.setText(str(solve(MyQtApp.A, MyQtApp.b)))
            self.lineEditLiczbaIteracji.setText(str(k))
            self.lineEditWartoscTolerancji.setText(str(rel_diff))

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    # MainWindow = QtWidgets.QMainWindow()
    ui = MyQtApp()
    # ui.setupUi(MainWindow)
    ui.show()
    sys.exit(app.exec_())
