[ return ]

column.c



/*
 * file: column.c
 *
 *  Name                Date        Description
 *  --------------      --------    -------------------------------------
 *  Andrew H. Fagg      09/05/93    Original
 *
 *
 *
 *
 * [DEFINE DESCRIPTION = Neural column class]
 *
 */

#include "nsl_include.h"
#include "column.h"
#include "alib.h"
#include "gen.h"

/*#define DEBUG */
/* #define DEBUG2*/

/*
  * column_class::column_class(char* local_name, name_class* parent,
  *
  *  Create a column object.  Sets up connector and creates gates.
  *
  */

column_class::column_class(char* local_name, name_class* parent,
			    short sensor_weight_flags,
			    column_parms_class*  cparms,
			    int n_gates,
			    short gate_weight_flags,
			    gate_parms_class* gparms)
{
  int i;
  char nm[10];			/* Temporary name for gates */

				/* Create name */
  name = new name_class(local_name, parent);

#ifdef DEBUG
  cout << "*** column_class::column_class() :" << name << " ***" nl;
#endif

				/* Create connectors. */
  sensory_connector = new connector_class(sensor_weight_flags);

				/* NULL weight vectors for now. */
  sensory_weights = NULL;
				/* Parameters. */
  parms = cparms;

				/* Create gates */
  num_gates = n_gates;

  gates = new gate_class*[num_gates]; /* Gate array */

				/* Create individual gates */
  for(i = 0; i < num_gates; ++i)
    {
      sprintf(nm, "%02d", i);	/* Compute local name. */

				/* Create gate. */
      gates[i] = new gate_class(nm, name, gate_weight_flags,
				gparms);
    }
}

/*
 *  column_class::~column_class()
 *
 *  Column class destructor : delete allocated vars and gates.
 */

column_class::~column_class()
{
  int i;

				/* Connector and weights */
  delete sensory_connector;
  if(sensory_weights != NULL)
      delete sensory_weights;

  delete name;			/* Name */

				/* Delete gates. */
  for(i = 0; i < num_gates; ++i)
    delete gates[i];
}

/*
  * void column_class::init_weights()        //OVERLOAD CALL: init_weights: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
  *
  *  Intialize the weight vectors.  First create, and then set
  * the vectors to the initial values stored in the connectors.
  *
  */

void column_class::init_weights()
{
#ifdef DEBUG
  cout << "*** Init weights for " << name << " ***" nl;
#endif

  int weight_size;
  int i;

				/* Priming connector */
				/* How big is vector? */
  weight_size = sensory_connector->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)
  if(weight_size != 0)
    {
				/* Create weight vector */
      sensory_weights = new nsl_vector(weight_size);
				/* Get initial values. */
      *sensory_weights = sensory_connector->get_initial_weights(0,0,0);
    }

				/* Init the gate weights. */
  for(i = 0; i < num_gates; ++i)
    gates[i]->init_weights();        //OVERLOAD CALL: init_weights: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
}

			


/*
  * void column_class::clear_activities()        //OVERLOAD CALL: clear_activities: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
  *
  *  Set all activity values of the column to 0.
  *
  */

void column_class::clear_activities()
{
  int i;

#ifdef DEBUG
  cout << "*** column_class::clear_activities() : " << name << " ***" nl;        //OVERLOAD CALL: clear_activities: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
#endif
  collector_mem = 0;
  collector = 0;
  sensory_mem = 0;
  sensory = 0;
  output_mem = 0;
  output = 0;
  pet_pos = 0;
  pet_neg = 0;
				/* Clear gate states. */
  for(i = 0; i < num_gates; ++i)
    gates[i]->clear_activities();        //OVERLOAD CALL: clear_activities: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
}


/*
  * void column_class::forward_mem()        //OVERLOAD CALL: forward_mem: column.c(column_class), layer.c(layer_class)
  *
  *  Compute the membrane potential of the output unit,
  * with all supporting inputs: gates, collector, and sensory unit.
  *
  */

