--- /dev/null
+#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 };
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.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;
+} 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;
+}