From 2eb21f6ce137e7d8994d81d1a2a73df197de899c Mon Sep 17 00:00:00 2001 From: ametama Date: Fri, 30 Jan 2026 23:59:14 +0100 Subject: [PATCH 1/1] initial commit --- .gitignore | 4 ++ Makefile | 15 ++++++++ include/argph.h | 4 ++ include/def.h | 20 ++++++++++ src/argp.c | 17 +++++++++ src/main.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 158 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 include/argph.h create mode 100644 include/def.h create mode 100644 src/argp.c create mode 100644 src/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c04976 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +compile_flags.txt +ngsolve +test.c +test.ngs diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..719aad9 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +build: compile_flags executable + +#compile_flags_gtk: +# echo "-Iinclude `pkg-config --cflags gtk4` -lm -fopenmp `pkg-config --libs gtk4`" | perl -pe 's|(-.*?)\s|\1\n|g' > compile_flags.txt +# echo "-o cgo" >> compile_flags.txt + +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) + +clear: + rm -f compile_flags.txt + rm -f extspice diff --git a/include/argph.h b/include/argph.h new file mode 100644 index 0000000..b574471 --- /dev/null +++ b/include/argph.h @@ -0,0 +1,4 @@ +#include + +struct arguments {}; +static struct argp argp; diff --git a/include/def.h b/include/def.h new file mode 100644 index 0000000..7cd100c --- /dev/null +++ b/include/def.h @@ -0,0 +1,20 @@ +typedef struct { + char *symbol; + double sample_min; + double sample_max; +} design_var; + +typedef struct { + char *symbol; + char *expr; +} measure_var; + +typedef struct { + char *netlist_file; + char *netlist; + int agentc; + int dvarc; + int mvarc; + design_var *dvars; + measure_var *mvars; +} task_def; diff --git a/src/argp.c b/src/argp.c new file mode 100644 index 0000000..54f7870 --- /dev/null +++ b/src/argp.c @@ -0,0 +1,17 @@ +#include "argph.h" + +static char doc[] = "ngsolve: ngspice optimizer"; +static char args_doc[] = "FILE"; +static struct argp_option options[] = {}; +static error_t parse_opt(int key, char *arg, struct argp_state *state) { + struct arguments *args = state->input; + switch (key) { + case ARGP_KEY_END: + if (state->arg_num > 0) argp_usage(state); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} +static struct argp argp = { options, parse_opt, args_doc, doc }; diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ecc6bb2 --- /dev/null +++ b/src/main.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include "argph.h" +#include "def.h" + +typedef struct { + pid_t pid; + int input_read; + int input_write; + int output_read; + int output_write; +} child_process; + +task_def task; + +char *readfile(FILE *f) { + if (f == NULL) return NULL; + int c; + char *str; + fseek(f, 0, SEEK_END); + long f_size = ftell(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; +} + +void spawn_ngspice(child_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. + dup2(chp->input_read, STDIN_FILENO); + // Convert to an ngspice process; + // execlp does not (!) return to caller. + 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. + chp->pid = p; +} + +double fitness(double *x) { + child_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); + close(chp.input_write); // Done writing (writes EOF to ngspice on chp.input_write). + // TODO: read measurements and build fitness from constraints and objectives. +} + +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; + } + FILE *netlist = fopen(task.netlist_file, "r"); + task.netlist = readfile(netlist); + fclose(netlist); + cgo_de_parameters par = { + task.dvarc, + task.agentc, + sample_range_min, + sample_range_max, + fitness, + 0.9, + 0.8 + }; + double *res = malloc(sizeof(double) * task.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)); +} + +int main(int argc, char *argv[]) { + struct arguments args; + argp_parse(&argp, argc, argv, 0, 0, &args); + return 0; +} -- 2.34.1