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

Resets recursively, keeping track of children. Created tests, which pass....

Resets recursively, keeping track of children. Created tests, which pass. Computation terminates on graph cycles. Added comments.
parent 955bcd56
No related branches found
No related tags found
No related merge requests found
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#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));
the_graph->nodes = malloc(sizeof(struct graph_node));
the_graph->n_nodes = 0;
the_graph->size = 1;
return the_graph;
}
void reset_node(int node_id) {
}
int graph_set_source(struct computation_graph *graph,
int dest_cntl_id, int dest_input, int src_cntl_id, int src_output) {
if (dest_cntl_id >= graph->n_nodes || src_cntl_id >= graph->n_nodes) {
return -1;
}
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->type->n_inputs || src_output >= src_node->type->n_outputs) {
return -1;
}
dest_node->input_srcs[dest_input].controller_id = src_cntl_id;
dest_node->input_srcs[dest_input].controller_output = src_output;
reset_node(src_cntl_id);
return 0;
}
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;
struct graph_node *node_arr = realloc(graph->nodes, sizeof(struct graph_node) * new_capacity);
if (!node_arr) {
return -1;
}
graph->size = new_capacity;
graph->nodes = node_arr;
}
struct graph_node *new_node = &graph->nodes[new_id];
new_node->name = strdup(name);
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->input_srcs = malloc(type->n_inputs * sizeof(struct input_type));
int 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_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].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].type->n_outputs) {
return -1;
}
return graph->nodes[node_id].output_values[output_id];
}
void graph_compute_node_rec(struct computation_graph *graph, int node_id, int depth) {
if (depth >= GRAPH_MAX_DEPTH) {
assert(1 == 0); // TODO :Xil_Assert false
return;
}
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->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);
}
}
}
// 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;
exec_input_vals[input_id] = graph->nodes[src_cntl_id].output_values[src_output_id];
}
(*node->type->execute)(node->state, node->param_values, exec_input_vals, node->output_values);
node->processed_state = PROCESSED;
}
void graph_compute_node(struct computation_graph *graph, int node_id) {
int i;
for (i = 0; i < graph->n_nodes; i++) {
graph->nodes[i].processed_state = UNPROCESSED;
}
graph_compute_node_rec(graph, node_id, 0);
}
int export_dot(const struct computation_graph* graph, FILE* of) {
fprintf(of, "digraph G {\n"); // Header
fprintf(of, "rankdir=\"LR\"\n"); // Horizontal layout
// Draw all the nodes and their inputs
int i;
for (i = 0; i < graph->n_nodes; i++) {
struct graph_node *node = &graph->nodes[i];
// Create node
fprintf(of, "\"%s\"[shape=record\nlabel=\"\n", node->name);
fprintf(of, "<f0> %s\n", node->name); // Node name is port 0
int j;
// Create ports for inputs
for (j = 0; j < node->type->n_inputs; j++) {
fprintf(of, "|<f%d> --\\>%s\n", j+1, node->type->input_names[j]);
}
// Create ports for parameters
for (j = 0; j < node->type->n_params; j++) {
fprintf(of, "|<f%d> [%s=%.3f]\n", j+1+node->type->n_inputs, node->type->param_names[j],node->param_values[j]);
}
fprintf(of, "\"]\n"); // Close label bracket
// Make connections from
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\":f%d [label=\"%s=%.3f\"]\n", src_node->name, node->name, j+1, output_name, src_node->output_values[output_id]);
}
}
fprintf(of, "}"); // Close graph
return 0;
}
\ No newline at end of file
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#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));
if (!the_graph) {return NULL;}
the_graph->nodes = malloc(sizeof(struct graph_node));
if (!the_graph->nodes) { return NULL; }
the_graph->n_nodes = 0;
the_graph->size = 1;
return the_graph;
}
static void reset_node_rec(struct computation_graph* graph, int node_id, int depth) {
if (depth > GRAPH_MAX_DEPTH) {
return;
}
struct graph_node* node = &graph->nodes[node_id];
// Don't reset nodes that are already connected to something else
// Don't reset nodes that have already been reset or discovered
if (node->n_children != 1 || node->processed_state != UNPROCESSED) {
return;
}
node->processed_state = DISCOVERED;
int input_id;
for (input_id = 0; input_id < node->type->n_inputs; input_id++) {
int src_node_id = node->input_srcs[input_id].controller_id;
if (src_node_id != -1) {
reset_node_rec(graph, src_node_id, depth + 1);
}
}
// Reset this node
if (node->type->reset != NULL) {
node->type->reset(node->state);
}
node->processed_state = PROCESSED;
}
int reset_node(struct computation_graph* graph, int node_id) {
if (node_id >= graph->n_nodes) {
return -1;
}
int i;
for (i = 0; i < graph->n_nodes; i++) {
graph->nodes[i].processed_state = UNPROCESSED;
}
reset_node_rec(graph, node_id, 0);
return 0;
}
int graph_set_source(struct computation_graph *graph,
int dest_node_id, int dest_input, int src_node_id, int src_output) {
if (dest_node_id >= graph->n_nodes || src_node_id >= graph->n_nodes) {
return -1;
}
struct graph_node *dest_node = &graph->nodes[dest_node_id];
struct graph_node *src_node = &graph->nodes[src_node_id];
if (dest_input >= dest_node->type->n_inputs || src_output >= src_node->type->n_outputs) {
return -1;
}
// If a previous source exists, remove one from its children count
int prev_src_id = dest_node->input_srcs[dest_input].controller_id;
if (prev_src_id != -1) {
graph->nodes[prev_src_id].n_children -= 1;
}
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;
reset_node(graph, src_node_id);
return 0;
}
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;
struct graph_node *node_arr = realloc(graph->nodes, sizeof(struct graph_node) * new_capacity);
if (!node_arr) {
return -1;
}
graph->size = new_capacity;
graph->nodes = node_arr;
}
struct graph_node *new_node = &graph->nodes[new_id];
new_node->name = strdup(name);
new_node->type = type;
new_node->state = state;
new_node->n_children = 0;
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));
// Check that malloc succeeded in every case which memory was requested
if ((type->n_outputs && !new_node->output_values) ||
(type->n_params && !new_node->param_values) ||
(type->n_inputs && !new_node->input_srcs)) {
return -1;
}
int i;
for (i = 0; i < type->n_inputs; i++) {
new_node->input_srcs[i].controller_id = -1;
}
graph->n_nodes += 1;
// Reset block upon creation
if (new_node->type->reset != NULL) {
new_node->type->reset(new_node->state);
}
return new_id;
}
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].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].type->n_outputs) {
return 0;
}
return graph->nodes[node_id].output_values[output_id];
}
void graph_compute_node_rec(struct computation_graph *graph, int node_id, int depth) {
if (depth >= GRAPH_MAX_DEPTH) {
assert(1 == 0); // TODO :Xil_Assert false
return;
}
if (node_id >= graph->n_nodes) {
return;
}
struct graph_node *node = &graph->nodes[node_id];
if (node->processed_state != UNPROCESSED) {
return;
}
node->processed_state = DISCOVERED;
int 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) {
graph_compute_node_rec(graph, src_cntl_id, depth + 1);
}
}
// 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->type->execute != NULL) {
(*node->type->execute)(node->state, node->param_values, exec_input_vals, node->output_values);
}
node->processed_state = PROCESSED;
}
void graph_compute_node(struct computation_graph *graph, int node_id) {
int i;
for (i = 0; i < graph->n_nodes; i++) {
graph->nodes[i].processed_state = UNPROCESSED;
}
graph_compute_node_rec(graph, node_id, 0);
}
int export_dot(const struct computation_graph* graph, FILE* of) {
fprintf(of, "digraph G {\n"); // Header
fprintf(of, "rankdir=\"LR\"\n"); // Horizontal layout
// Draw all the nodes and their inputs
int i;
for (i = 0; i < graph->n_nodes; i++) {
struct graph_node *node = &graph->nodes[i];
// Create node
fprintf(of, "\"%s\"[shape=record\nlabel=\"\n", node->name);
fprintf(of, "<f0> %s\n", node->name); // Node name is port 0
int j;
// Create ports for inputs
for (j = 0; j < node->type->n_inputs; j++) {
fprintf(of, "|<f%d> --\\>%s\n", j+1, node->type->input_names[j]);
}
// Create ports for parameters
for (j = 0; j < node->type->n_params; j++) {
fprintf(of, "|<f%d> [%s=%.3f]\n", j+1+node->type->n_inputs, node->type->param_names[j],node->param_values[j]);
}
fprintf(of, "\"]\n"); // Close label bracket
// Make connections from
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\":f%d [label=\"%s=%.3f\"]\n", src_node->name, node->name, j+1, output_name, src_node->output_values[output_id]);
}
}
fprintf(of, "}"); // Close graph
return 0;
}
#ifndef __COMPUTATION_GRAPH_H__
#define __COMPUTATION_GRAPH_H__
#include <stdio.h>
typedef void (*execute_node_t)(void *state,
const double* params,
const double *inputs,
double *outputs);
typedef void (*reset_node_t)(void *state);
enum node_processed_state {
UNPROCESSED,
DISCOVERED,
PROCESSED
};
struct computation_graph {
int n_nodes;
int size;
struct graph_node *nodes;
};
// 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;
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;
int controller_output;
} *input_srcs;
};
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_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_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);
int export_dot(const struct computation_graph* graph, FILE* of);
#endif // __COMPUTATION_GRAPH_H__
#ifndef __COMPUTATION_GRAPH_H__
#define __COMPUTATION_GRAPH_H__
#include <stdio.h>
typedef void (*execute_node_t)(void *state,
const double* params,
const double *inputs,
double *outputs);
typedef void (*reset_node_t)(void *state);
enum node_processed_state {
UNPROCESSED,
DISCOVERED,
PROCESSED
};
struct computation_graph {
int n_nodes;
int size;
struct graph_node *nodes;
};
// 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;
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;
int n_children;
void *state;
int processed_state;
struct input_type {
int controller_id;
int controller_output;
} *input_srcs;
};
/*
* Creates an empty computation graph
* May return NULL on failure
*/
struct computation_graph *create_graph();
/*
* Defines which node's output gets its value passed into the input of a different node.
* Will call reset for each node which was previously orphaned, but is now connected to the graph
* dest_node_id: The ID of the node to which the input belongs
* dest_input: The ID of the input for node dest_cntl to pass the value into
* src_node_id: The node ID where the value is coming from
* src_output: The ID of the output on <src_node_id> where the value comes from
* Returns 0 for success
*/
int graph_set_source(struct computation_graph *graph, int dest_node_id, int dest_input, int src_node_id, int src_output);
/*
* Creates a new node with the given data, and adds it to the graph.
* Returns a negative integer upon failure.
* Otherwise returns a positive integer which is the ID of the new node
*/
int graph_add_node(struct computation_graph *graph,
const char *name,
const struct graph_node_type *type,
void *state);
/*
* Returns the value at the output of the requested node for the requested output.
* Returns 0 if the given node or output IDs are invalid
*/
double graph_get_output(const struct computation_graph *graph, int node_id, int output_id);
/*
* Sets a parameter given by param_id on node node_id to the given value
* Returns 0 upon success
*/
int graph_set_param_val(struct computation_graph *graph, int node_id, int param_id, double value);
/*
* Computes the node given by node_id.
* To do so, computes all nodes which are ancestors of node_id in topological order, with
* the final computation being node_id itself.
*/
void graph_compute_node(struct computation_graph *graph, int node_id);
/*
* Writes a graphical representation of the given graph to <of> in the DOT language
*/
int export_dot(const struct computation_graph* graph, FILE* of);
#endif // __COMPUTATION_GRAPH_H__
......@@ -4,34 +4,38 @@
#include "node_mult.h"
#include "node_constant.h"
#include "node_gain.h"
#include "tests.h"
int main() {
struct computation_graph *graph = create_graph();
// struct computation_graph *graph = create_graph();
//
// int const1 = graph_add_node_const(graph, "Const 2");
// graph_set_param_val(graph, const1, CONST_SET, 2);
// int const2 = graph_add_node_const(graph, "Const 1");
// graph_set_param_val(graph, const2, CONST_SET, 3);
//
// 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);
//
// int gain1_id = graph_add_node_gain(graph, "Gain");
// graph_set_param_val(graph, gain1_id, GAIN_GAIN, 3);
// graph_set_source(graph, gain1_id, GAIN_INPUT, add1_id, ADD_SUM);
//
// int mult1_id = graph_add_node_mult(graph, "Mult");
// graph_set_source(graph, mult1_id, MULT_MULTIPLICAND2, gain1_id, GAIN_RESULT);
// graph_set_source(graph, mult1_id, MULT_MULTIPLICAND1, const1, CONST_VAL);
//
// graph_compute_node(graph, mult1_id);
int const1 = graph_add_node_const(graph, "Const 2");
graph_set_param_val(graph, const1, CONST_SET, 2);
int const2 = graph_add_node_const(graph, "Const 1");
graph_set_param_val(graph, const2, CONST_SET, 3);
// 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, GAIN_RESULT));
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);
int gain1_id = graph_add_node_gain(graph, "Gain");
graph_set_param_val(graph, gain1_id, GAIN_GAIN, 3);
graph_set_source(graph, gain1_id, GAIN_INPUT, add1_id, ADD_SUM);
int mult1_id = graph_add_node_mult(graph, "Mult");
graph_set_source(graph, mult1_id, MULT_MULTIPLICAND2, gain1_id, GAIN_RESULT);
graph_set_source(graph, mult1_id, MULT_MULTIPLICAND1, const1, CONST_VAL);
graph_compute_node(graph, mult1_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, GAIN_RESULT));
int success = graph_run_tests();
printf("Success: %s", success == 0 ? "Yes" : "No");
fflush(stdout);
return 0;
}
#include "node_accumulator.h"
#include <stdlib.h>
static struct accum_state {
double accumulated;
};
static void accum_nodes(void *state, const double* params, const double *inputs, double *outputs) {
struct accum_state* my_state = (struct accum_state*)state;
my_state->accumulated += inputs[ACCUM_IN];
outputs[ACCUMULATED] = my_state->accumulated;
}
static void reset(void *state) {
((struct accum_state*)state)->accumulated = 0;
}
static const char* const in_names[2] = {"Accumulator in"};
static const char* const out_names[1] = {"Accumulated"};
static const char* const param_names[0] = {};
const struct graph_node_type node_accum_type = {
.input_names = in_names,
.output_names = out_names,
.param_names = param_names,
.n_inputs = 1,
.n_outputs = 1,
.n_params = 0,
.execute = accum_nodes,
.reset = reset
};
int graph_add_node_accum(struct computation_graph *graph, const char* name) {
struct accum_state* node_state = malloc(sizeof(struct accum_state));
if (sizeof(struct accum_state) && !node_state) {
return -1; // malloc failed
}
return graph_add_node(graph, name, &node_accum_type, node_state);
}
#ifndef __NODE_ACCUMULATOR_H__
#define __NODE_ACCUMULATOR_H__
#include "computation_graph.h"
int graph_add_node_accum(struct computation_graph *graph, const char* name);
const extern struct graph_node_type node_accum_type;
enum graph_node_accum_inputs {
ACCUM_IN,
};
enum graph_node_accum_outputs {
ACCUMULATED
};
#endif // __NODE_ACCUMULATOR_H__
\ No newline at end of file
//
// Created by dawehr on 2/9/2017.
//
#include "tests.h"
#define GRAPH_TEST_EPS 0.00001
static int nequal(double val1, double val2) {
if (fabs(val1 - val2) < GRAPH_TEST_EPS) {
return 0;
}
return -1;
}
int graph_run_tests() {
int success = 0;
success |= graph_test_one_add();
success |= graph_test_circular_runs();
success |= graph_test_circular_resets();
success |= graph_test_accumulator();
success |= graph_test_single_run();
success |= graph_test_reset_rules();
success |= graph_test_self_loop();
return success;
}
int graph_test_one_add() {
struct computation_graph *graph = create_graph();
int block = graph_add_node_add(graph, "Add");
int cblock3 = graph_add_node_const(graph, "3");
graph_set_param_val(graph, cblock3, CONST_SET, 3);
int cblock4 = graph_add_node_const(graph, "4");
graph_set_param_val(graph, cblock4, CONST_SET, 4);
graph_set_source(graph, block, ADD_SUMMAND1, cblock3, CONST_VAL);
graph_set_source(graph, block, ADD_SUMMAND2, cblock4, CONST_VAL);
graph_compute_node(graph, block);
double result = graph_get_output(graph, block, ADD_SUM);
return nequal(result, 7);
}
int graph_test_circular_runs() {
struct computation_graph *graph = create_graph();
int gain1 = graph_add_node_gain(graph, "gain1");
int gain2 = graph_add_node_gain(graph, "gain2");
graph_set_source(graph, gain2, GAIN_INPUT, gain1, GAIN_RESULT);
graph_set_source(graph, gain1, GAIN_INPUT, gain2, GAIN_RESULT);
graph_compute_node(graph, gain2);
// If no infinite loop, then success. Value is undefined for circular graphs
return 0;
}
int graph_test_circular_resets() {
struct computation_graph *graph = create_graph();
int acum1 = graph_add_node_accum(graph, "accumulator1");
int acum2 = graph_add_node_accum(graph, "accumulator2");
graph_set_source(graph, acum2, ACCUM_IN, acum1, ACCUMULATED);
graph_set_source(graph, acum1, ACCUM_IN, acum2, ACCUMULATED);
return 0; // Passes if no infinite loop
}
// Tests the accumulator block, thereby testing reset and state changes
int graph_test_accumulator() {
struct computation_graph *graph = create_graph();
int cblock = graph_add_node_const(graph, "const");
int acum_b = graph_add_node_accum(graph, "accumulator");
graph_set_source(graph, acum_b, ACCUM_IN, cblock, CONST_VAL);
graph_set_param_val(graph, cblock, CONST_SET, 3);
graph_compute_node(graph, acum_b);
graph_set_param_val(graph, cblock, CONST_SET, 8);
graph_compute_node(graph, acum_b);
graph_set_param_val(graph, cblock, CONST_SET, -2);
graph_compute_node(graph, acum_b);
double result = graph_get_output(graph, acum_b, ACCUMULATED);
if (nequal(result, 9)) {
printf("graph_test_accumulator failed on step 1, equals %f\n", result);
return -1;
}
// Test reset on source set
int gain_b = graph_add_node_gain(graph, "Gain");
graph_set_param_val(graph, gain_b, GAIN_GAIN, 1);
graph_set_source(graph, gain_b, GAIN_INPUT, acum_b, ACCUMULATED);
graph_compute_node(graph, gain_b);
result = graph_get_output(graph, gain_b, GAIN_RESULT);
if (nequal(result, -2)) {
printf("graph_test_accumulator failed on step 2\n");
return -2;
}
return 0;
}
// Tests that a block will only execute once per compute,
// even if its output is connected to multiple inputs
int graph_test_single_run() {
struct computation_graph *graph = create_graph();
int acum_b = graph_add_node_accum(graph, "accumulator");
int add_block = graph_add_node_add(graph, "Add");
int cblock = graph_add_node_const(graph, "const");
graph_set_param_val(graph, cblock, CONST_SET, 2);
graph_set_source(graph, acum_b, ACCUM_IN, cblock, CONST_VAL);
graph_set_source(graph, add_block, ADD_SUMMAND1, acum_b, ACCUMULATED);
graph_set_source(graph, add_block, ADD_SUMMAND2, acum_b, ACCUMULATED);
graph_compute_node(graph, add_block);
double result = graph_get_output(graph, add_block, ADD_SUM);
return nequal(result, 4);
}
// Tests that upon connection of a second child, a block will not reset
int graph_test_reset_rules() {
struct computation_graph *graph = create_graph();
int cblock = graph_add_node_const(graph, "5");
graph_set_param_val(graph, cblock, CONST_SET, 5);
int acum_b = graph_add_node_accum(graph, "accumulator");
int gain1 = graph_add_node_gain(graph, "gain1");
graph_set_param_val(graph, gain1, GAIN_GAIN, 1);
graph_set_source(graph, gain1, GAIN_INPUT, acum_b, ACCUMULATED);
graph_set_source(graph, acum_b, ACCUM_IN, cblock, CONST_VAL);
graph_compute_node(graph, gain1);
// state of acum_b is now 5
int gain2 = graph_add_node_gain(graph, "gain2");
graph_set_param_val(graph, gain2, GAIN_GAIN, 1);
// Connect gain 2, and accumulator should not get reset
graph_set_source(graph, gain2, GAIN_INPUT, acum_b, ACCUMULATED);
graph_compute_node(graph, gain2);
double result = graph_get_output(graph, gain2, GAIN_RESULT);
return nequal(result, 10);
}
int graph_test_self_loop() {
struct computation_graph *graph = create_graph();
int gain1 = graph_add_node_gain(graph, "gain1");
graph_set_source(graph, gain1, GAIN_INPUT, gain1, GAIN_RESULT);
graph_compute_node(graph, gain1);
return 0;
}
\ No newline at end of file
//
// Created by dawehr on 2/9/2017.
//
#ifndef COMPUTATION_GRAPH_TESTS_H
#define COMPUTATION_GRAPH_TESTS_H
#include "computation_graph.h"
#include "node_add.h"
#include "node_mult.h"
#include "node_constant.h"
#include "node_gain.h"
#include "node_accumulator.h"
#include <math.h>
int graph_run_tests();
int graph_test_one_add();
int graph_test_circular_runs();
int graph_test_circular_resets();
int graph_test_self_loop();
int graph_test_accumulator();
int graph_test_single_run();
int graph_test_reset_rules();
#endif //COMPUTATION_GRAPH_TESTS_H
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