diff --git a/quad/computation_graph/src/computation_graph.c b/quad/computation_graph/src/computation_graph.c index 9fb4ffcc82fd4e06eb390fcfd353d7a5bd539960..d64fa753f1e1d287e8bc55717a8f3b7ce6d27435 100644 --- a/quad/computation_graph/src/computation_graph.c +++ b/quad/computation_graph/src/computation_graph.c @@ -4,6 +4,10 @@ #include "computation_graph.h" #define GRAPH_MAX_DEPTH 20 +#define GRAPH_MAX_INPUTS 20 + +// Array to store input values for passing to the execute function of each node +static double exec_input_vals[GRAPH_MAX_INPUTS]; struct computation_graph *create_graph() { struct computation_graph *the_graph = malloc(sizeof(struct computation_graph)); @@ -24,7 +28,7 @@ int graph_set_source(struct computation_graph *graph, } struct graph_node *dest_node = &graph->nodes[dest_cntl_id]; struct graph_node *src_node = &graph->nodes[src_cntl_id]; - if (dest_input >= dest_node->n_inputs || src_output >= src_node->n_outputs) { + if (dest_input >= dest_node->type->n_inputs || src_output >= src_node->type->n_outputs) { return -1; } @@ -34,15 +38,11 @@ int graph_set_source(struct computation_graph *graph, return 0; } -int graph_create_node(struct computation_graph *graph, - const char* name, - const char* const* input_names, - const char* const* output_names, - int n_inputs, - int n_outputs, - execute_node_t exec_func, - reset_node_t reset_func, - void *state) { +int graph_add_node(struct computation_graph *graph, + const char* name, + const struct graph_node_type *type, + void *state) { + assert(type->n_inputs <= GRAPH_MAX_INPUTS); int new_id = graph->n_nodes; if (new_id >= graph->size) { int new_capacity = graph->n_nodes == 0 ? 1 : graph->n_nodes * 2; @@ -55,34 +55,29 @@ int graph_create_node(struct computation_graph *graph, } struct graph_node *new_node = &graph->nodes[new_id]; new_node->name = strdup(name); - new_node->input_names = input_names; - new_node->output_names = output_names; - new_node->output_values = malloc(n_outputs * sizeof(double)); - new_node->input_values = malloc(n_inputs * sizeof(double)); + new_node->type = type; + new_node->output_values = malloc(type->n_outputs * sizeof(double)); + new_node->param_values = malloc(type->n_params * sizeof(double)); new_node->state = state; - new_node->execute = exec_func; - new_node->reset = reset_func; - new_node->n_inputs = n_inputs; - new_node->n_outputs = n_outputs; - new_node->input_srcs = malloc(n_inputs * sizeof(struct input_type)); + new_node->input_srcs = malloc(type->n_inputs * sizeof(struct input_type)); int i; - for (i = 0; i < n_inputs; i++) { + for (i = 0; i < type->n_inputs; i++) { new_node->input_srcs[i].controller_id = -1; } graph->n_nodes += 1; return new_id; } -int graph_set_input_val(struct computation_graph *graph, int node_id, int input_id, double value) { - if (node_id >= graph->n_nodes || input_id >= graph->nodes[node_id].n_inputs) { +int graph_set_param_val(struct computation_graph *graph, int node_id, int param_id, double value) { + if (node_id >= graph->n_nodes || param_id >= graph->nodes[node_id].type->n_params) { return -1; } - graph->nodes[node_id].input_values[input_id] = value; + graph->nodes[node_id].param_values[param_id] = value; return 0; } double graph_get_output(const struct computation_graph *graph, int node_id, int output_id) { - if (node_id >= graph->n_nodes || output_id >= graph->nodes[node_id].n_outputs) { + if (node_id >= graph->n_nodes || output_id >= graph->nodes[node_id].type->n_outputs) { return -1; } return graph->nodes[node_id].output_values[output_id]; @@ -96,22 +91,23 @@ void graph_compute_node_rec(struct computation_graph *graph, int node_id, int de if (node_id >= graph->n_nodes) { return; } + // TODO: Fix self-reference loop struct graph_node *node = &graph->nodes[node_id]; if (node->processed_state == PROCESSED) { return; } int input_id; - for (input_id = 0; input_id < node->n_inputs; input_id++) { + for (input_id = 0; input_id < node->type->n_inputs; input_id++) { int src_cntl_id = node->input_srcs[input_id].controller_id; if (src_cntl_id != -1) { if (graph->nodes[src_cntl_id].processed_state == UNPROCESSED) { graph_compute_node_rec(graph, src_cntl_id, depth + 1); } int src_output_id = node->input_srcs[input_id].controller_output; - node->input_values[input_id] = graph->nodes[src_cntl_id].output_values[src_output_id]; + exec_input_vals[input_id] = graph->nodes[src_cntl_id].output_values[src_output_id]; } } - (*node->execute)(node->state, node->input_values, node->output_values); + (*node->type->execute)(node->state, node->param_values, exec_input_vals, node->output_values); node->processed_state = PROCESSED; } @@ -130,22 +126,24 @@ int export_dot(const struct computation_graph* graph, FILE* of) { int i; for (i = 0; i < graph->n_nodes; i++) { struct graph_node *node = &graph->nodes[i]; - // Separate node and inputs as a cluster - fprintf(of, "subgraph cluster_%d {\n", i); // Create node - fprintf(of, "\"%s\"\n", node->name); - // Draw inputs to graph + fprintf(of, "\"%s\"[label=\"", node->name); + fprintf(of, "Name: %s\n", node->name); // Node name first int j; - for (j = 0; j < node->n_inputs; j++) { - // Block for input to node - fprintf(of, "\"%s[%s]\"[shape=box]\n", node->name, node->input_names[j]); - // Link inputs to node - fprintf(of, "\"%s[%s]\" -> \"%s\"[label=\"%.3f\"]\n", node->name, node->input_names[j], node->name, - node->input_values[j]); + // Add parameters as labels + for (j = 0; j < node->type->n_params; j++) { + fprintf(of, "%s=%.3f\n", node->type->param_names[j], node->param_values[j]); + } + fprintf(of, "\"]\n"); // Close label bracket + // + for (j = 0; j < node->type->n_inputs; j++) { + struct graph_node* src_node = &graph->nodes[node->input_srcs[j].controller_id]; + int output_id = node->input_srcs[j].controller_output; + const char* output_name = src_node->type->output_names[output_id]; + fprintf(of, "\"%s\" -> \"%s\" [label=\"%s=%.3f\"]\n", src_node->name, node->name, output_name, src_node->output_values[output_id]); } - fprintf(of, "}\n"); // Close cluster } - + /* // Draw the links between nodes for (i = 0; i < graph->n_nodes; i++) { struct graph_node *node = &graph->nodes[i]; @@ -161,7 +159,7 @@ int export_dot(const struct computation_graph* graph, FILE* of) { } } } - - fprintf(of, "}"); // Close graph + */ + fprintf(of, "}"); // Close graph1 return 0; } \ No newline at end of file diff --git a/quad/computation_graph/src/computation_graph.h b/quad/computation_graph/src/computation_graph.h index 18c7930d1b666c63578e8fee9f4d4699d23f07bd..301187cf4ee8b59c5c01f921e856a03e89fb4732 100644 --- a/quad/computation_graph/src/computation_graph.h +++ b/quad/computation_graph/src/computation_graph.h @@ -3,7 +3,10 @@ #include <stdio.h> -typedef void (*execute_node_t)(void *state, const double *inputs, double *outputs); +typedef void (*execute_node_t)(void *state, + const double* params, + const double *inputs, + double *outputs); typedef void (*reset_node_t)(void *state); @@ -19,17 +22,25 @@ struct computation_graph { struct graph_node *nodes; }; -struct graph_node { - char *name; - const char* const *input_names; - const char* const *output_names; - double *output_values; - double *input_values; +// Declares a node type +struct graph_node_type { + const char* const* input_names; + const char* const* output_names; + const char* const* param_names; int n_inputs; int n_outputs; - void *state; + int n_params; execute_node_t execute; reset_node_t reset; +}; + +// Declares an instance of a node +struct graph_node { + const char *name; + const struct graph_node_type* type; + double *output_values; + double *param_values; + void *state; int processed_state; struct input_type { int controller_id; @@ -41,19 +52,14 @@ struct computation_graph *create_graph(); int graph_set_source(struct computation_graph *graph, int dest_cntl, int dest_input, int src_cntl, int src_output); -int graph_create_node(struct computation_graph *graph, - const char* name, - const char* const *input_names, - const char* const *output_names, - int n_inputs, - int n_outputs, - execute_node_t exec_func, - reset_node_t reset_func, - void *state); +int graph_add_node(struct computation_graph *graph, + const char *name, + const struct graph_node_type *type, + void *state); double graph_get_output(const struct computation_graph *graph, int node_id, int output_id); -int graph_set_input_val(struct computation_graph *graph, int node_id, int input_id, double value); +int graph_set_param_val(struct computation_graph *graph, int node_id, int param_id, double value); void graph_compute_node(struct computation_graph *graph, int node_id); diff --git a/quad/computation_graph/src/main.c b/quad/computation_graph/src/main.c index 19a188ac2374e01c3d1a8f880a105917d35b409e..761a1ac515d36423276fb0908b73a1ffe82567f3 100644 --- a/quad/computation_graph/src/main.c +++ b/quad/computation_graph/src/main.c @@ -1,29 +1,33 @@ #include <stdio.h> #include "computation_graph.h" -#include "node_add2.h" +#include "node_add.h" #include "node_mult.h" +#include "node_constant.h" +#include "node_pow.h" int main() { struct computation_graph *graph = create_graph(); - int add2_id = graph_add_node_add2(graph, "add1"); - graph_set_input_val(graph, add2_id, ADD2_SUMMAND1, 3); - graph_set_input_val(graph, add2_id, ADD2_SUMMAND2, 2); - int add3_id = graph_add_node_add2(graph, "add2"); - graph_set_input_val(graph, add3_id, ADD2_SUMMAND2, 5); - graph_set_source(graph, add3_id, ADD2_SUMMAND1, add2_id, ADD2_SUM); + int const1 = graph_add_node_const(graph, "Const 1"); + graph_set_param_val(graph, const1, CONST_SET, 2); + int const2 = graph_add_node_const(graph, "Const 2"); + graph_set_param_val(graph, const2, CONST_SET, 3); - int mult1_id = graph_add_node_mult(graph, "mult"); - graph_set_source(graph, mult1_id, MULT_MULTIPLICAND1, add2_id, ADD2_SUM); - graph_set_source(graph, mult1_id, MULT_MULTIPLICAND2, add3_id, ADD2_SUM); + int add1_id = graph_add_node_add(graph, "Add"); + graph_set_source(graph, add1_id, ADD_SUMMAND1, const1, CONST_VAL); + graph_set_source(graph, add1_id, ADD_SUMMAND2, const2, CONST_VAL); - graph_compute_node(graph, mult1_id); + int pow1_id = graph_add_node_pow(graph, "Pow"); + graph_set_param_val(graph, pow1_id, POW_EXP, 3); + graph_set_source(graph, pow1_id, POW_BASE, add1_id, ADD_SUM); + + graph_compute_node(graph, pow1_id); FILE* dot_fp; dot_fp = fopen("..\\comp_graph.dot", "w"); export_dot(graph, dot_fp); fclose(dot_fp); - printf("Sum is %f\n", graph_get_output(graph, mult1_id, ADD2_SUM)); + printf("Sum is %f\n", graph_get_output(graph, pow1_id, POW_RESULT)); fflush(stdout); return 0; } diff --git a/quad/computation_graph/src/node_add.c b/quad/computation_graph/src/node_add.c new file mode 100644 index 0000000000000000000000000000000000000000..a28ca657b6ebe25838806b8369c1669aefb99323 --- /dev/null +++ b/quad/computation_graph/src/node_add.c @@ -0,0 +1,25 @@ +#include "node_add.h" +#include <stdlib.h> + +static void add_nodes(void *state, const double* params, const double *inputs, double *outputs) { + outputs[ADD_SUM] = inputs[ADD_SUMMAND1] + inputs[ADD_SUMMAND2]; +} +static void reset(void *state) {} + +static const char* const in_names[2] = {"Summand 1", "Summand 2"}; +static const char* const out_names[1] = {"Sum"}; +static const char* const param_names[0] = {}; +const struct graph_node_type node_add_type = { + .input_names = in_names, + .output_names = out_names, + .param_names = param_names, + .n_inputs = 2, + .n_outputs = 1, + .n_params = 0, + .execute = add_nodes, + .reset = reset +}; + +int graph_add_node_add(struct computation_graph *graph, const char* name) { + return graph_add_node(graph, name, &node_add_type, NULL); +} diff --git a/quad/computation_graph/src/node_add.h b/quad/computation_graph/src/node_add.h new file mode 100644 index 0000000000000000000000000000000000000000..5c90ea16cfd390e126a600415e4e173bf5076943 --- /dev/null +++ b/quad/computation_graph/src/node_add.h @@ -0,0 +1,17 @@ +#ifndef __NODE_ADD_H__ +#define __NODE_ADD_H__ +#include "computation_graph.h" + +int graph_add_node_add(struct computation_graph *graph, const char* name); + +const extern struct graph_node_type node_add_type; + +enum graph_node_add_inputs { + ADD_SUMMAND1, + ADD_SUMMAND2, +}; + +enum graph_node_add_outputs { + ADD_SUM +}; +#endif // __NODE_ADD_H__ \ No newline at end of file diff --git a/quad/computation_graph/src/node_add2.c b/quad/computation_graph/src/node_add2.c deleted file mode 100644 index 62c9c1a844a5ab66f027df76af411e412c056466..0000000000000000000000000000000000000000 --- a/quad/computation_graph/src/node_add2.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "node_add2.h" -#include <stdlib.h> - -static const char* const in_names[2] = {"Summand 1", "Summand 2"}; -static const char* const out_names[1] = {"Sum"}; - -static void add_nodes(void *state, const double *inputs, double *outputs) { - outputs[ADD2_SUM] = inputs[ADD2_SUMMAND1] + inputs[ADD2_SUMMAND2]; -} - -static void reset(void *state) {} - -int graph_add_node_add2(struct computation_graph *graph, const char* name) { - return graph_create_node(graph, name, in_names, out_names, 2, 1, &add_nodes, &reset, NULL); -} diff --git a/quad/computation_graph/src/node_add2.h b/quad/computation_graph/src/node_add2.h deleted file mode 100644 index ba2d3e0e03043fb50e6c537d660bee4a63ece79a..0000000000000000000000000000000000000000 --- a/quad/computation_graph/src/node_add2.h +++ /dev/null @@ -1,12 +0,0 @@ -#include "computation_graph.h" - -int graph_add_node_add2(struct computation_graph *graph, const char* name); - -enum graph_node_add2_inputs { - ADD2_SUMMAND1, - ADD2_SUMMAND2 -}; - -enum graph_node_add2_outputs { - ADD2_SUM -}; diff --git a/quad/computation_graph/src/node_constant.c b/quad/computation_graph/src/node_constant.c new file mode 100644 index 0000000000000000000000000000000000000000..47ab571d5636d45c7e27ff3d47c45f3e7f305e38 --- /dev/null +++ b/quad/computation_graph/src/node_constant.c @@ -0,0 +1,25 @@ +#include "node_constant.h" +#include <stdlib.h> + +static void output_const(void *state, const double *params, const double *inputs, double *outputs) { + outputs[CONST_VAL] = params[CONST_SET]; +} +static void reset(void *state) {} + +static const char* const in_names[0] = {}; +static const char* const out_names[1] = {"Constant"}; +static const char* const param_names[1] = {"Constant"}; +const struct graph_node_type node_const_type = { + .input_names = in_names, + .output_names = out_names, + .param_names = param_names, + .n_inputs = 0, + .n_outputs = 1, + .n_params = 1, + .execute = output_const, + .reset = reset +}; + +int graph_add_node_const(struct computation_graph *graph, const char* name) { + return graph_add_node(graph, name, &node_const_type, NULL); +} diff --git a/quad/computation_graph/src/node_constant.h b/quad/computation_graph/src/node_constant.h new file mode 100644 index 0000000000000000000000000000000000000000..67acbc2d733393bb12af640bb34ff3e99b344150 --- /dev/null +++ b/quad/computation_graph/src/node_constant.h @@ -0,0 +1,16 @@ +#ifndef __NODE_CONSTANT_H__ +#define __NODE_CONSTANT_H__ +#include "computation_graph.h" + +int graph_add_node_const(struct computation_graph *graph, const char* name); + +const extern struct graph_node_type node_const_type; + +enum graph_node_const_params { + CONST_SET +}; + +enum graph_node_const_outputs { + CONST_VAL +}; +#endif //__NODE_CONSTANT_H__ \ No newline at end of file diff --git a/quad/computation_graph/src/node_mult.c b/quad/computation_graph/src/node_mult.c index cc4a1b21db51a9f806d33b0b6af2d0c162bf24a1..b727249f62a3fda1dba8aca5701c50868c5aa550 100644 --- a/quad/computation_graph/src/node_mult.c +++ b/quad/computation_graph/src/node_mult.c @@ -1,15 +1,25 @@ #include "node_mult.h" #include <stdlib.h> -static const char* const in_names[2] = {"Multiplicand 1", "Multiplicand 2"}; -static const char* const out_names[1] = {"Product"}; - -static void mult_nodes(void *state, const double *inputs, double *outputs) { +static void mult_nodes(void *state, const double* params, const double *inputs, double *outputs) { outputs[MULT_PRODUCT] = inputs[MULT_MULTIPLICAND1] * inputs[MULT_MULTIPLICAND2]; } - static void reset(void *state) {} +static const char* const in_names[2] = {"Multiplicand 1", "Multiplicand 2"}; +static const char* const out_names[1] = {"Product"}; +static const char* const param_names[0] = {}; +const struct graph_node_type node_mult_type = { + .input_names = in_names, + .output_names = out_names, + .param_names = param_names, + .n_inputs = 2, + .n_outputs = 1, + .n_params = 0, + .execute = mult_nodes, + .reset = reset +}; + int graph_add_node_mult(struct computation_graph *graph, const char* name) { - return graph_create_node(graph, name, in_names, out_names, 2, 1, &mult_nodes, &reset, NULL); + return graph_add_node(graph, name, &node_mult_type, NULL); } diff --git a/quad/computation_graph/src/node_mult.h b/quad/computation_graph/src/node_mult.h index 744bf85f08ddd35238ed624f496cf18aa62a1ffa..39b37cd59f0dbb20516be1983d5c86c2291ca49d 100644 --- a/quad/computation_graph/src/node_mult.h +++ b/quad/computation_graph/src/node_mult.h @@ -1,12 +1,18 @@ +#ifndef __NODE_MULT_H__ +#define __NODE_MULT_H__ #include "computation_graph.h" int graph_add_node_mult(struct computation_graph *graph, const char* name); +const extern struct graph_node_type node_mult_type; + enum graph_node_mult_inputs { MULT_MULTIPLICAND1, - MULT_MULTIPLICAND2 + MULT_MULTIPLICAND2, }; enum graph_node_mult_outputs { MULT_PRODUCT }; + +#endif // __NODE_MULT_H__ \ No newline at end of file diff --git a/quad/computation_graph/src/node_pow.c b/quad/computation_graph/src/node_pow.c new file mode 100644 index 0000000000000000000000000000000000000000..2e817fc39d8bc227b7d876ad98f7f3c40bd03448 --- /dev/null +++ b/quad/computation_graph/src/node_pow.c @@ -0,0 +1,26 @@ +#include "node_pow.h" +#include <stdlib.h> +#include <math.h> + +static void pow_nodes(void *state, const double* params, const double *inputs, double *outputs) { + outputs[POW_RESULT] = pow(inputs[POW_BASE], params[POW_EXP]); +} +static void reset(void *state) {} + +static const char* const in_names[1] = {"Base"}; +static const char* const out_names[1] = {"Result"}; +static const char* const param_names[1] = {"Exponent"}; +const struct graph_node_type node_pow_type = { + .input_names = in_names, + .output_names = out_names, + .param_names = param_names, + .n_inputs = 1, + .n_outputs = 1, + .n_params = 1, + .execute = pow_nodes, + .reset = reset +}; + +int graph_add_node_pow(struct computation_graph *graph, const char* name) { + return graph_add_node(graph, name, &node_pow_type, NULL); +} diff --git a/quad/computation_graph/src/node_pow.h b/quad/computation_graph/src/node_pow.h new file mode 100644 index 0000000000000000000000000000000000000000..be98299548aaf5147687e4c248383038d1d56f14 --- /dev/null +++ b/quad/computation_graph/src/node_pow.h @@ -0,0 +1,20 @@ +#ifndef __NODE_POW_H__ +#define __NODE_POW_H__ +#include "computation_graph.h" + +int graph_add_node_pow(struct computation_graph *graph, const char* name); + +const extern struct graph_node_type node_pow_type; + +enum graph_node_pow_inputs { + POW_BASE +}; + +enum graph_node_pow_params { + POW_EXP +}; + +enum graph_node_add2_outputs { + POW_RESULT +}; +#endif // __NODE_POW_H__ \ No newline at end of file