/* * file : reverse_connector.c * * [DEFINE DESCRIPTION = Sparse matrix representation class, with connection strengths] * * Name Date Description * -------------- -------- ------------------------------------- * Andrew H. Fagg 08/13/92 Original * * The connector type provides an efficient way of connecting * units together in sparse networks. The connector class * stores a list of connections that have been made into a unit. * These connections (information stored within the connector class) * consist of a name of the source of the connection and a pointer * to the nsl_data value that stores the activity value of the * connecting unit, and an initial weight (if applicable). * Once the connections are made, the set of activity values * can be accessed as a single vector. * * * The connector stores connections in dynamically-allocated * arrays in blocks of <ALLOC_BLOCK>. So, every <ALLOC_BLOCK> * connections, the old list of pointers must be deallocated * and a new (longer) set must be allocated. * */ #include "nsl_include.h" #include "reverse_connector.h" #include "connector.h" #include "alib.h" #include "gen.h" /* #define DEBUG */ /* * reverse_connector_input_class::reverse_connector_input_class(short fl) * * <fl> = connector configuration (as defined in connection.h). * * Connector class constructor. Allocate the first block * of storage arrays. * */ reverse_connector_input_class::reverse_connector_input_class() { #ifdef DEBUG cout << "create new reverse input connector" nl; cout.flush(); #endif num_pointers = 0; num_allocated = ALLOC_BLOCK; /* pointers = new nsl_data*[num_allocated]; */ pointers = NULL; names = new name_class*[num_allocated]; contributing_arrays = new nsl_data**[num_allocated]; contributing_indices = new int[num_allocated]; /* flags = fl; */ #ifdef DEBUG cout << "end new" nl; cout.flush(); #endif } /* * reverse_connector_input_class::~connector_class() * * connector class destructor. * */ reverse_connector_input_class::~reverse_connector_input_class() { if(pointers) delete pointers; delete names; if(contributing_arrays) delete contributing_arrays; if(contributing_indices) delete contributing_indices; } /* * void reverse_connector_input_class::add_connection(nsl_data* new_value, //OVERLOAD CALL: add_connection: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class) * name_class *name) * * <new_value> = a pointer to the activity value input (source). * <name> = name of source. * * Add a new connection to a connector. If this addition requires * a new block of storage, then create it, copy the relevant info * and delete the old lists. * */ void reverse_connector_input_class::add_connection(nsl_data** contributing_array, int contributing_index, name_class *name) { /* nsl_data** temp; */ name_class** temp_names; nsl_data*** array_temp; int* index_temp; #ifdef DEBUG cout << "reverse_connector_input_class::add_connection(): " //OVERLOAD CALL: add_connection: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class) << contributing_index sp << *name nl; cout.flush(); #endif if(num_pointers == num_allocated) { /* Allocate a new block. */ num_allocated += ALLOC_BLOCK; /* New arrays. */ temp_names = new name_class*[num_allocated]; array_temp = new nsl_data**[num_allocated]; index_temp = new int[num_allocated]; /* Copy information. */ bcopy(names, temp_names, sizeof(name_class*) * num_pointers); bcopy(contributing_arrays, array_temp, sizeof(nsl_data**) * num_pointers); bcopy(contributing_indices, index_temp, sizeof(int) * num_pointers); /* Delete old arrays. */ delete names; delete contributing_arrays; delete contributing_indices; names = temp_names; contributing_arrays = array_temp; contributing_indices = index_temp; } /* Assign new connection. */ names[num_pointers] = name; contributing_arrays[num_pointers] = contributing_array; contributing_indices[num_pointers] = contributing_index; num_pointers++; #ifdef DEBUG cout << "end connect" nl; cout.flush(); #endif } /* * nsl_vector reverse_connector_input_class::get_values() //OVERLOAD CALL: get_values: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class), sensor.c(sensor_class) * * Return a vector of input activity values. * */ nsl_vector reverse_connector_input_class::get_values() { nsl_vector out(num_pointers); register int i; for(i = 0; i < num_pointers; ++i) out.elem(i) = (*pointers[i]).elem(); return out; } /* * name_class* reverse_connector_input_class::get_name(int i) //OVERLOAD CALL: get_name: column.c(column_class), connector.c(connector_class), gate.c(gate_class), layer.c(layer_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class), sensor.c(sensor_class) * * <i> = index of connection. * * Return the name of a particular connection (source name). * */ name_class* reverse_connector_input_class::get_name(int i) { /* Check for proper index. */ if(i >= 0 && i < num_pointers) return names[i]; else { cmd_error("*** reverse_connector_input_class::get_name ***"); cmd_error("bad index: ", i); exit(0); } } /* * int reverse_connector_input_class::get_num_connections() //OVERLOAD CALL: get_num_connections: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class) * * Return the number of connections. * */ int reverse_connector_input_class::get_num_connections() { return num_pointers; } /* * short reverse_connector_input_class::get_flags() //OVERLOAD CALL: get_flags: connector.c(connector_class), reverse_connector.c(reverse_connector_output_class) * * Return the configuration flags. * */ /* short reverse_connector_input_class::get_flags() //OVERLOAD CALL: get_flags: connector.c(connector_class), reverse_connector.c(reverse_connector_output_class) { return flags; } */ /* * void reverse_connector_input_class::init_contributing_arrays() * * Set up direct inferences to the contributing elements. * This is accomplished by looking up the appropriate contributing * array, finding the appropriate index into it & then taking the * pointer to that location. * This routine MUST BE CALLED AFTER init_contributions() * (output class). * */ void reverse_connector_input_class::init_contributing_arrays() { register int i; pointers = new nsl_data*[num_pointers]; for(i = 0; i < num_pointers; ++i) pointers[i] = &((*(contributing_arrays[i]))[contributing_indices[i]]); delete contributing_arrays; } /* * void reverse_connector_output_class::report_state(nsl_vector* v1, //OVERLOAD CALL: report_state: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class) * nsl_vector* v2, * nsl_vector* v3, * nsl_vector* v4) * * Report the state of each connection. Name, and 4 columns * of values, as determined by the parent function. * */ void reverse_connector_input_class::report_state(nsl_vector* v1, nsl_vector* v2, nsl_vector* v3, nsl_vector* v4) { int i; for(i = 0; i < num_pointers; ++i) { cout << names[i] << "\t" ; if(v1 == NULL) cout tab; else cout << v1->elem(i) tab; if(v2 == NULL) cout tab; else cout << v2->elem(i) tab; if(v3 == NULL) cout tab; else cout << v3->elem(i) tab; if(v4 == NULL) cout tab; else cout << v4->elem(i) tab; cout nl; } } /************************* * * reverse_connector_output_class * *************************/ /* * reverse_connector_output_class::reverse_connector_output_class(short fl) * * <fl> = connector configuration (as defined in connection.h). * * Connector class constructor. Allocate the first block * of storage arrays. * */ reverse_connector_output_class::reverse_connector_output_class(short fl) { #ifdef DEBUG cout << "create new reverse output connector" nl; cout.flush(); #endif num_pointers = 0; num_allocated = ALLOC_BLOCK; pointers = new nsl_data*[num_allocated]; names = new name_class*[num_allocated]; contributions = NULL; initial_weights = new nsl_vector(num_allocated); flags = fl; #ifdef DEBUG cout << "end new" nl; cout.flush(); #endif } /* * reverse_connector_output_class::~reverse_connector_output_class() * * connector class destructor. * */ reverse_connector_output_class::~reverse_connector_output_class() { delete pointers; delete names; if(contributions) delete contributions; if(initial_weights != NULL) delete initial_weights; } /* * void reverse_connector_output_class::add_connection(nsl_data* new_value, name_class *name, //OVERLOAD CALL: add_connection: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class) * float initial_value) * * <new_value> = a pointer to the activity value input (source). * <name> = name of source. * <initial_value> = the initial value of the weight (used only if * the connector is not a CONNECTOR_RANDOM). * * Add a new connection to a connector. If this addition requires * a new block of storage, then create it, copy the relevant info * and delete the old lists. * */ void reverse_connector_output_class::add_connection(nsl_data* new_value, name_class *name, float initial_value) { nsl_data** temp; name_class** temp_names; nsl_vector* temp_weights; #ifdef DEBUG cout << "Add connection: " << *new_value sp << *name nl; cout.flush(); #endif if(num_pointers == num_allocated) { /* Allocate a new block. */ num_allocated += ALLOC_BLOCK; /* New arrays. */ temp = new nsl_data*[num_allocated]; temp_names = new name_class*[num_allocated]; temp_weights = new nsl_vector(num_allocated); /* Copy information. */ bcopy(pointers, temp, sizeof(nsl_data *) * num_pointers); bcopy(names, temp_names, sizeof(name_class *) * num_pointers); /* Delete old arrays. */ delete pointers; delete names; pointers = temp; names = temp_names; /* Handle initial-weight arrays. */ if(!(flags&CONNECTOR_RANDOM)) { register int i; for(i = 0; i < num_pointers; ++i) temp_weights->elem(i) = initial_weights->elem(i); delete initial_weights; initial_weights = temp_weights; } } /* Assign new connection. */ pointers[num_pointers] = new_value; names[num_pointers] = name; if(!(flags&CONNECTOR_RANDOM)) initial_weights->elem(num_pointers) = initial_value; num_pointers++; #ifdef DEBUG cout << "end connect" nl; cout.flush(); #endif } /* * void reverse_connector_output_class::set_values(nsl_vector in) //OVERLOAD CALL: set_values: reverse_connector.c(reverse_connector_output_class), sensor.c(sensor_class), sensor.c(sensor_class) * * Set the output activity values. * */ void reverse_connector_output_class::set_values(nsl_vector& in) { register int i; if(in.get_xn() != num_pointers) { cmd_error("reverse_connector_output_class::set_values() : index mismatch"); //OVERLOAD CALL: set_values: reverse_connector.c(reverse_connector_output_class), sensor.c(sensor_class), sensor.c(sensor_class) cmd_error("vector input : ", in.get_xn()); cmd_error("number of pointers : ", num_pointers); exit(0); } for(i = 0; i < num_pointers; ++i) contributions[i].elem() = in.elem(i); } /* * nsl_vector reverse_connector_output_class::get_initial_weights(nsl_data* offset) * * <offset> = weight offset for random weights * * Return a vector of initial weights. * If CONNECTOR_RANDOM is set in the status, then the weights are * randomly selected. Otherwise, they are copied from the * connector's <initial_weights> vector. * If CONNECTOR_NORMALIZE is selected, then the weights are * L1-normalized. * */ nsl_vector reverse_connector_output_class::get_initial_weights (nsl_data* offset, nsl_data* weight_min, nsl_data* weight_max) { #ifdef DEBUG cout << "*** Entered reverse_connector_output_class::get_initial_weights ***" nl; cout.flush(); #endif nsl_vector out(num_pointers); if(flags & CONNECTOR_RANDOM) { /* Random case. */ #ifdef DEBUG cout << "*** reverse_connector_output_class::get_initial_weights : before random ***" nl; cout.flush(); #endif random(out); //OVERLOAD CALL: random: funcs.c(?), funcs.c(?) #ifdef DEBUG cout << "*** reverse_connector_output_class::get_initial_weights : after random ***" nl; cout.flush(); #endif out = *offset + out; } else { /* Copy from initial weights. */ register int i; for(i = 0; i < num_pointers; ++i) out.elem(i) = initial_weights->elem(i); } #ifdef DEBUG cout << "*** reverse_connector_output_class::get_initial_weights : before normalize ***" nl; cout.flush(); #endif if(flags & CONNECTOR_NORMALIZE) /* Normalize. */ out = out/out.sum(); if(flags & CONNECTOR_NEW_NORMALIZE) /* Normalize. */ out = new_normalize(out, weight_min, weight_max); if(flags & CONNECTOR_CLIP_NORMALIZE) out = NSLsat(out, 0, 1, weight_min->elem(), weight_max->elem()); #ifdef DEBUG cout << "*** End reverse_connector_output_class::get_initial_weights ***" nl; cout.flush(); #endif return out; } /* * name_class* reverse_connector_output_class::get_name(int i) //OVERLOAD CALL: get_name: column.c(column_class), connector.c(connector_class), gate.c(gate_class), layer.c(layer_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class), sensor.c(sensor_class) * * <i> = index of connection. * * Return the name of a particular connection (source name). * */ name_class* reverse_connector_output_class::get_name(int i) { /* Check for proper index. */ if(i >= 0 && i < num_pointers) return names[i]; else { cmd_error("*** reverse_connector_output_class::get_name ***"); cmd_error("bad index: ", i); exit(0); } } /* * int reverse_connector_output_class::get_num_connections() //OVERLOAD CALL: get_num_connections: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class) * * Return the number of connections. * */ int reverse_connector_output_class::get_num_connections() { return num_pointers; } /* * short reverse_connector_output_class::get_flags() //OVERLOAD CALL: get_flags: connector.c(connector_class), reverse_connector.c(reverse_connector_output_class) * * Return the configuration flags. * */ short reverse_connector_output_class::get_flags() { return flags; } /* * void reverse_connector_output_class::init_contributions() * * Initialize the output contributions list, now that num_pointers * has been established. MUST BE CALLED AFTER all connections are * established and BEFORE contributing arrays are initialized * (input class). * */ void reverse_connector_output_class::init_contributions() { contributions = new nsl_data[num_pointers]; } /* * nsl_data** reverse_connector_output_class::get_contributing_array() * * Return a pointer to the contributing array. * */ nsl_data** reverse_connector_output_class::get_contributing_array() { return &contributions; } /* * nsl_vector reverse_connector_output_class::get_values() //OVERLOAD CALL: get_values: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class), sensor.c(sensor_class) * * Return a vector of output activity values. * */ nsl_vector reverse_connector_output_class::get_values() { nsl_vector out(num_pointers); register int i; for(i = 0; i < num_pointers; ++i) out.elem(i) = (*pointers[i]).elem(); return out; } /* * nsl_vector reverse_connector_output_class::get_contributing_values() * * Return a vector of the contributing values. * */ nsl_vector reverse_connector_output_class::get_contributing_values() { nsl_vector out(num_pointers); register int i; for(i = 0; i < num_pointers; ++i) out.elem(i) = contributions[i].elem(); return out; } /* * void reverse_connector_output_class::report_state(nsl_vector* v1, //OVERLOAD CALL: report_state: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class) * nsl_vector* v2, * nsl_vector* v3, * nsl_vector* v4) * * Report the state of each connection. Name, and 4 columns * of values, as determined by the parent function. * */ void reverse_connector_output_class::report_state(nsl_vector* v1, nsl_vector* v2, nsl_vector* v3, nsl_vector* v4) { int i; for(i = 0; i < num_pointers; ++i) { cout << names[i] << "\t" ; if(v1 == NULL) cout tab; else cout << v1->elem(i) tab; if(v2 == NULL) cout tab; else cout << v2->elem(i) tab; if(v3 == NULL) cout tab; else cout << v3->elem(i) tab; if(v4 == NULL) cout tab; else cout << v4->elem(i) tab; cout nl; } }