[ return ]

reverse_connector.c



/*
 *  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;
    }
}


[ return ]