void column_class::forward_mem()
{
  int i;

#ifdef DEBUG
  cout << "*** column_class::forward_mem() " << name << " ***" nl;        //OVERLOAD CALL: forward_mem: column.c(column_class), layer.c(layer_class)
#endif

  pet_pos = 0;
  pet_neg = 0;

				/* Compute gate states */
  for(i = 0; i < num_gates; ++i)
    gates[i]->forward();

				/* Gates to collector */
  collector_mem = 0;

  for(i = 0; i < num_gates; ++i)
      collector_mem = collector_mem + *gates[i]->get_support();

				/* PET contribution from gates */
  if(parms->pet_flag->elem() == 1.0)
    {
      for(i = 0; i < num_gates; ++i)
	{
	  pet_pos = pet_pos + gates[i]->get_pet_pos();        //OVERLOAD CALL: get_pet_pos: column.c(column_class), gate.c(gate_class)
	  pet_neg = pet_neg + gates[i]->get_pet_neg();        //OVERLOAD CALL: get_pet_neg: column.c(column_class), gate.c(gate_class)
	};
    };

				/* Collector activity value. */
  collector = elevatedSAT(collector_mem,         //OVERLOAD CALL: elevatedSAT: funcs.c(?), funcs.c(?)
			parms->collector_kx1->elem(),
			parms->collector_kx2->elem(),
			parms->collector_ky1->elem(),
			parms->collector_ky2->elem(),
			parms->collector_ky3->elem());

				/* Sensory unit */
  if(sensory_connector->get_num_connections() > 0)        //OVERLOAD CALL: get_num_connections: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class)
    {
      sensory_mem = (*sensory_weights ^ sensory_connector->get_values()).sum();        //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)

				/* Compute PET contribution */
      if(parms->pet_flag->elem() == 1.0)
	{
	  pet_pos = pet_pos + 
	    (NSLramp(*sensory_weights ^ sensory_connector->get_values())).sum();        //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)
	  pet_neg = pet_neg + 
	    (NSLramp(- *sensory_weights ^ sensory_connector->get_values())).sum();        //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)
	};      
    }
  else				/* No inputs */
    sensory_mem = 0;

				/* Sensory activity value. */
				/* Note that kx2 is used as a gain here. */
				/*   bad notation?  yes.  but it is  */
				/*   convenient. */
  sensory = 
    NSLramp(sensory_mem, parms->sensory_kx1->elem(),
		                parms->sensory_ky1->elem(),
		                parms->sensory_ky2->elem());

				/* Apply gain only if above threshold */
  if(sensory.elem() > parms->sensory_ky2->elem())
    {
      sensory.elem() = 
	parms->sensory_kx2->elem() *
	  (sensory.elem() - parms->sensory_ky2->elem())
	    + parms->sensory_ky2->elem();
    }

				/* Output unit (membrane potential). */
  DIFF.eq(output_mem, *parms->tau) =
    -output_mem + collector + sensory;

				/* Hard lower limit */
  if(output_mem.elem() < parms->minimum_output_mem->elem())
    output_mem.elem() = parms->minimum_output_mem->elem();

}


/*
  * void column_class::forward_act();        //OVERLOAD CALL: forward_act: column.c(column_class), layer.c(layer_class)
  *
  *  Compute the activity level of the output unit.  Note
  * membrane potential is computed first over the entire network
  * (thus implementing a parallel update scheme).
  *
  */

void column_class::forward_act()
{
/*
  output = threshlog(output_mem, parms->output_kx1->elem(),        //OVERLOAD CALL: threshlog: funcs.c(?), funcs.c(?)
//		              parms->output_kx2->elem(),
		              parms->output_ky1->elem(),
		              parms->output_ky2->elem());
*/
  output = threshexp(output_mem, parms->output_kx1->elem(),        //OVERLOAD CALL: threshexp: funcs.c(?), funcs.c(?)
		              parms->output_ky1->elem(),
		              parms->output_ky2->elem(),
		              parms->output_kx2->elem());
}

