feat: differential evolution optimizer
authorametama <ametama@wafflesoft.org>
Thu, 15 Jan 2026 02:50:32 +0000 (03:50 +0100)
committerametama <ametama@wafflesoft.org>
Thu, 15 Jan 2026 02:50:32 +0000 (03:50 +0100)
include/de.h [new file with mode: 0644]
src/de.c [new file with mode: 0644]
src/main.c

diff --git a/include/de.h b/include/de.h
new file mode 100644 (file)
index 0000000..cb95e53
--- /dev/null
@@ -0,0 +1,12 @@
+#include "swarm.h"
+
+typedef struct {
+  int dim;
+  int particlec;
+  range *rrange;
+  double (*f)(double*);  // fitness function
+  double cr;             // crossover probability = .9
+  double dw;             // differential weight   = .8
+} de_parameters;
+
+void de_optimize(de_parameters *par, double *res);
diff --git a/src/de.c b/src/de.c
new file mode 100644 (file)
index 0000000..8377787
--- /dev/null
+++ b/src/de.c
@@ -0,0 +1,43 @@
+#include <stdlib.h>
+#include "vector.h"
+#include "de.h"
+
+void de_optimize(de_parameters *par, double *res) {
+    int l = par->particlec * par->dim;
+    double *mem = malloc(sizeof(double) * l * 2);
+    int conv = 0;
+    double *xs = mem;
+    double *ys = mem + l;
+    for (double *x = xs; x < ys; x += par->dim)
+        vec_pick(par->dim, par->rrange, x);
+    while (conv < 1000) {
+        for (double *x = xs; x < ys; x += par->dim) {
+            double *y = x + l;
+            double *picks[4] = { x };  // agents { x, a, b, c }
+            for (int i = 1; i < 4; i++) {
+                double *pick = xs + (rand() % (par->particlec - i));
+                picks[i] = pick;
+                for (int k = 0; k < i; k++)
+                    if (pick >= picks[k]) picks[i]++;
+            }
+            int r = rand() % par->dim;
+            for (int i = 0; i < par->dim; i++) {
+                if (i == r || rands() < par->cr) y[i] = picks[1][i] + par->dw * (picks[2][i] - picks[3][i]);
+                else y[i] = x[i];
+            }
+            if (par->f(y) <= par->f(x)) vec_copy(par->dim, y, x);
+            else conv++;
+        }
+    }
+    double *best = xs;
+    double bestf = par->f(best);
+    for (double *x = xs; x < ys; x += par->dim) {
+        double cur = par->f(x);
+        if (cur < bestf) {
+            best = x;
+            bestf = cur;
+        }
+    }
+    vec_copy(par->dim, best, res);
+    free(mem);
+}
index 430874c586d4551f7cf0d9fa24ffff8038cf57f6..c56f59003f214ed7c9653527eed13ce3560ce522 100644 (file)
@@ -1,7 +1,7 @@
 #include <math.h>
 #include <stdio.h>
 #include "vector.h"
-#include "swarm.h"
+#include "de.h"
 
 double b0(double *x) {
   return -x[0];
@@ -28,6 +28,7 @@ int main(int argc, char *argv[]) {
     (range) { -100.0, 100.0 },
     (range) { -100.0, 100.0 }
   };
+  /*
   swarm_parameters par = {
     2,
     100,
@@ -38,11 +39,22 @@ int main(int argc, char *argv[]) {
     2.05,
     2.05
   };
-  particle_state best = { vec_alloc(par.dim), 0.0 };
-  swarm_optimize(&par, &best);
+  */
+  de_parameters par = {
+    2,
+    100,
+    rrange,
+    f,
+    0.9,
+    0.8
+  };
+  // particle_state best = { vec_alloc(par.dim), 0.0 };
+  double res[2];
+  //swarm_optimize(&par, &best);
+  de_optimize(&par, res);
   printf("apso: converged in x=");
-  vec_print(par.dim, best.x);
-  printf(" with fitness f(x)=%f\n", best.fitness);
+  vec_print(par.dim, res);
+  printf(" with fitness f(x)=%f\n", f(res));
   // GtkApplication *app = gui_init();
   // return g_application_run(G_APPLICATION(app), argc, argv);
   return 0;