#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <cgo.h>
#include "argph.h"
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;
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;
}
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[]) {