/*
 * name_class* column_class::get_name()        //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)
 *
 *  Return the column name.
 */

name_class* column_class::get_name()
{
  return name;
}


/*
 * nsl_data* column_class::get_collector()        //OVERLOAD CALL: get_collector: layer.c(layer_class), column.c(column_class)
 *
 * Return a pointer to the activation level of the column.
 *
 */

nsl_data* column_class::get_collector()
{
  return &collector;
}

/*
 * nsl_data* column_class::get_collector_mem()        //OVERLOAD CALL: get_collector_mem: column.c(column_class), layer.c(layer_class)
 *
 *  Return a pointer to the membrane potential level of the column.
 *
 */

nsl_data* column_class::get_collector_mem()
{
  return &collector_mem;
}

/*
 * nsl_data* column_class::get_sensory()        //OVERLOAD CALL: get_sensory: layer.c(layer_class), column.c(column_class)
 *
 * Return a pointer to the activation level of the column.
 *
 */

nsl_data* column_class::get_sensory()
{
  return &sensory;
}

/*
 * nsl_data* column_class::get_sensory_mem()        //OVERLOAD CALL: get_sensory_mem: column.c(column_class), layer.c(layer_class)
 *
 *  Return a pointer to the membrane potential level of the column.
 *
 */

nsl_data* column_class::get_sensory_mem()
{
  return &sensory_mem;
}



/*
 * nsl_data* column_class::get_output()        //OVERLOAD CALL: get_output: layer.c(layer_class), column.c(column_class)
 *
 * Return a pointer to the activation level of the column.
 *
 */

nsl_data* column_class::get_output()
{
  return &output;
}

/*
 * nsl_data* column_class::get_output_mem()        //OVERLOAD CALL: get_output_mem: column.c(column_class), layer.c(layer_class)
 *
 *  Return a pointer to the membrane potential level of the column.
 *
 */

nsl_data* column_class::get_output_mem()
{
  return &output_mem;
}


/*
 * nsl_vector* column_class::get_sensory_weights()
 *
 * Return a pointer to the sensory weight vector.
 *
 */

nsl_vector* column_class::get_sensory_weights()
{
  return sensory_weights;
}

/*
 * connector_class* column_class::get_sensory_connector()
 *
 *  Return a pointer to the column sensory connector.
 *
 */

connector_class* column_class::get_sensory_connector()
{
  return sensory_connector;
}



/*
  * connector_class* column_class::get_gate_connector(int gate, int unit)        //OVERLOAD CALL: get_gate_connector: column.c(column_class), layer.c(layer_class)
  *
  *  Return the connector of the specified gate and unit.
  *
  */

connector_class* column_class::get_gate_connector(int gate, int unit)
{
  if(gate < 0 || gate >= num_gates)
    {
      cout << "column_class::get_gate_connector(): " << name        //OVERLOAD CALL: get_gate_connector: column.c(column_class), layer.c(layer_class)
	<< "error : index must be between 0 and " << num_gates-1 << "." nl;
      return NULL;
    }
  return gates[gate]->get_connector(unit);
}

/*
 * void unit_class::report_column()        //OVERLOAD CALL: report_column: column.c(column_class), layer.c(layer_class)
 *
 *  Print out all unit state information.
 *
 */

void column_class::report_column(int gate_flag, int connector_flag)
{
  int i;

  cout nl << "--------------------------" nl;
  cout << "Unit: " << name nl;
  cout << "collector mem = \t" << collector_mem;
  cout << "collector act = \t" << collector;
  cout << "sensory mem = \t" << sensory_mem;
  cout << "sensory act = \t" << sensory;
  cout << "output mem = \t" << output_mem;
  cout << "output act = \t" << output;
  cout nl;

  if(connector_flag)
    {
      cout nl << "Sensory Connector" nl;
      if(sensory_connector->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)
	{
	  nsl_vector tmp = sensory_connector->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)
	  sensory_connector->report_state(sensory_weights, &tmp, NULL, NULL);        //OVERLOAD CALL: report_state: connector.c(connector_class), reverse_connector.c(reverse_connector_input_class), reverse_connector.c(reverse_connector_output_class)
	}
      else
	cout << "Empty" nl;
    }
  if(gate_flag)
    {
      cout nl << "GATES:" nl;
      for(i = 0; i < num_gates; ++i)
	gates[i]->report_gate(connector_flag);        //OVERLOAD CALL: report_gate: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
    }
}


