task: netlist preprocessing, reading of design score
authorametama <ametama@wafflesoft.org>
Mon, 2 Feb 2026 01:39:20 +0000 (02:39 +0100)
committerametama <ametama@wafflesoft.org>
Mon, 2 Feb 2026 01:39:20 +0000 (02:39 +0100)
src/main.c
test.ch [new file with mode: 0644]

index 88066d0cd4e011b3b22107195cd5ea70fa9228fb..528b74f369f5205471b7597479cabbfa6257d3a2 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <cgo.h>
 #include "argph.h"
@@ -11,9 +12,17 @@ typedef struct {
     int input_write;
     int output_read;
     int output_write;
-} child_process;
+} ngspice_process;
 
-task_def task;
+task_def taskg;
+
+char *macros = \
+    "#define Minimize(expr) let __ngsolve_f=__ngsolve_f+expr\n"
+    "#define Maximize(expr) Minimize(-expr)\n"
+    "#define Constrain(expr) let __ngsolve_c=__ngsolve_c+expr\n"
+    "#define Lt(a, b) max(exp(a - b) - 1, 0)\n"
+    "#define Gt(a, b) Lt(b, a)\n"
+    "#define Band(v, lo, hi) Lt(lo, v) + Lt(v, hi)\n";
 
 char *readfile(FILE *f) {
     if (f == NULL) return NULL;
@@ -24,7 +33,6 @@ char *readfile(FILE *f) {
     fseek(f, 0, SEEK_SET);
     str = malloc(f_size + 1);
     for (size_t i = 0; i < f_size; i++) str[i] = (char) fgetc(f);
-    str[f_size] = '\0';
     return str;
 }
 
@@ -40,78 +48,101 @@ char *readstream(int fd) {
     return buf;
 }
 
-void spawn_ngspice(child_process *chp) {
+void load_netlist(task_def *task) {
+    FILE *netlist = fopen(taskg.netlist_file, "r");
+    char *netlist_raw = readfile(netlist);
+    fclose(netlist);
+    int in[2];
+    int out[2];
+    pipe(in);
+    pipe(out);
+    pid_t p = fork();
+    if (!p) {
+        close(in[1]);
+        close(out[0]);
+        dup2(in[0], STDIN_FILENO);
+        dup2(out[1], STDOUT_FILENO);
+        if (execlp("gcc", "gcc", "-E", "-P", "-x", "c", "-", NULL)) {
+            printf("ngsolve: FATAL EXCEPTION\n    gcc invocation unsuccessful. Check that a working binary is added to PATH as `gcc`.");
+            exit(1);
+        }
+    }
+    close(in[0]);
+    close(out[1]);
+    dprintf(in[1], "%s\n%s", macros, netlist_raw);
+    free(netlist_raw);
+    close(in[1]);
+    task->netlist = readstream(out[0]);
+    close(out[0]);
+}
+
+void spawn_ngspice(ngspice_process *chp) {
     if (pipe(&chp->input_read) || pipe(&chp->output_read)) {
         printf("ngsolve: FATAL EXCEPTION\n    pipe creation unsuccessful.");
         exit(1);
     }
     pid_t p = fork();
     if (!p) {
-        close(chp->input_write);  // Used by parent.
-        close(chp->output_read);  // Used by parent.
-        // Connect stdin to pipe in parent.
+        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);
         // Convert to an ngspice process;
-        // execlp does not (!) return to caller.
+        // execlp does not (!) return to caller if successful.
         if (execlp("ngspice", "ngspice", "<&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);  // Used by child.
-    close(chp->output_write);  // Used by child.
+    close(chp->input_read);
+    close(chp->output_write);
     chp->pid = p;
 }
 
 double fitness(double *x) {
-    child_process chp;
+    ngspice_process chp;
     spawn_ngspice(&chp);
     dprintf(chp.input_write, "ngsolve\n");
-    for (size_t d = 0; d < task.dvarc; d++)
-        dprintf(chp.input_write, ".PARAM %s=%f\n", task.dvars[d].symbol, x[d]);
-    dprintf(chp.input_write, "%s\n.CONTROL\necho \"", task.netlist);
-    for (size_t d = 0; d < task.mvarc; d++)
-        dprintf(chp.input_write, "$&%s ", task.mvars[d].symbol);
-    dprintf(chp.input_write, "\" >&%d\nexec %d>&-\n.ENDC\n.END\n" /* Done writing (writes EOF to parent on chp.output_write). */, chp.output_write, chp.output_write);
+    for (size_t d = 0; d < taskg.dvarc; d++)
+        dprintf(chp.input_write, ".PARAM %s=%f\n", taskg.dvars[d].symbol, x[d]);
+    // 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).
-    // Measurements are retrieved here to calculate fitness.
-    // Calculating fitness using statements added to the input
-    // to ngspice has been considered but the input language
-    // appears to be too weak or buggy to do this sensibly.
-    double *mvars = malloc(sizeof(double) * task.mvarc);
-    char *mvar_output = readstream(chp.output_read);
-    char *pos = mvar_output;
-    for (int d = 0; d < task.mvarc; d++) mvars[d] = strtod(pos, &pos);
-    free(mvar_output);
-    // TODO: add constraints to task.
-    // TODO: calculate fitness.
-    free(mvars);
+    char *outp = readstream(chp.output_read);
+    close(chp.output_read);
+    char *pos = outp;
+    double constraints = strtod(pos, &pos);
+    double fitness = strtod(pos, &pos);
+    free(outp);
+    // TODO: convert this into first finding valid
+    // area (constraints) and then optimizing for fitness.
+    return constraints + fitness;
 }
 
 void optimize() {
-    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;
+    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;
     }
-    FILE *netlist = fopen(task.netlist_file, "r");
-    task.netlist = readfile(netlist);
-    fclose(netlist);
+    load_netlist(&taskg);
     cgo_de_parameters par = {
-        task.dvarc,
-        task.agentc,
+        taskg.dvarc,
+        taskg.agentc,
         sample_range_min,
         sample_range_max,
         fitness,
         0.9,
         0.8
     };
-    double *res = malloc(sizeof(double) * task.dvarc);
+    double *res = malloc(sizeof(double) * taskg.dvarc);
     cgo_de(&par, res);
     printf("ngsolve: converged at x=(");
-    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));
+    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));
 }
 
 int main(int argc, char *argv[]) {
diff --git a/test.ch b/test.ch
new file mode 100644 (file)
index 0000000..fb348f3
--- /dev/null
+++ b/test.ch
@@ -0,0 +1,3 @@
+#define A 123
+
+A