refactor: split gui/optimization
authorametama <ametama@wafflesoft.org>
Wed, 17 Dec 2025 21:50:37 +0000 (22:50 +0100)
committerametama <ametama@wafflesoft.org>
Wed, 17 Dec 2025 21:50:37 +0000 (22:50 +0100)
include/gui.h [new file with mode: 0644]
include/particle_swarm.h [deleted file]
include/swarm.h [new file with mode: 0644]
src/gui.c [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/particle_swarm.c [deleted file]
src/swarm.c [new file with mode: 0644]

diff --git a/include/gui.h b/include/gui.h
new file mode 100644 (file)
index 0000000..2ea4b73
--- /dev/null
@@ -0,0 +1,3 @@
+#include <gtk/gtk.h>
+
+GtkApplication *gui_init();
diff --git a/include/particle_swarm.h b/include/particle_swarm.h
deleted file mode 100644 (file)
index a9fdedb..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-typedef struct particle particle;
-
-typedef struct {
-  double min;
-  double max;
-} range;
-
-typedef struct {
-  double *x;
-  double fitness;
-} particle_state;
-
-typedef struct {
-  int particlec;
-  particle *particles;
-  particle *global_best;
-} swarm;
-
-struct particle {
-  particle_state current;
-  particle_state best;
-  double *velocity;
-};
-
-void pick(const int dim, const range *vrange, double *v);
-void swarm_init(swarm *sw, const int dim, const range *vrange);
-void swarm_velocity_update(swarm *sw, const int dim);
diff --git a/include/swarm.h b/include/swarm.h
new file mode 100644 (file)
index 0000000..25cbe0b
--- /dev/null
@@ -0,0 +1,38 @@
+typedef struct particle particle;
+
+typedef struct {
+  double min;
+  double max;
+} range;
+
+typedef struct {
+  double *x;
+  double fitness;
+} particle_state;
+
+typedef struct {
+  int dim;
+  double (*f)(double*);
+  int particlec;
+  double eps;
+  double w;
+  double c;
+  double s;
+} swarm_parameters;
+
+typedef struct {
+  swarm_parameters params;
+  particle *particles;
+  particle *global_best;
+} swarm;
+
+struct particle {
+  particle_state current;
+  particle_state best;
+  double *velocity;
+};
+
+void pick(const int dim, const range *vrange, double *v);
+void swarm_populate(swarm *sw, const range *rrange);
+void swarm_velocity_update(swarm *sw);
+void swarm_optimize(swarm *sw);
diff --git a/src/gui.c b/src/gui.c
new file mode 100644 (file)
index 0000000..532f9af
--- /dev/null
+++ b/src/gui.c
@@ -0,0 +1,15 @@
+#include "gui.h"
+
+static void on_activate(GtkApplication *app) {
+  GtkWidget *window = gtk_application_window_new(app);
+  GtkWidget *button = gtk_button_new_with_label("Hello, World!");
+  g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_window_close), window);
+  gtk_window_set_child(GTK_WINDOW(window), button);
+  gtk_window_present(GTK_WINDOW(window));
+}
+
+GtkApplication *gui_init() {
+  GtkApplication *app = gtk_application_new("org.wafflesoft.NCPSO", G_APPLICATION_DEFAULT_FLAGS);
+  g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
+  return app;
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..3ba6629
--- /dev/null
@@ -0,0 +1,47 @@
+#include "vector.h"
+#include "swarm.h"
+#include "gui.h"
+
+double b0(double *x) {
+  return -x[0];
+}
+
+double b1(double *x) {
+  return -x[1];
+}
+
+double b2(double *x) {
+  return x[0] - 10;
+}
+
+double b3(double *x) {
+  return x[1] - 15;
+}
+
+double f(double *x) {
+  return exp(b0(x)) + exp(b1(x)) + exp(b2(x)) + exp(b3(x)) + x[0] - x[1];
+}
+
+int main(int argc, char *argv[]) {
+  swarm sw = {
+    2,
+    f,
+    100,
+    pow(2, 40),
+    0.8,
+    2.05,
+    2.05
+  };
+  range rrange[2] = {
+    (range) { -100.0, 100.0 },
+    (range) { -100.0, 100.0 }
+  };
+  swarm_populate(&sw, rrange);
+  swarm_optimize(&sw);
+  printf("APSO: converged in x=");
+  vec_print(sw.params.dim, sw.global_best->current.x);
+  printf(" with fitness f(x)=%f\n", sw.global_best->current.fitness);
+  // GtkApplication *app = gui_init();
+  // return g_application_run(G_APPLICATION(app), argc, argv);
+  return 0;
+}
diff --git a/src/particle_swarm.c b/src/particle_swarm.c
deleted file mode 100644 (file)
index 1d574c1..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "particle_swarm.h"
-#include "vector.h"
-#include <gtk/gtk.h>
-
-double c = 2.05;
-double s = 2.05;
-double w = 0.8;
-
-double rands() {
-  return (double) rand() / RAND_MAX;
-}
-
-double randrange(double min, double max) {
-  return rands() * (max - min) + min;
-}
-
-void pick(const int dim, const range *vrange, double *v) {
-  for (int d = 0; d < dim; d++) v[d] = randrange(vrange[d].min, vrange[d].max);
-}
-
-double b0(double *x) {
-  return -x[0];
-}
-
-double b1(double *x) {
-  return -x[1];
-}
-
-double b2(double *x) {
-  return x[0] - 10;
-}
-
-double b3(double *x) {
-  return x[1] - 15;
-}
-
-double f(double *x) {
-  return exp(b0(x)) + exp(b1(x)) + exp(b2(x)) + exp(b3(x)) + x[0] - x[1];
-}
-
-void swarm_init(swarm *sw, const int dim, const range *vrange) {
-  sw->particles = malloc(sizeof(particle) * sw->particlec);
-  sw->global_best = &sw->particles[0];
-  for (int p = 0; p < sw->particlec; p++) {
-    particle *pt = &sw->particles[p];
-    pt->current.x = vec_alloc(dim);
-    pt->best.x = vec_alloc(dim);
-    pt->velocity = vec_alloc(dim);
-    for (int d = 0; d < dim; d++) {
-      pick(dim, vrange, pt->current.x);
-      vec_copy(dim, pt->current.x, pt->best.x);
-    }
-    pt->current.fitness = f(pt->current.x);
-    pt->best.fitness = pt->current.fitness;
-    if (pt->current.fitness < sw->global_best->current.fitness) sw->global_best = pt;
-  }
-}
-
-void swarm_velocity_update(swarm *sw, const int dim) {
-  for (int p = 0; p < sw->particlec; p++) {
-    particle *pt = &sw->particles[p];
-    for (int d = 0; d < dim; d++)
-      pt->velocity[d] = w * pt->velocity[d] + c * rands() * (pt->best.x[d] - pt->current.x[d]) + s * rands() * (sw->global_best->current.x[d] - pt->current.x[d]);
-  }
-  for (int p = 0; p < sw->particlec; p++) {
-    particle *pt = &sw->particles[p];
-    vec_add(dim, pt->velocity, pt->current.x);
-    pt->current.fitness = f(pt->current.x);
-    if (pt->current.fitness < pt->best.fitness) pt->best = pt->current;
-    if (pt->current.fitness < sw->global_best->current.fitness) sw->global_best = &sw->particles[p];
-  }
-}
-
-static void on_activate(GtkApplication *app) {
-  GtkWidget *window = gtk_application_window_new(app);
-  GtkWidget *button = gtk_button_new_with_label("Hello, World!");
-  g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_window_close), window);
-  gtk_window_set_child(GTK_WINDOW(window), button);
-  gtk_window_present(GTK_WINDOW(window));
-}
-
-int main(int argc, char *argv[]) {
-  double eps = pow(2, 40);
-  int dim = 2;
-  int particlec = 100;
-  range vrange[2] = {
-    (range) { -100.0, 100.0 },
-    (range) { -100.0, 100.0 }
-  };
-  swarm sw;
-  sw.particlec = particlec;
-  swarm_init(&sw, dim, vrange);
-  int conv = 0;
-  double best = 0.0;
-  while (conv < 10000) {
-    swarm_velocity_update(&sw, dim);
-    if (fabs(sw.global_best->current.fitness - best) < eps)
-      conv++;
-    else {
-      best = sw.global_best->current.fitness;
-      conv = 0;
-    }
-  }
-  printf("PSO: converged in x=");
-  vec_print(dim, sw.global_best->current.x);
-  printf(" with fitness f(x)=%f\n", sw.global_best->current.fitness);
-
-  GtkApplication *app = gtk_application_new("org.wafflesoft.NCPSO", G_APPLICATION_DEFAULT_FLAGS);
-  g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
-  return g_application_run(G_APPLICATION(app), argc, argv);
-}
diff --git a/src/swarm.c b/src/swarm.c
new file mode 100644 (file)
index 0000000..3fe83ff
--- /dev/null
@@ -0,0 +1,67 @@
+#include <math.h>
+#include <stdlib.h>
+#include "swarm.h"
+#include "vector.h"
+
+double c = 2.05;
+double s = 2.05;
+double w = 0.8;
+
+double rands() {
+  return (double) rand() / RAND_MAX;
+}
+
+double randrange(double min, double max) {
+  return rands() * (max - min) + min;
+}
+
+void pick(const int dim, const range *vrange, double *v) {
+  for (int d = 0; d < dim; d++) v[d] = randrange(vrange[d].min, vrange[d].max);
+}
+
+void swarm_populate(swarm *sw, const range *rrange) {
+  sw->particles = malloc(sizeof(particle) * sw->params.particlec);
+  sw->global_best = &sw->particles[0];
+  for (int p = 0; p < sw->params.particlec; p++) {
+    particle *pt = &sw->particles[p];
+    pt->current.x = vec_alloc(sw->params.dim);
+    pt->best.x = vec_alloc(sw->params.dim);
+    pt->velocity = vec_alloc(sw->params.dim);
+    for (int d = 0; d < sw->params.dim; d++) {
+      pick(sw->params.dim, rrange, pt->current.x);
+      vec_copy(sw->params.dim, pt->current.x, pt->best.x);
+    }
+    pt->current.fitness = sw->params.f(pt->current.x);
+    pt->best.fitness = pt->current.fitness;
+    if (pt->current.fitness < sw->global_best->current.fitness) sw->global_best = pt;
+  }
+}
+
+void swarm_velocity_update(swarm *sw) {
+  for (int p = 0; p < sw->params.particlec; p++) {
+    particle *pt = &sw->particles[p];
+    for (int d = 0; d < sw->params.dim; d++)
+      pt->velocity[d] = w * pt->velocity[d] + c * rands() * (pt->best.x[d] - pt->current.x[d]) + s * rands() * (sw->global_best->current.x[d] - pt->current.x[d]);
+  }
+  for (int p = 0; p < sw->params.particlec; p++) {
+    particle *pt = &sw->particles[p];
+    vec_add(sw->params.dim, pt->velocity, pt->current.x);
+    pt->current.fitness = sw->params.f(pt->current.x);
+    if (pt->current.fitness < pt->best.fitness) pt->best = pt->current;
+    if (pt->current.fitness < sw->global_best->current.fitness) sw->global_best = &sw->particles[p];
+  }
+}
+
+void swarm_optimize(swarm *sw) {
+  int conv = 0;
+  double best = INFINITY;
+  while (conv < 10000) {
+    swarm_velocity_update(sw);
+    if (fabs(sw->global_best->current.fitness - best) < sw->params.eps)
+      conv++;
+    else {
+      best = sw->global_best->current.fitness;
+      conv = 0;
+    }
+  }
+}