/*
  * void column_class::report_gate(int index, int connector_flag)        //OVERLOAD CALL: report_gate: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
  *
  *  Report information about a single gate.
  *
  */

void column_class::report_gate(int index, int connector_flag)
{
  if(!num_gates)
    {
      cout << "column_class::report_gate() " << name        //OVERLOAD CALL: report_gate: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
	<< "error : no gates to report." nl;
      return;
    }
  if(index < 0 || index >= num_gates)
    {
      cout << "column_class::report_gate() " << name        //OVERLOAD CALL: report_gate: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
	<< "error : index must be between 0 and "
	  << num_gates - 1 nl;
      return;
    }
  gates[index]->report_gate(connector_flag);        //OVERLOAD CALL: report_gate: column.c(column_class), gate.c(gate_class), layer.c(layer_class)
}

int column_class::stuff(ifstream& netfile)
{
  int size;
  int i;
  char tmp[STRSIZE];

  netfile >> size;

#ifdef DEBUG2
  cout << "Reading column " << name << ", number of gates = " << size nl;
#endif
				/* Check to make sure size is legal */
  if(size < 0 || size > num_gates)
    {
      cout << "stuff(): " << name << ".  Size must be between 0 and "        //OVERLOAD CALL: stuff: gate.c(gate_class), layer.c(layer_class), column.c(column_class), connector.c(connector_class)
	<< num_gates << " (" << size << ")." nl;
      return 0;
    }
				/* Read the set of gates */
  for(i = 0; i < size; ++i)
    {
      netfile >> tmp;		/* Get the gate header */
      if(strncmp(tmp, "gate", STRSIZE))
	{
	  cout << "Stuffing column " << name << ", expected gate, but got:" nl;
	  cout << tmp;
	  return 0;
	}
      netfile >> tmp;		/* Get the gate name */

				/* Read the gate from the file */
      if(!gates[i]->stuff(netfile))        //OVERLOAD CALL: stuff: gate.c(gate_class), layer.c(layer_class), column.c(column_class), connector.c(connector_class)
	return 0;

				/* Now get the sensory connector */
      netfile >> tmp;		/* support connector header: 'sensory' */
      if(strncmp(tmp, "sensory", STRSIZE))
	{
	  cout << "Stuffing column " << name << ", expected sensory, but got:" nl;
	  cout << tmp nl;
	  return 0;
	}
      netfile >> tmp;		/* Get 'connector' */
      if(strncmp(tmp, "connector", STRSIZE))
	{
	  cout << "Stuffing column " << name << ", expected connector, but got:" nl;
	  cout << tmp nl;
	  return 0;
	}
				/* Get the connector */
      if(!sensory_connector->stuff(netfile))        //OVERLOAD CALL: stuff: gate.c(gate_class), layer.c(layer_class), column.c(column_class), connector.c(connector_class)
	return 0;
      
    }
  
  return 1;
};

/*
 * nsl_data* column_class::get_pet_pos()        //OVERLOAD CALL: get_pet_pos: column.c(column_class), gate.c(gate_class)
 *
 *  Return a pointer to the positive component of the
 * pet measure.
 *
 */

nsl_data* column_class::get_pet_pos()
{
  return &pet_pos;
}

/*
 * nsl_data* column_class::get_pet_neg()        //OVERLOAD CALL: get_pet_neg: column.c(column_class), gate.c(gate_class)
 *
 *  Return a pointer to the negative component of the
 * pet measure.
 *
 */

nsl_data* column_class::get_pet_neg()
{
  return &pet_neg;
}


[ return ]