# Univerzitet u Novom Sadu, Fakultet tehničkih nauka, Novi Sad, Srbija
# Studijski program OAS Informacioni inženjering
# Predmet Metode i tehnike nauke o podacima

# Pomoćni sadržaj


# %% Biblioteke

import abc
import numpy as np
import matplotlib.pyplot as plt


# %% Implementacija fazi skupova i operacija

class FaziSkup(abc.ABC):
    @abc.abstractmethod
    def __init__(self):
        self.očitavanje_pripadnosti_vektorski = np.vectorize(
            self.očitavanje_pripadnosti)

    @abc.abstractmethod
    def očitavanje_pripadnosti(self, x):
        pass

class FaziSkupKomplement(FaziSkup):
    def __init__(self, osnova):
        super().__init__()
        self.fazi_skup_osnova = osnova

    def očitavanje_pripadnosti(self, x):
        return 1 - self.fazi_skup_osnova.očitavanje_pripadnosti(x)

class FaziSkupUnija(FaziSkup):
    def __init__(self, a, b):
        super().__init__()
        self.fazi_skup_a = a
        self.fazi_skup_b = b

    def očitavanje_pripadnosti(self, x):
        return max(self.fazi_skup_a.očitavanje_pripadnosti(x),
                   self.fazi_skup_b.očitavanje_pripadnosti(x))

class FaziSkupPresek(FaziSkup):
    def __init__(self, a, b):
        super().__init__()
        self.fazi_skup_a = a
        self.fazi_skup_b = b

    def očitavanje_pripadnosti(self, x):
        return min(self.fazi_skup_a.očitavanje_pripadnosti(x),
                   self.fazi_skup_b.očitavanje_pripadnosti(x))

class FaziSkupRazlika(FaziSkup):
    def __init__(self, a, b):
        super().__init__()
        self.fazi_skup_a = a
        self.fazi_skup_b = b

    def očitavanje_pripadnosti(self, x):
        return min(self.fazi_skup_a.očitavanje_pripadnosti(x),
                   1 - self.fazi_skup_b.očitavanje_pripadnosti(x))

class FaziSkupTrougaoni(FaziSkup):
    def __init__(self, a, b, c):
        super().__init__()
        self.a = a
        self.b = b
        self.c = c

    def očitavanje_pripadnosti(self, x):
        if x >= self.a and x <= self.b:
            return (x - self.a) / (self.b - self.a)
        elif x > self.b and x <= self.c:
            return (self.c - x) / (self.c - self.b)
        else:
            return 0.0

class FaziSkupTrapezoidni(FaziSkup):
    def __init__(self, a, b, c, d):
        super().__init__()
        self.a = a
        self.b = b
        self.c = c
        self.d = d

    def očitavanje_pripadnosti(self, x):
        if x >= self.a and x <= self.b:
            return (x - self.a) / (self.b - self.a)
        elif x > self.b and x <= self.c:
            return 1.0
        elif x > self.c and x <= self.d:
            return (self.d - x) / (self.d - self.c)
        else:
            return 0.0


# %% Upotreba fazi skupa

fazi_skup_trougaoni = FaziSkupTrougaoni(-2, 0, 1)
fazi_skup_trapezoidni = FaziSkupTrapezoidni(-0.5, 0.5, 1.5, 2)
fazi_skup_komplement = FaziSkupKomplement(fazi_skup_trougaoni)
fazi_skup_unija = FaziSkupUnija(fazi_skup_trougaoni, fazi_skup_trapezoidni)
fazi_skup_presek = FaziSkupPresek(fazi_skup_trougaoni, fazi_skup_trapezoidni)
fazi_skup_razlika = FaziSkupRazlika(fazi_skup_trougaoni, fazi_skup_trapezoidni)

x = np.arange(-5, 5, 0.1)
y_trougaoni = fazi_skup_trougaoni.očitavanje_pripadnosti_vektorski(x)
y_trapezoidni = fazi_skup_trapezoidni.očitavanje_pripadnosti_vektorski(x)
y_komplement = fazi_skup_komplement.očitavanje_pripadnosti_vektorski(x)
y_unija = fazi_skup_unija.očitavanje_pripadnosti_vektorski(x)
y_presek = fazi_skup_presek.očitavanje_pripadnosti_vektorski(x)
y_razlika = fazi_skup_razlika.očitavanje_pripadnosti_vektorski(x)

plt.figure()
plt.plot(x, y_trougaoni, "--b", alpha=0.5, label="Fazi skup A")
plt.plot(x, y_komplement, "-r", alpha=0.5, label="Komplement A")
plt.legend()
plt.title("Primer komplementa fazi skupa")

plt.figure()
plt.plot(x, y_trougaoni, "--b", alpha=0.5, label="Fazi skup A")
plt.plot(x, y_trapezoidni, "-.g", alpha=0.5, label="Fazi skup B")
plt.plot(x, y_unija, "-r", alpha=0.5, label="Unija A i B")
plt.legend()
plt.title("Primer unije fazi skupova")

plt.figure()
plt.plot(x, y_trougaoni, "--b", alpha=0.5, label="Fazi skup A")
plt.plot(x, y_trapezoidni, "-.g", alpha=0.5, label="Fazi skup B")
plt.plot(x, y_presek, "-r", alpha=0.5, label="Presek A i B")
plt.legend()
plt.title("Primer preseka fazi skupova")

plt.figure()
plt.plot(x, y_trougaoni, "--b", alpha=0.5, label="Fazi skup A")
plt.plot(x, y_trapezoidni, "-.g", alpha=0.5, label="Fazi skup B")
plt.plot(x, y_razlika, "-r", alpha=0.5, label="Razlika A i B")
plt.legend()
plt.title("Primer razlike fazi skupova")

