diff --git a/quad/computation_graph/Makefile b/quad/computation_graph/Makefile index dd6e7b7e24e5c23087f7c24a24b875c650a6bbee..44c7e592619900de5251a68e4a8acb989422a6fc 100644 --- a/quad/computation_graph/Makefile +++ b/quad/computation_graph/Makefile @@ -10,7 +10,7 @@ SRC_PATH = ./src # Space-separated pkg-config libraries used by this project LIBS = # General compiler flags -COMPILE_FLAGS = -std=c99 -Wall -Wextra -pedantic -g +COMPILE_FLAGS = -std=c99 -Wall -Wextra -g # Additional release-specific flags RCOMPILE_FLAGS = -D NDEBUG # Additional debug-specific flags diff --git a/quad/computation_graph/src/computation_graph.c b/quad/computation_graph/src/computation_graph.c index eb54048ce90dcc9e13741eb514a542d681ddc4a9..28b10fbb45faac72293d7f50407c9f795d13bbca 100644 --- a/quad/computation_graph/src/computation_graph.c +++ b/quad/computation_graph/src/computation_graph.c @@ -41,6 +41,7 @@ static void reset_node_rec(struct computation_graph* graph, int node_id, int dep if (node->type->reset != NULL) { node->type->reset(node->state); } + node->updated = 1; node->processed_state = PROCESSED; } @@ -75,6 +76,7 @@ int graph_set_source(struct computation_graph *graph, src_node->n_children += 1; // Count destination node as a child dest_node->input_srcs[dest_input].controller_id = src_node_id; dest_node->input_srcs[dest_input].controller_output = src_output; + dest_node->updated = 1; reset_node(graph, src_node_id); return 0; } @@ -99,6 +101,7 @@ int graph_add_node(struct computation_graph *graph, new_node->type = type; new_node->state = state; new_node->n_children = 0; + new_node->updated = 1; new_node->output_values = malloc(type->n_outputs * sizeof(double)); new_node->param_values = malloc(type->n_params * sizeof(double)); new_node->input_srcs = malloc(type->n_inputs * sizeof(struct input_type)); @@ -125,10 +128,11 @@ int graph_set_param_val(struct computation_graph *graph, int node_id, int param_ return -1; } graph->nodes[node_id].param_values[param_id] = value; + graph->nodes[node_id].updated = 1; return 0; } -double graph_get_param_val(struct computation_graph *graph, int node_id, int param_id) { +double graph_get_param_val(const struct computation_graph *graph, int node_id, int param_id) { if (node_id >= graph->n_nodes || param_id >= graph->nodes[node_id].type->n_params) { return NAN; } @@ -160,23 +164,26 @@ void graph_compute_node_rec(struct computation_graph *graph, int node_id, int de int src_cntl_id = node->input_srcs[input_id].controller_id; if (src_cntl_id != -1) { graph_compute_node_rec(graph, src_cntl_id, depth + 1); + node->updated |= graph->nodes[src_cntl_id].updated; } } - // Populate the exec_input_vals array for computation - 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_output_id = node->input_srcs[input_id].controller_output; - if (src_cntl_id != -1) { - exec_input_vals[input_id] = graph->nodes[src_cntl_id].output_values[src_output_id]; + if (node->updated) { + // Populate the exec_input_vals array for computation + 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_output_id = node->input_srcs[input_id].controller_output; + if (src_cntl_id != -1) { + exec_input_vals[input_id] = graph->nodes[src_cntl_id].output_values[src_output_id]; + } + else { + // Set input value to 0 if not connected + exec_input_vals[input_id] = 0; + } } - else { - // Set input value to 0 if not connected - exec_input_vals[input_id] = 0; + if (node->type->execute != NULL) { + (*node->type->execute)(node->state, node->param_values, exec_input_vals, node->output_values); } } - if (node->type->execute != NULL) { - (*node->type->execute)(node->state, node->param_values, exec_input_vals, node->output_values); - } node->processed_state = PROCESSED; } @@ -191,6 +198,10 @@ void graph_compute_nodes(struct computation_graph *graph, int* node_ids, int n_n graph_compute_node_rec(graph, node_id, 0); } } + // Clear all the updated flags + for (i = 0; i < graph->n_nodes; i++) { + graph->nodes[i].updated = 0; + } } int export_dot(const struct computation_graph* graph, FILE* of, int print_outputs) { diff --git a/quad/computation_graph/src/computation_graph.h b/quad/computation_graph/src/computation_graph.h index 5b38d252f95db85b2556044ed965bc250c703a8b..e5e769fd28abcb90f66ef2df40434e132c496c62 100644 --- a/quad/computation_graph/src/computation_graph.h +++ b/quad/computation_graph/src/computation_graph.h @@ -37,17 +37,18 @@ struct graph_node_type { // Declares an instance of a node struct graph_node { - const char *name; - const struct graph_node_type* type; - double *output_values; - double *param_values; - int n_children; - void *state; - int processed_state; - struct input_type { + const char *name; // Name of this node instance + const struct graph_node_type* type; // Type of this node + double *output_values; // Computed output values + double *param_values; // Values of parameters set for this node + int n_children; // The number of connected children + void *state; // Pointer to the state instance + int processed_state; // State of the node with respecct to the graph traversal + struct input_type { // Array of tuples indicating the source for each input to this node int controller_id; int controller_output; } *input_srcs; + int updated; // 1 if this node has had an input or parameter change }; /* @@ -93,7 +94,7 @@ int graph_set_param_val(struct computation_graph *graph, int node_id, int param_ * Returns the value of the param at param_id for the given node * Will return NaN if the given node or parameter IDs are not valid */ -double graph_get_param_val(struct computation_graph *graph, int node_id, int param_id); +double graph_get_param_val(const struct computation_graph *graph, int node_id, int param_id); /* * Computes the nodes given by node_id. diff --git a/quad/computation_graph/src/main.c b/quad/computation_graph/src/main.c index be0e8ee775fd4b8900bb41724a8431ab6384ac11..b7fb2d3302228793a67465812e155e37e2f3b1f8 100644 --- a/quad/computation_graph/src/main.c +++ b/quad/computation_graph/src/main.c @@ -37,5 +37,6 @@ int main() { int success = graph_run_tests(); printf("Success: %s\n", success == 0 ? "Yes" : "No"); fflush(stdout); + return 0; } diff --git a/quad/computation_graph/test/Makefile b/quad/computation_graph/test/Makefile index 73d20c6744b465f4fb83afc3afe0e11ef31baf70..4fb6cf11603044352c832c27ce2b2a21edc58147 100644 --- a/quad/computation_graph/test/Makefile +++ b/quad/computation_graph/test/Makefile @@ -4,7 +4,7 @@ INC = $(QUAD_ROOT)/computation_graph/src BLOCKS_INC = $(QUAD_ROOT)/computation_graph/src/graph_blocks LIB = $(QUAD_ROOT)/lib/test -test_computation_graph: test_computation_graph.c +test_computation_graph: test_computation_graph.c $(SRC) gcc -o test_computation_graph -I. -I$(INC) -I$(BLOCKS_INC) -I$(LIB) $(LIB)/test.o test_computation_graph.c $(SRC) -lm .PHONY: clean diff --git a/quad/computation_graph/test/test_computation_graph.c b/quad/computation_graph/test/test_computation_graph.c index 8b11796af3a0042c5224cb65a37926185f17ee64..e4155ec8fb90ade08d0cc9484a4ca99ea8d02dbf 100644 --- a/quad/computation_graph/test/test_computation_graph.c +++ b/quad/computation_graph/test/test_computation_graph.c @@ -131,7 +131,9 @@ int graph_test_reset_rules() { to_compute_for[0] = gain2; graph_compute_nodes(graph, to_compute_for, 1); double result = graph_get_output(graph, gain2, GAIN_RESULT); - return nequal(result, 10); + // Equals 5 and not 10 because the inputs to the accumulator did not change, + // so it didn't run again' + return nequal(result, 5); } int graph_test_self_loop() {