task: readstream append 0-byte, score passing fixed
authorametama <ametama@wafflesoft.org>
Mon, 2 Feb 2026 20:44:25 +0000 (21:44 +0100)
committerametama <ametama@wafflesoft.org>
Mon, 2 Feb 2026 20:44:25 +0000 (21:44 +0100)
Makefile
include/def.h
src/main.c
test.ch [deleted file]

index 719aad98c0212a0c45e683e6ae7f9f3d0631af58..3cce430ba16abf26380705247e4647ffd173e3f5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ compile_flags:
        echo "-Iinclude -lcgo -lm -fopenmp" | perl -pe 's|(-.*?)\s|\1\n|g' > compile_flags.txt
 
 executable: $(wildcard src/*.c)
-       gcc $(shell cat compile_flags.txt) -o ngsolve $(shell ls src/*.c)
+       gcc $(shell ls src/*.c) $(shell cat compile_flags.txt) -o ngsolve
 
 clear:
        rm -f compile_flags.txt
index 7cd100ce8692f32532685b7320f8d48b730945e6..4395857772f6bbc2c9e32af9f5645df0cb76f1d4 100644 (file)
@@ -14,7 +14,5 @@ typedef struct {
     char *netlist;
     int agentc;
     int dvarc;
-    int mvarc;
     design_var *dvars;
-    measure_var *mvars;
 } task_def;
index 528b74f369f5205471b7597479cabbfa6257d3a2..42ab57db37ceb86bafe9e8bae992b98613ca48f8 100644 (file)
@@ -2,25 +2,26 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <cgo.h>
 #include "argph.h"
 #include "def.h"
 
 typedef struct {
     pid_t pid;
-    int input_read;
-    int input_write;
-    int output_read;
-    int output_write;
+    int input[2];
+    int output[2];
 } ngspice_process;
 
 task_def taskg;
 
+// ngspice .func replacements have some undesirable
+// behaviours, gcc macros used instead.
 char *macros = \
     "#define Minimize(expr) let __ngsolve_f=__ngsolve_f+expr\n"
-    "#define Maximize(expr) Minimize(-expr)\n"
+    "#define Maximize(expr) let __ngsolve_f=__ngsolve_f-(expr)\n"
     "#define Constrain(expr) let __ngsolve_c=__ngsolve_c+expr\n"
-    "#define Lt(a, b) max(exp(a - b) - 1, 0)\n"
+    "#define Lt(a, b) Constrain(max(0, exp(a - b) - 1))\n"
     "#define Gt(a, b) Lt(b, a)\n"
     "#define Band(v, lo, hi) Lt(lo, v) + Lt(v, hi)\n";
 
@@ -38,18 +39,23 @@ char *readfile(FILE *f) {
 
 char *readstream(int fd) {
     int s = 128;
+    int r;
     char *buf = malloc(s * 2);
-    if (read(fd, buf, s) != s) return buf;
+    if ((r = read(fd, buf, s)) != s) {
+        *(buf + r) = 0;
+        return buf;
+    };
     char *pos = buf + s;
-    while (read(fd, pos, s) == s) {
+    while ((r = read(fd, pos, s)) == s) {
         buf = realloc(buf, (s *= 2) * 2);
         pos = buf + s;
     }
+    *(pos + r) = 0;
     return buf;
 }
 
 void load_netlist(task_def *task) {
-    FILE *netlist = fopen(taskg.netlist_file, "r");
+    FILE *netlist = fopen( task->netlist_file, "r");
     char *netlist_raw = readfile(netlist);
     fclose(netlist);
     int in[2];
@@ -62,7 +68,7 @@ void load_netlist(task_def *task) {
         close(out[0]);
         dup2(in[0], STDIN_FILENO);
         dup2(out[1], STDOUT_FILENO);
-        if (execlp("gcc", "gcc", "-E", "-P", "-x", "c", "-", NULL)) {
+        if (execlp("gcc", "gcc", "-E", "-P", "-x", "c", "/dev/fd/0", NULL)) {
             printf("ngsolve: FATAL EXCEPTION\n    gcc invocation unsuccessful. Check that a working binary is added to PATH as `gcc`.");
             exit(1);
         }
@@ -77,41 +83,44 @@ void load_netlist(task_def *task) {
 }
 
 void spawn_ngspice(ngspice_process *chp) {
-    if (pipe(&chp->input_read) || pipe(&chp->output_read)) {
+    if (pipe(chp->input) || pipe(chp->output)) {
         printf("ngsolve: FATAL EXCEPTION\n    pipe creation unsuccessful.");
         exit(1);
     }
     pid_t p = fork();
     if (!p) {
-        close(chp->input_write);
-        close(chp->output_read);
-        // STDOUT is not linked to chp->output_write as this
-        // would pollute the pipe with ngspice logs.
-        dup2(chp->input_read, STDIN_FILENO);
+        int null_fd = open("/dev/null", O_WRONLY);
+        close(chp->input[1]);
+        close(chp->output[0]);
+        dup2(chp->input[0], STDIN_FILENO);
+        dup2(null_fd, STDOUT_FILENO);
+        dup2(null_fd, STDERR_FILENO);
         // Convert to an ngspice process;
         // execlp does not (!) return to caller if successful.
-        if (execlp("ngspice", "ngspice", "<&0", NULL)) {
+        if (execlp("ngspice", "ngspice", "-b", "/dev/fd/0", NULL)) {
             printf("ngsolve: FATAL EXCEPTION\n    ngspice invocation unsuccessful. Check that a working binary is added to PATH as `ngspice`.");
             exit(1);
         }
     }
-    close(chp->input_read);
-    close(chp->output_write);
+    close(chp->input[0]);
+    close(chp->output[1]);
     chp->pid = p;
 }
 
 double fitness(double *x) {
     ngspice_process chp;
     spawn_ngspice(&chp);
-    dprintf(chp.input_write, "ngsolve\n");
+    dprintf(chp.input[1], "ngsolve\n\n.CONTROL\nlet __ngsolve_f=0\nlet __ngsolve_c=0\n.ENDC\n");
     for (size_t d = 0; d < taskg.dvarc; d++)
-        dprintf(chp.input_write, ".PARAM %s=%f\n", taskg.dvars[d].symbol, x[d]);
+        // .PARAM lines are used by circuit definition but cannot be used in
+        // .CONTROL blocks. .CSPARAM lines vice-versa (therefore both necessary).
+        dprintf(chp.input[1], ".PARAM %s=%f\n.CSPARAM %s=%s\n", taskg.dvars[d].symbol, x[d], taskg.dvars[d].symbol, taskg.dvars[d].symbol);
     // Note: ngspice manual specifies input files have to end on ".END\n".
     // This seems to not be enforced, so this control statement can be appended after it.
-    dprintf(chp.input_write, "*%s\n.CONTROL\necho \"$&__ngsolve_c $&__ngsolve_f\" >&%d\nexec %d>&-\n.ENDC\n", taskg.netlist, chp.output_write, chp.output_write);
-    close(chp.input_write);  // Done writing (writes EOF to ngspice on chp.input_write).
-    char *outp = readstream(chp.output_read);
-    close(chp.output_read);
+    dprintf(chp.input[1], "*%s\n.CONTROL\necho \"$&__ngsolve_c $&__ngsolve_f\" >> /dev/fd/%d\n.ENDC\n.END\n", taskg.netlist, chp.output[1]);
+    close(chp.input[1]);  // Done writing (writes EOF to ngspice on chp.input_write).
+    char *outp = readstream(chp.output[0]);
+    close(chp.output[0]);
     char *pos = outp;
     double constraints = strtod(pos, &pos);
     double fitness = strtod(pos, &pos);
@@ -121,32 +130,49 @@ double fitness(double *x) {
     return constraints + fitness;
 }
 
-void optimize() {
-    double *sample_range_min = malloc(sizeof(double) * taskg.dvarc);
-    double *sample_range_max = malloc(sizeof(double) * taskg.dvarc);
-    for (size_t d = 0; d < taskg.dvarc; d++) {
-        sample_range_min[d] = taskg.dvars[d].sample_min;
-        sample_range_max[d] = taskg.dvars[d].sample_max;
+void optimize(task_def *task) {
+    double *sample_range_min = malloc(sizeof(double) * task->dvarc);
+    double *sample_range_max = malloc(sizeof(double) * task->dvarc);
+    for (size_t d = 0; d < task->dvarc; d++) {
+        sample_range_min[d] = task->dvars[d].sample_min;
+        sample_range_max[d] = task->dvars[d].sample_max;
     }
-    load_netlist(&taskg);
     cgo_de_parameters par = {
-        taskg.dvarc,
-        taskg.agentc,
+        task->dvarc,
+        task->agentc,
         sample_range_min,
         sample_range_max,
         fitness,
         0.9,
         0.8
     };
-    double *res = malloc(sizeof(double) * taskg.dvarc);
+    double *res = malloc(sizeof(double) * task->dvarc);
     cgo_de(&par, res);
     printf("ngsolve: converged at x=(");
-    for (size_t d = 0; d < taskg.dvarc - 1; d++) printf("%s=%f, ", taskg.dvars[d].symbol, res[d]);
-    printf("%s=%f) with f(x)=%f\n", taskg.dvars[taskg.dvarc - 1].symbol, res[taskg.dvarc - 1], fitness(res));
+    for (size_t d = 0; d < task->dvarc - 1; d++) printf("%s=%f, ", task->dvars[d].symbol, res[d]);
+    printf("%s=%f) with f(x)=%f\n", task->dvars[task->dvarc - 1].symbol, res[task->dvarc - 1], fitness(res));
 }
 
 int main(int argc, char *argv[]) {
     struct arguments args;
     argp_parse(&argp, argc, argv, 0, 0, &args);
+    design_var dvars[] = {
+        {
+            "a",
+            -10,
+            10
+        },
+        {
+            "b",
+            -10,
+            10
+        }
+    };
+    taskg.netlist_file = "test.ngs";
+    taskg.agentc = 10;
+    taskg.dvarc = 2;
+    taskg.dvars = dvars;
+    load_netlist(&taskg);
+    optimize(&taskg);
     return 0;
 }
diff --git a/test.ch b/test.ch
deleted file mode 100644 (file)
index fb348f3..0000000
--- a/test.ch
+++ /dev/null
@@ -1,3 +0,0 @@
-#define A 123
-
-A