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

Modified computation graph so blocks will only execute if their inputs have...

Modified computation graph so blocks will only execute if their inputs have been changed. This allows PID blocks to only execute if they have new data, allowing different sampling times.
parent 31fb1e0a
No related branches found
No related tags found
1 merge request!8Controller network
...@@ -10,7 +10,7 @@ SRC_PATH = ./src ...@@ -10,7 +10,7 @@ SRC_PATH = ./src
# Space-separated pkg-config libraries used by this project # Space-separated pkg-config libraries used by this project
LIBS = LIBS =
# General compiler flags # General compiler flags
COMPILE_FLAGS = -std=c99 -Wall -Wextra -pedantic -g COMPILE_FLAGS = -std=c99 -Wall -Wextra -g
# Additional release-specific flags # Additional release-specific flags
RCOMPILE_FLAGS = -D NDEBUG RCOMPILE_FLAGS = -D NDEBUG
# Additional debug-specific flags # Additional debug-specific flags
......
...@@ -41,6 +41,7 @@ static void reset_node_rec(struct computation_graph* graph, int node_id, int dep ...@@ -41,6 +41,7 @@ static void reset_node_rec(struct computation_graph* graph, int node_id, int dep
if (node->type->reset != NULL) { if (node->type->reset != NULL) {
node->type->reset(node->state); node->type->reset(node->state);
} }
node->updated = 1;
node->processed_state = PROCESSED; node->processed_state = PROCESSED;
} }
...@@ -75,6 +76,7 @@ int graph_set_source(struct computation_graph *graph, ...@@ -75,6 +76,7 @@ int graph_set_source(struct computation_graph *graph,
src_node->n_children += 1; // Count destination node as a child 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_id = src_node_id;
dest_node->input_srcs[dest_input].controller_output = src_output; dest_node->input_srcs[dest_input].controller_output = src_output;
dest_node->updated = 1;
reset_node(graph, src_node_id); reset_node(graph, src_node_id);
return 0; return 0;
} }
...@@ -99,6 +101,7 @@ int graph_add_node(struct computation_graph *graph, ...@@ -99,6 +101,7 @@ int graph_add_node(struct computation_graph *graph,
new_node->type = type; new_node->type = type;
new_node->state = state; new_node->state = state;
new_node->n_children = 0; new_node->n_children = 0;
new_node->updated = 1;
new_node->output_values = malloc(type->n_outputs * sizeof(double)); new_node->output_values = malloc(type->n_outputs * sizeof(double));
new_node->param_values = malloc(type->n_params * sizeof(double)); new_node->param_values = malloc(type->n_params * sizeof(double));
new_node->input_srcs = malloc(type->n_inputs * sizeof(struct input_type)); 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_ ...@@ -125,10 +128,11 @@ int graph_set_param_val(struct computation_graph *graph, int node_id, int param_
return -1; return -1;
} }
graph->nodes[node_id].param_values[param_id] = value; graph->nodes[node_id].param_values[param_id] = value;
graph->nodes[node_id].updated = 1;
return 0; 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) { if (node_id >= graph->n_nodes || param_id >= graph->nodes[node_id].type->n_params) {
return NAN; return NAN;
} }
...@@ -160,23 +164,26 @@ void graph_compute_node_rec(struct computation_graph *graph, int node_id, int de ...@@ -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; int src_cntl_id = node->input_srcs[input_id].controller_id;
if (src_cntl_id != -1) { if (src_cntl_id != -1) {
graph_compute_node_rec(graph, src_cntl_id, depth + 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 if (node->updated) {
for (input_id = 0; input_id < node->type->n_inputs; input_id++) { // Populate the exec_input_vals array for computation
int src_cntl_id = node->input_srcs[input_id].controller_id; for (input_id = 0; input_id < node->type->n_inputs; input_id++) {
int src_output_id = node->input_srcs[input_id].controller_output; int src_cntl_id = node->input_srcs[input_id].controller_id;
if (src_cntl_id != -1) { int src_output_id = node->input_srcs[input_id].controller_output;
exec_input_vals[input_id] = graph->nodes[src_cntl_id].output_values[src_output_id]; 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 { if (node->type->execute != NULL) {
// Set input value to 0 if not connected (*node->type->execute)(node->state, node->param_values, exec_input_vals, node->output_values);
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);
}
node->processed_state = PROCESSED; node->processed_state = PROCESSED;
} }
...@@ -191,6 +198,10 @@ void graph_compute_nodes(struct computation_graph *graph, int* node_ids, int n_n ...@@ -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); 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) { int export_dot(const struct computation_graph* graph, FILE* of, int print_outputs) {
......
...@@ -37,17 +37,18 @@ struct graph_node_type { ...@@ -37,17 +37,18 @@ struct graph_node_type {
// Declares an instance of a node // Declares an instance of a node
struct graph_node { struct graph_node {
const char *name; const char *name; // Name of this node instance
const struct graph_node_type* type; const struct graph_node_type* type; // Type of this node
double *output_values; double *output_values; // Computed output values
double *param_values; double *param_values; // Values of parameters set for this node
int n_children; int n_children; // The number of connected children
void *state; void *state; // Pointer to the state instance
int processed_state; int processed_state; // State of the node with respecct to the graph traversal
struct input_type { struct input_type { // Array of tuples indicating the source for each input to this node
int controller_id; int controller_id;
int controller_output; int controller_output;
} *input_srcs; } *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_ ...@@ -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 * 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 * 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. * Computes the nodes given by node_id.
......
...@@ -37,5 +37,6 @@ int main() { ...@@ -37,5 +37,6 @@ int main() {
int success = graph_run_tests(); int success = graph_run_tests();
printf("Success: %s\n", success == 0 ? "Yes" : "No"); printf("Success: %s\n", success == 0 ? "Yes" : "No");
fflush(stdout); fflush(stdout);
return 0; return 0;
} }
...@@ -4,7 +4,7 @@ INC = $(QUAD_ROOT)/computation_graph/src ...@@ -4,7 +4,7 @@ INC = $(QUAD_ROOT)/computation_graph/src
BLOCKS_INC = $(QUAD_ROOT)/computation_graph/src/graph_blocks BLOCKS_INC = $(QUAD_ROOT)/computation_graph/src/graph_blocks
LIB = $(QUAD_ROOT)/lib/test 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 gcc -o test_computation_graph -I. -I$(INC) -I$(BLOCKS_INC) -I$(LIB) $(LIB)/test.o test_computation_graph.c $(SRC) -lm
.PHONY: clean .PHONY: clean
......
...@@ -131,7 +131,9 @@ int graph_test_reset_rules() { ...@@ -131,7 +131,9 @@ int graph_test_reset_rules() {
to_compute_for[0] = gain2; to_compute_for[0] = gain2;
graph_compute_nodes(graph, to_compute_for, 1); graph_compute_nodes(graph, to_compute_for, 1);
double result = graph_get_output(graph, gain2, GAIN_RESULT); 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() { int graph_test_self_loop() {
......
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