diff --git a/grafico.h b/grafico.h new file mode 100644 index 0000000..a480725 --- /dev/null +++ b/grafico.h @@ -0,0 +1,238 @@ +#include +#include +#include + +// Segmento che parte dalle coordinate x,y di "inizio" a quelle di "fine" +typedef struct +{ + double m; + double q; +} Retta; + +void disegna_assi(); +void cls(int, int); +void disegna_punti(int); +void traccia_retta(double, double, int); +int *coordinate(int, int); +void stampa_epoca(int); + +/* void main() { + allegro_init(); + install_keyboard(); // Installa il gestore della tastiera + set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0); + cls(); + + for (int i = 0; i < 1000; i++) { + double m = (double)i / 100; + cls(); + traccia_retta(m,1.5); + sleep(0.1); + } + + readkey(); +} */ + +/* +Schermo 800x600 +Centro 400x300 + +0,0 - 400,0 - 800,0 +0,300 - 400,300 - 800,300 +0,600 - 400,600 - 800,600 + +Ogni punto nel grafico, 100 pixel +Range -2, 2 + +es retta y = mx + q con x=1, m=1, q=1 +y = 1 * 1 + 1 = 2 + +x = 1 +y = 2 + +*/ + +void traccia_retta(double m, double q, int colore) +{ + // determino il centro + int center_x = SCREEN_W / 2; // Coordinata x del centro + int center_y = SCREEN_H / 2; // Coordinata y del centro + + // Retta coi valori reali + double x_start = -3; + double x_end = 3; + double y_start = (m * x_start + q); + double y_end = (m * x_end + q); + + line(screen, center_x + (int)(x_start * 100), center_y - (int)(y_start * 100), center_x + (int)(x_end * 100), center_y - (int)(y_end * 100), colore); + sleep(0.1); +} + +void disegna_assi() +{ + // determino il centro + int center_x = SCREEN_W / 2; // Coordinata x del centro + int center_y = SCREEN_H / 2; // Coordinata y del centro + + // Colore delle linee + int colore_nero = makecol(0, 0, 0); + + // Disegna gli assi + line(screen, center_x, 0, center_x, SCREEN_H - 1, colore_nero); + line(screen, 0, center_y, SCREEN_W - 1, center_y, colore_nero); + + // Zero nel punto di intersezione + textout_ex(screen, font, "0", center_x - 10, center_y + 5, colore_nero, -1); +} + +void disegna_legenda(int multi_layer) { + + int colore_rosso = makecol(255, 0, 0); + int colore_verde = makecol(0, 255, 0); + int colore_blu = makecol(0, 0, 255); + + if(multi_layer == 0) + textout_ex(screen, font, "Percettrone", 0 + 10, 0 + 10, colore_rosso, -1); + else { + textout_ex(screen, font, "Percettrone 1", 0 + 10, 0 + 10, colore_rosso, -1); + textout_ex(screen, font, "Percettrone 2", 0 + 10, 0 + 20, colore_verde, -1); + textout_ex(screen, font, "Percettrone out", 0 + 10, 0 + 30, colore_blu, -1); + } +} + +void stampa_epoca(int epoca) { + int colore_rosso = makecol(255, 0, 0); + + char stringa[4]; + sprintf(stringa, "%d", epoca); + + textout_ex(screen, font, stringa, SCREEN_W - 50, 0 + 20, colore_rosso, -1); +} + +/* +il tipo indica quali punti vogliamo disegnare nel grafico: +0: AND +1: OR +2: XOR +3: NAND +4: NOR +5: XNOR +*/ +void cls(int tipo, int multi_layer) +{ + clear_to_color(screen, makecol(255, 255, 255)); // Sfondo bianco + disegna_assi(); + disegna_punti(tipo); + disegna_legenda(multi_layer); +} + +void disegna_punti(int tipo) +{ + int raggio = 3; + int colore_verde = makecol(0, 255, 0); + int colore_rosso = makecol(255, 0, 0); + int colore_nero = makecol(0, 0, 0); + + textout_ex(screen, font, "Epoca:", SCREEN_W - 100, 0 + 20, colore_rosso, -1); + + switch (tipo) + { + case 0: //AND + int *punto = coordinate(0, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + punto = coordinate(0, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + punto = coordinate(1, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + punto = coordinate(1, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + + textout_ex(screen, font, "AND", SCREEN_W - 50, 0 + 10, colore_nero, -1); + break; + case 1: //OR + punto = coordinate(0, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + punto = coordinate(0, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + punto = coordinate(1, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + punto = coordinate(1, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + + textout_ex(screen, font, "OR", SCREEN_W - 50, 0 + 10, colore_nero, -1); + break; + case 2: //XOR + punto = coordinate(0, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + punto = coordinate(0, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + punto = coordinate(1, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + punto = coordinate(1, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + + textout_ex(screen, font, "XOR", SCREEN_W - 50, 0 + 10, colore_nero, -1); + break; + case 3: //NAND + punto = coordinate(0, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + punto = coordinate(0, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + punto = coordinate(1, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + punto = coordinate(1, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + + textout_ex(screen, font, "NAND", SCREEN_W - 50, 0 + 10, colore_nero, -1); + break; + case 4: //NOR + punto = coordinate(0, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + punto = coordinate(0, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + punto = coordinate(1, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + punto = coordinate(1, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + + textout_ex(screen, font, "NOR", SCREEN_W - 50, 0 + 10, colore_nero, -1); + break; + case 5: //XNOR + punto = coordinate(0, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + punto = coordinate(0, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + punto = coordinate(1, 0); + circlefill(screen, punto[0], punto[1], raggio, colore_rosso); + punto = coordinate(1, 1); + circlefill(screen, punto[0], punto[1], raggio, colore_verde); + + textout_ex(screen, font, "XNOR", SCREEN_W - 50, 0 + 10, colore_nero, -1); + break; + + default: + break; + } +} + +// Mi da le coordinate in pixel dati i punti in ingresso +int *coordinate(int x, int y) +{ + // determino il centro + int center_x = SCREEN_W / 2; // Coordinata x del centro + int center_y = SCREEN_H / 2; // Coordinata y del centro + + int *coordinate = (int *)malloc(sizeof(int) * 2); + + coordinate[0] = center_x + (x * 100); + coordinate[1] = center_y - (y * 100); + + return coordinate; +} + +void sleep_ms(int milliseconds) +{ + struct timespec ts; + ts.tv_sec = milliseconds / 1000; + ts.tv_nsec = (milliseconds % 1000) * 1000000; + nanosleep(&ts, NULL); +} \ No newline at end of file diff --git a/layer_multi.c b/layer_multi.c new file mode 100644 index 0000000..f04a139 --- /dev/null +++ b/layer_multi.c @@ -0,0 +1,189 @@ +#include +#include "percettrone.h" +#include "grafico.h" + +int MAX_EPOCHE = 10000; + +/* + il tipo indica quali punti vogliamo disegnare nel grafico: + 0: AND + 1: OR + 2: XOR + 3: NAND + 4: NOR + 5: XNOR +*/ +int tipo = 2; + +void stampa_risultati(Percettrone); + +void main() +{ + srand(time(NULL)); + + allegro_init(); + install_keyboard(); + set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0); + cls(tipo, 1); + + int output[4]; + switch (tipo) + { + case 0: + output[0] = 0; + output[1] = 0; + output[2] = 0; + output[3] = 1; + break; + case 1: + output[0] = 0; + output[1] = 1; + output[2] = 1; + output[3] = 1; + break; + case 2: + output[0] = 0; + output[1] = 1; + output[2] = 1; + output[3] = 0; + break; + case 3: + output[0] = 1; + output[1] = 1; + output[2] = 1; + output[3] = 0; + break; + case 4: + output[0] = 1; + output[1] = 0; + output[2] = 0; + output[3] = 0; + break; + case 5: + output[0] = 1; + output[1] = 0; + output[2] = 0; + output[3] = 1; + break; + + default: + break; + } + + Percettrone p_ext_1 = crea_percettrone(); + int colore_rosso = makecol(255, 0, 0); + + Percettrone p_ext_2 = crea_percettrone(); + int colore_verde = makecol(0, 255, 0); + + Percettrone pout = crea_percettrone(); + int colore_blu = makecol(0, 0, 255); + + // Contatore per fermare il percettrone, se vale 4 significa che ha indovinato tutte e 4 le combinazioni + int corrette = 0; + + Retta *rette_p_ext_1 = (Retta *)malloc(sizeof(Retta)); + Retta *rette_p_ext_2 = (Retta *)malloc(sizeof(Retta)); + Retta *rette_pout = (Retta *)malloc(sizeof(Retta)); + + int size_iniziale = sizeof(rette_p_ext_1); + + // Soglia sigmoide + double soglia_funzione_attivazione = 0.5; + + for (int i = 0; i < MAX_EPOCHE; i++) + { + if (corrette == 4) + { + printf("\nEpoche necessarie: %d\n", i); + stampa_risultati_layer_multi(p_ext_1, p_ext_2, pout); + + for (int z = 0; z < i; z++) + { + cls(tipo, 1); + traccia_retta(rette_p_ext_1[z].m, rette_p_ext_1[z].q, colore_rosso); + traccia_retta(rette_p_ext_2[z].m, rette_p_ext_2[z].q, colore_verde); + traccia_retta(rette_pout[z].m, rette_pout[z].q, colore_blu); + //printf("Sto tracciando la retta p1 con coefficiente: %f e intercetta: %f\n", rette_p_ext_1[z].m, rette_p_ext_1[z].q); + //printf("Sto tracciando la retta p2 con coefficiente: %f e intercetta: %f\n", rette_p_ext_2[z].m, rette_p_ext_2[z].q); + //printf("Sto tracciando la retta pout con coefficiente: %f e intercetta: %f\n", rette_pout[z].m, rette_pout[z].q); + stampa_epoca(z + 1); + sleep_ms(10); + } + + readkey(); + + break; + } + + printf("\nEpoca %d\n", i); + corrette = 0; + + for (int j = 0; j < 4; j++) + { + + double y_ext_1 = funzione_sigmoide(p_ext_1, x[j][0], x[j][1]); + double y_ext_2 = funzione_sigmoide(p_ext_2, x[j][0], x[j][1]); + double yout = funzione_sigmoide(pout, y_ext_1, y_ext_2); + + double errore = -(output[j] - yout); + int previsione = -1; + + if (yout >= soglia_funzione_attivazione) + { + previsione = 1; + } + else + { + previsione = 0; + } + + stampa_layer_uno(p_ext_1, y_ext_1, x[j][0], x[j][1], errore); + stampa_layer_out(pout, previsione, y_ext_1, y_ext_2, errore); + stampa_layer_uno(p_ext_2, y_ext_2, x[j][0], x[j][1], errore); + + if (previsione == output[j]) + { + corrette++; + } + else + { + // Gradienti percettrone 1 + double gradiente_w1 = errore * yout * (1 - yout) * y_ext_1 * (1 - y_ext_1) * x[j][0]; + double gradiente_w2 = errore * yout * (1 - yout) * y_ext_1 * (1 - y_ext_1) * x[j][1]; + double gradiente_bias = errore * yout * (1 - yout) * y_ext_1 * (1 - y_ext_1); + correggi_pesi(&p_ext_1, gradiente_w1, gradiente_w2, gradiente_bias); + + // Gradienti percettrone 2 + gradiente_w1 = errore * yout * (1 - yout) * y_ext_2 * (1 - y_ext_2) * x[j][0]; + gradiente_w2 = errore * yout * (1 - yout) * y_ext_2 * (1 - y_ext_2) * x[j][1]; + gradiente_bias = errore * yout * (1 - yout) * y_ext_2 * (1 - y_ext_2); + correggi_pesi(&p_ext_2, gradiente_w1, gradiente_w2, gradiente_bias); + + // Gradienti percettrone out + gradiente_w1 = errore * yout * (1 - yout) * y_ext_1; + gradiente_w2 = errore * yout * (1 - yout) * y_ext_2; + gradiente_bias = errore * yout * (1 - yout); + correggi_pesi(&pout, gradiente_w1, gradiente_w2, gradiente_bias); + } + + // Prevengo la divisione per zero + if(p_ext_1.w2 != 0 && p_ext_2.w2 != 0 && pout.w2 !=0) + { + rette_p_ext_1[i].m = -(p_ext_1.w1 * x[j][0]) / p_ext_1.w2; + rette_p_ext_1[i].q = -(p_ext_1.bias / p_ext_1.w2); + rette_p_ext_2[i].m = -(p_ext_2.w1 * x[j][0]) / p_ext_2.w2; + rette_p_ext_2[i].q = -(p_ext_2.bias / p_ext_2.w2); + rette_pout[i].m = -(pout.w1 * x[j][0]) / pout.w2; + rette_pout[i].q = -(pout.bias / pout.w2); + + if (corrette != 4) + { + rette_p_ext_1 = (Retta *)realloc(rette_p_ext_1, sizeof(Retta) * (i + 2)); + rette_p_ext_2 = (Retta *)realloc(rette_p_ext_2, sizeof(Retta) * (i + 2)); + rette_pout = (Retta *)realloc(rette_pout, sizeof(Retta) * (i + 2)); + } + } + } + } +} \ No newline at end of file diff --git a/layer_singolo.c b/layer_singolo.c index e69de29..c2ec22a 100644 --- a/layer_singolo.c +++ b/layer_singolo.c @@ -0,0 +1,148 @@ +#include +#include "percettrone.h" +#include "grafico.h" + +int MAX_EPOCHE = 10000; +/* + il tipo indica quali punti vogliamo disegnare nel grafico: + 0: AND + 1: OR + 2: XOR + 3: NAND + 4: NOR + 5: XNOR +*/ +int tipo = 3; + +void stampa_risultati(Percettrone); +void sleep_ms(int); + +void main() +{ + srand(time(NULL)); + + allegro_init(); + install_keyboard(); + set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0); + cls(tipo, 0); + + int output[4]; + switch (tipo) + { + case 0: + output[0] = 0; + output[1] = 0; + output[2] = 0; + output[3] = 1; + break; + case 1: + output[0] = 0; + output[1] = 1; + output[2] = 1; + output[3] = 1; + break; + case 2: + output[0] = 0; + output[1] = 1; + output[2] = 1; + output[3] = 0; + break; + case 3: + output[0] = 1; + output[1] = 1; + output[2] = 1; + output[3] = 0; + break; + case 4: + output[0] = 1; + output[1] = 0; + output[2] = 0; + output[3] = 0; + break; + case 5: + output[0] = 1; + output[1] = 0; + output[2] = 0; + output[3] = 1; + break; + + default: + break; + } + + Percettrone p = crea_percettrone(); + int colore_rosso = makecol(255, 0, 0); + + // Contatore per fermare il percettrone, se vale 4 significa che ha indovinato tutte e 4 le combinazioni + int corrette = 0; + + Retta *rette = (Retta *)malloc(sizeof(Retta)); + + // Soglia sigmoide + double soglia_funzione_attivazione = 0.5; + + for (int i = 0; i < MAX_EPOCHE; i++) + { + if (corrette == 4) + { + printf("\nEpoche necessarie: %d\n", i); + stampa_risultati_layer_singolo(p); + + for (int z = 0; z < i; z++) + { + cls(tipo, 0); + traccia_retta(rette[z].m, rette[z].q, colore_rosso); + //printf("Sto tracciando la retta con coefficiente: %f e intercetta: %f\n", rette[z].m, rette[z].q); + stampa_epoca(z + 1); + sleep_ms(100); + } + + readkey(); + break; + } + + printf("\nEpoca %d\n", i); + corrette = 0; + + for (int j = 0; j < 4; j++) + { + + double y = funzione_sigmoide(p, x[j][0], x[j][1]); + + double errore = -(output[j] - y); + int previsione = -1; + + if (y >= soglia_funzione_attivazione) + { + previsione = 1; + } + else + { + previsione = 0; + } + + stampa_layer_out(p, previsione, x[j][0], x[j][1], errore); + + if (previsione == output[j]) + { + corrette++; + } + else + { + double gradiente_w1 = errore * y * (1 - y) * x[j][0]; + double gradiente_w2 = errore * y * (1 - y) * x[j][1]; + double gradiente_bias = errore * y * (1 - y); + + correggi_pesi(&p, gradiente_w1, gradiente_w2, gradiente_bias); + } + + rette[i].m = -(p.w1 * x[j][0]) / p.w2; + rette[i].q = -(p.bias / p.w2); + + if (corrette != 4) + { + rette = (Retta *)realloc(rette, sizeof(Retta) * (i + 2)); + } + } + } +} \ No newline at end of file diff --git a/percettrone b/percettrone deleted file mode 100755 index 1572d01..0000000 Binary files a/percettrone and /dev/null differ diff --git a/percettrone.c b/percettrone.c deleted file mode 100644 index f4b3c9c..0000000 --- a/percettrone.c +++ /dev/null @@ -1,48 +0,0 @@ -#include ; -#include ; -#include ; - -Percettrone p1 = creaPercettrone(); -Percettrone p2 = creaPercettrone(); -Percettrone p3 = creaPercettrone(); - -struct struttura_percettrone { - double w1; - double w2; - double bias; - double lre; -}; -typedef struct struttura_percettrone Percettrone; - -Percettrone creaPercettrone() { - srand(time(NULL)); - - Percettrone percettrone; - - percettrone.w1 = random(); - percettrone.w2 = random(); - percettrone.bias = random(); - percettrone.lre = 0.2; - - return percettrone; -} - -double random() { - // Genero numeri nell'intervallo [-1,1] - return ((double)(rand() % 101 * 0.01 * 2 ) -1); -} - -void main() { - creaPercettrone(); -} - - - - /* # il return verrĂ  confrontato col valore di soglia di attivazione - def funzione_sigmoide(self, x1, x2): - return (1 / (1 + math.exp(-((x1 * self.w1) + (x2 * self.w2) + self.bias)))) - - def correggi_pesi(self, gradiente_w1, gradiente_w2, gradiente_bias): - self.bias = self.bias - (gradiente_bias * self.lre) - self.w1 = self.w1 - (gradiente_w1 * self.lre) - self.w2 = self.w2 - (gradiente_w2 * self.lre) */ \ No newline at end of file diff --git a/percettrone.h b/percettrone.h new file mode 100644 index 0000000..0adac87 --- /dev/null +++ b/percettrone.h @@ -0,0 +1,94 @@ +#include +#include + +double LRE = 0.2; + +typedef struct { + double w1; + double w2; + double bias; + double lre; +} Percettrone; + +// Inputs +int x[4][2] = { + {0, 0}, + {0, 1}, + {1, 0}, + {1, 1}, +}; + +// Dichiarazione dei metodi +Percettrone crea_percettrone(); +double randomico(); +double funzione_sigmoide(Percettrone, double, double); +void correggi_pesi(Percettrone*, double, double, double); + +void stampa_layer_uno(Percettrone, double, int, int, double); +void stampa_layer_out(Percettrone, int, double, double, double); +void stampa_risultati_layer_singolo(Percettrone); +void stampa_risultati_layer_multi(Percettrone, Percettrone, Percettrone); + +Percettrone crea_percettrone() { + + Percettrone percettrone; + + percettrone.w1 = randomico(); + percettrone.w2 = randomico(); + percettrone.bias = randomico(); + percettrone.lre = LRE; + + return percettrone; +} + +double randomico() { + // Genero numeri nell'intervallo [-1,1] + return ((double)(rand() % 101 * 0.01 * 2 ) -1); +} + +double funzione_sigmoide(Percettrone p, double x1, double x2) { + double funzione = (x1 * p.w1) + (x2 * p.w2) + p.bias; + double potenza_e = exp(-funzione); + double risultato = 1 / ( 1 + potenza_e); + + return risultato; +} + +void correggi_pesi(Percettrone *p, double grad_w1, double grad_w2, double grad_bias) { + (*p).bias = (*p).bias - (grad_bias * (*p).lre); + (*p).w1 = (*p).w1 - (grad_w1 * (*p).lre); + (*p).w2 = (*p).w2 - (grad_w2 * (*p).lre); +} + +void stampa_layer_uno(Percettrone p, double y, int x1, int x2, double errore) +{ + printf("\n"); + printf("\tW1: %f\n", p.w1); + printf("X1: %d --------> \n", x1); + printf("\t\t( bias: %f ) -------> Y: %f, errore: %f\n", p.bias, y, errore); + printf("X2: %d --------> \n", x2); + printf("\tW2: %f\n", p.w2); + printf("\n\n"); +} + +void stampa_layer_out(Percettrone p, int y, double x1, double x2, double errore) { + printf("\t\t\t\t\t\tW1: %f\n", p.w1); + printf("\t\t\t\t\tX1: %f --------> \n", x1); + printf("\t\t\t\t\t\t\t( bias: %f ) -------> Y: %d, errore: %f\n", p.bias, y, errore); + printf("\t\t\t\t\tX2: %f --------> \n", x2); + printf("\t\t\t\t\t\tW2: %f\n", p.w2); +} + +void stampa_risultati_layer_singolo(Percettrone p) { + printf("\nPercettrone:\n"); + printf("\t W1: %f, W2: %f, bias: %f\n", p.w1, p.w2, p.bias); +} + +void stampa_risultati_layer_multi(Percettrone p1, Percettrone p2, Percettrone pout) { + printf("\nPercettrone 1:\n"); + printf("\t W1: %f, W2: %f, bias: %f\n", p1.w1, p1.w2, p1.bias); + printf("Percettrone 2:\n"); + printf("\t W1: %f, W2: %f, bias: %f\n", p2.w1, p2.w2, p2.bias); + printf("Percettrone OUT:\n"); + printf("\t W1: %f, W2: %f, bias: %f\n", pout.w1, pout.w2, pout.bias); +} \ No newline at end of file diff --git a/stampe_video.h b/stampe_video.h new file mode 100644 index 0000000..e69de29 diff --git a/tempCodeRunnerFile.c b/tempCodeRunnerFile.c new file mode 100644 index 0000000..7d105a7 --- /dev/null +++ b/tempCodeRunnerFile.c @@ -0,0 +1 @@ +-3 \ No newline at end of file