Skip to content
Snippets Groups Projects
Commit e5355845 authored by dawehr's avatar dawehr
Browse files

Some refactoring, separating node type from node instance. Added parameters,...

Some refactoring, separating node type from node instance. Added parameters, and disabled ability to set inputs.
parent 1d006197
No related branches found
No related tags found
No related merge requests found
Showing with 231 additions and 105 deletions
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
#include "computation_graph.h" #include "computation_graph.h"
#define GRAPH_MAX_DEPTH 20 #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 *create_graph() {
struct computation_graph *the_graph = malloc(sizeof(struct computation_graph)); struct computation_graph *the_graph = malloc(sizeof(struct computation_graph));
...@@ -24,7 +28,7 @@ int graph_set_source(struct computation_graph *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 *dest_node = &graph->nodes[dest_cntl_id];
struct graph_node *src_node = &graph->nodes[src_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; return -1;
} }
...@@ -34,15 +38,11 @@ int graph_set_source(struct computation_graph *graph, ...@@ -34,15 +38,11 @@ int graph_set_source(struct computation_graph *graph,
return 0; return 0;
} }
int graph_create_node(struct computation_graph *graph, int graph_add_node(struct computation_graph *graph,
const char* name, const char* name,
const char* const* input_names, const struct graph_node_type *type,
const char* const* output_names, void *state) {
int n_inputs, assert(type->n_inputs <= GRAPH_MAX_INPUTS);
int n_outputs,
execute_node_t exec_func,
reset_node_t reset_func,
void *state) {
int new_id = graph->n_nodes; int new_id = graph->n_nodes;
if (new_id >= graph->size) { if (new_id >= graph->size) {
int new_capacity = graph->n_nodes == 0 ? 1 : graph->n_nodes * 2; int new_capacity = graph->n_nodes == 0 ? 1 : graph->n_nodes * 2;
...@@ -55,34 +55,29 @@ int graph_create_node(struct computation_graph *graph, ...@@ -55,34 +55,29 @@ int graph_create_node(struct computation_graph *graph,
} }
struct graph_node *new_node = &graph->nodes[new_id]; struct graph_node *new_node = &graph->nodes[new_id];
new_node->name = strdup(name); new_node->name = strdup(name);
new_node->input_names = input_names; new_node->type = type;
new_node->output_names = output_names; new_node->output_values = malloc(type->n_outputs * sizeof(double));
new_node->output_values = malloc(n_outputs * sizeof(double)); new_node->param_values = malloc(type->n_params * sizeof(double));
new_node->input_values = malloc(n_inputs * sizeof(double));
new_node->state = state; new_node->state = state;
new_node->execute = exec_func; new_node->input_srcs = malloc(type->n_inputs * sizeof(struct input_type));
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));
int i; 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; new_node->input_srcs[i].controller_id = -1;
} }
graph->n_nodes += 1; graph->n_nodes += 1;
return new_id; return new_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) {
if (node_id >= graph->n_nodes || input_id >= graph->nodes[node_id].n_inputs) { if (node_id >= graph->n_nodes || param_id >= graph->nodes[node_id].type->n_params) {
return -1; return -1;
} }
graph->nodes[node_id].input_values[input_id] = value; graph->nodes[node_id].param_values[param_id] = value;
return 0; return 0;
} }
double graph_get_output(const struct computation_graph *graph, int node_id, int output_id) { 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 -1;
} }
return graph->nodes[node_id].output_values[output_id]; 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 ...@@ -96,22 +91,23 @@ void graph_compute_node_rec(struct computation_graph *graph, int node_id, int de
if (node_id >= graph->n_nodes) { if (node_id >= graph->n_nodes) {
return; return;
} }
// TODO: Fix self-reference loop
struct graph_node *node = &graph->nodes[node_id]; struct graph_node *node = &graph->nodes[node_id];
if (node->processed_state == PROCESSED) { if (node->processed_state == PROCESSED) {
return; return;
} }
int input_id; 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; int src_cntl_id = node->input_srcs[input_id].controller_id;
if (src_cntl_id != -1) { if (src_cntl_id != -1) {
if (graph->nodes[src_cntl_id].processed_state == UNPROCESSED) { if (graph->nodes[src_cntl_id].processed_state == UNPROCESSED) {
graph_compute_node_rec(graph, src_cntl_id, depth + 1); graph_compute_node_rec(graph, src_cntl_id, depth + 1);
} }
int src_output_id = node->input_srcs[input_id].controller_output; 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; node->processed_state = PROCESSED;
} }
...@@ -130,22 +126,24 @@ int export_dot(const struct computation_graph* graph, FILE* of) { ...@@ -130,22 +126,24 @@ int export_dot(const struct computation_graph* graph, FILE* of) {
int i; int i;
for (i = 0; i < graph->n_nodes; i++) { for (i = 0; i < graph->n_nodes; i++) {
struct graph_node *node = &graph->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 // Create node
fprintf(of, "\"%s\"\n", node->name); fprintf(of, "\"%s\"[label=\"", node->name);
// Draw inputs to graph fprintf(of, "Name: %s\n", node->name); // Node name first
int j; int j;
for (j = 0; j < node->n_inputs; j++) { // Add parameters as labels
// Block for input to node for (j = 0; j < node->type->n_params; j++) {
fprintf(of, "\"%s[%s]\"[shape=box]\n", node->name, node->input_names[j]); fprintf(of, "%s=%.3f\n", node->type->param_names[j], node->param_values[j]);
// Link inputs to node }
fprintf(of, "\"%s[%s]\" -> \"%s\"[label=\"%.3f\"]\n", node->name, node->input_names[j], node->name, fprintf(of, "\"]\n"); // Close label bracket
node->input_values[j]); //
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 // Draw the links between nodes
for (i = 0; i < graph->n_nodes; i++) { for (i = 0; i < graph->n_nodes; i++) {
struct graph_node *node = &graph->nodes[i]; struct graph_node *node = &graph->nodes[i];
...@@ -161,7 +159,7 @@ int export_dot(const struct computation_graph* graph, FILE* of) { ...@@ -161,7 +159,7 @@ int export_dot(const struct computation_graph* graph, FILE* of) {
} }
} }
} }
*/
fprintf(of, "}"); // Close graph fprintf(of, "}"); // Close graph1
return 0; return 0;
} }
\ No newline at end of file
...@@ -3,7 +3,10 @@ ...@@ -3,7 +3,10 @@
#include <stdio.h> #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); typedef void (*reset_node_t)(void *state);
...@@ -19,17 +22,25 @@ struct computation_graph { ...@@ -19,17 +22,25 @@ struct computation_graph {
struct graph_node *nodes; struct graph_node *nodes;
}; };
struct graph_node { // Declares a node type
char *name; struct graph_node_type {
const char* const *input_names; const char* const* input_names;
const char* const *output_names; const char* const* output_names;
double *output_values; const char* const* param_names;
double *input_values;
int n_inputs; int n_inputs;
int n_outputs; int n_outputs;
void *state; int n_params;
execute_node_t execute; execute_node_t execute;
reset_node_t reset; 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; int processed_state;
struct input_type { struct input_type {
int controller_id; int controller_id;
...@@ -41,19 +52,14 @@ struct computation_graph *create_graph(); ...@@ -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_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, int graph_add_node(struct computation_graph *graph,
const char* name, const char *name,
const char* const *input_names, const struct graph_node_type *type,
const char* const *output_names, void *state);
int n_inputs,
int n_outputs,
execute_node_t exec_func,
reset_node_t reset_func,
void *state);
double graph_get_output(const struct computation_graph *graph, int node_id, int output_id); 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); void graph_compute_node(struct computation_graph *graph, int node_id);
......
#include <stdio.h> #include <stdio.h>
#include "computation_graph.h" #include "computation_graph.h"
#include "node_add2.h" #include "node_add.h"
#include "node_mult.h" #include "node_mult.h"
#include "node_constant.h"
#include "node_pow.h"
int main() { int main() {
struct computation_graph *graph = create_graph(); 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"); int const1 = graph_add_node_const(graph, "Const 1");
graph_set_input_val(graph, add3_id, ADD2_SUMMAND2, 5); graph_set_param_val(graph, const1, CONST_SET, 2);
graph_set_source(graph, add3_id, ADD2_SUMMAND1, add2_id, ADD2_SUM); 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"); int add1_id = graph_add_node_add(graph, "Add");
graph_set_source(graph, mult1_id, MULT_MULTIPLICAND1, add2_id, ADD2_SUM); graph_set_source(graph, add1_id, ADD_SUMMAND1, const1, CONST_VAL);
graph_set_source(graph, mult1_id, MULT_MULTIPLICAND2, add3_id, ADD2_SUM); 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; FILE* dot_fp;
dot_fp = fopen("..\\comp_graph.dot", "w"); dot_fp = fopen("..\\comp_graph.dot", "w");
export_dot(graph, dot_fp); export_dot(graph, dot_fp);
fclose(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); fflush(stdout);
return 0; return 0;
} }
#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);
}
#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
#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);
}
#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
};
#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);
}
#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
#include "node_mult.h" #include "node_mult.h"
#include <stdlib.h> #include <stdlib.h>
static const char* const in_names[2] = {"Multiplicand 1", "Multiplicand 2"}; static void mult_nodes(void *state, const double* params, const double *inputs, double *outputs) {
static const char* const out_names[1] = {"Product"};
static void mult_nodes(void *state, const double *inputs, double *outputs) {
outputs[MULT_PRODUCT] = inputs[MULT_MULTIPLICAND1] * inputs[MULT_MULTIPLICAND2]; outputs[MULT_PRODUCT] = inputs[MULT_MULTIPLICAND1] * inputs[MULT_MULTIPLICAND2];
} }
static void reset(void *state) {} 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) { 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);
} }
#ifndef __NODE_MULT_H__
#define __NODE_MULT_H__
#include "computation_graph.h" #include "computation_graph.h"
int graph_add_node_mult(struct computation_graph *graph, const char* name); 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 { enum graph_node_mult_inputs {
MULT_MULTIPLICAND1, MULT_MULTIPLICAND1,
MULT_MULTIPLICAND2 MULT_MULTIPLICAND2,
}; };
enum graph_node_mult_outputs { enum graph_node_mult_outputs {
MULT_PRODUCT MULT_PRODUCT
}; };
#endif // __NODE_MULT_H__
\ No newline at end of file
#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);
}
#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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment