ftp.nice.ch/pub/next/developer/objc/ai/NeuralNetwork.N.bs.tar.gz#/Neural-Network/Neuron-HT.m

This is Neuron-HT.m in view mode; [Download] [Up]

/*$Log:	Neuron.m,v $
Revision 1.4  92/01/14  21:19:46  zazula
Check in before starting HashTable mod

Revision 1.3  92/01/02  14:04:31  zazula
Faster linked-list for connections
No more Storage object

Revision 1.2  92/01/02  12:41:34  zazula
Initial version - support for stochastic networks via temperature T
*/
#import "Neuron.h"
#import <appkit/nextstd.h>
#import "math.h"


//----------------------------------------------------------

@implementation Neuron

- inputs { return inputs; }
- setType:(int)type { nodeType = type; return self; }
- (int)getType { return nodeType; }
- setTemp:(double)newT { T = newT; return self; }
- (double)getTemp { return T; }
- setRandom:theRandom { random = theRandom; return self; }

//----------------------------------------------------------

- (double)activation:(double)net
{
   double   temp;
	
	if(random == nil) random = [[Random alloc] init];
   switch (nodeType) {
   case Binary :
      if(T > 0.0)
         temp = ([random percent] <= 1.0/(1.0+exp(-2*net/T))) ? 1.0 : 0.0;
      else
         temp = (net > 0.5) ? 1.0 : 0.0;
      break;
   case Sigmoid : 
      temp = 1.0/(1.0+exp(-net));
      break;
   case Sign : 
      if(T > 0.0)
         temp = ([random percent] <= 1.0/(1.0+exp(-2*net/T))) ? 1.0 : -1.0;
      else
         temp = (net > 0.0) ? 1.0 : -1.0;
      break;
   case Tanh :
		if(T > 0.0)
			temp = tanh(net/T);
		else
      	temp = tanh(net);
      break;
   }
   
   return temp;
}

//----------------------------------------------------------

- init
{
   [super init];
   lastOutput = 0.0;
   nodeType = Sigmoid;        // default node type
   T = 0.0;                   // default temperature
  	head = tail = NULL;			// initialize the linked-list of connections
	ht = [[HashTable alloc] initKeyDesc:"@" valueDesc:"i"];
	
   return self;
}

//-----------------------------------------------------------

- step
// update the output value based on our inputs
{
   int i = 0;
//   connection *C;
   double temp=0.0;     // use temp variable to allow for feedback
	NXHashState state = [ht initState];
	double *weight;
	id		 source;
	   
//	C = head;
//	while(C != NULL) {
//		temp += C->weight*[C->source lastOutput];
//		C = (connection *)C->next;
//	}
	while([ht nextState:&state key:&source value:&weight]) {
		temp += *weight * [source lastOutput];
	}
		
   lastOutput = [self activation:temp];
   
   return self;
}

//-----------------------------------------------------------

- (double)lastOutput
{
   return lastOutput;
}

//-----------------------------------------------------------

- connect:sender
{
	if(random == nil) random = [[Random alloc] init];
   return [self connect:sender withWeight:[random percent]/10.0];
}

//-----------------------------------------------------------

- connect:sender withWeight:(double)weight
//
// adds sender to the list of inputs
// we should check to make sure sender is a Neruon
// also need to check if it is already in the list
//
{
/*
   connection *C;
   
   C = (connection *)malloc(sizeof(connection));
	if(head == NULL) {
		head = C;
	}
	else {
		tail->next = C;
	}
	tail = C;
   C->source = sender;
   C->weight = weight;
	C->next   = NULL;
*/
	double	*value = malloc(sizeof(double));
	*value = weight;
	[ht insertKey:sender value:value];
	      
   return self;
}

//-----------------------------------------------------------

- (double)getWeightFor:source
{
/*
   int i=0;
   connection *C;

	C = head;
	while((C != NULL) && (C->source != source))
		C = (connection *)C->next;
		
   if(C != NULL) {            // if C==NULL, source isn't an input
      return C->weight;
   }
   else {
      fprintf(stderr,"connection not found in getWeightFor:\n");
      return NAN;
   }
*/
	return *(double *)[ht valueForKey:source];	
}

//-----------------------------------------------------------

- setWeightFor:source to:(double)weight
{
/*
   int i=0;
   connection *C;
   
	C = head;
	while((C != NULL) && (C->source != source))
		C = (connection *)C->next;
		
   if(C != NULL) {            // if C==NULL, source isn't an input
      C->weight = weight;
      return self;
   }
   else {
      fprintf(stderr,"connection not found in setWeightFor:to:\n");
      return nil;
   }
*/
	*(double *)[ht valueForKey:source] = weight;
	return self;
}

//-----------------------------------------------------------

- setOutput:(double)output
{
   lastOutput = output;
   
   return self;
}
//-----------------------------------------------------------

- changeWeightFor:source by:(double)delta
{
/*
   int i=0;
   connection *C;
   
	C = head;
	while((C != NULL) && (C->source != source))
		C = (connection *)C->next;
		
   if(C != NULL) {            // if C==NULL, source isn't an input
      C->weight += delta;
		if(SYMMETRIC) // for symmetric connections
   		[source setWeightFor:self to:C->weight];
      return self;
   }
   else {
      fprintf(stderr,"connection not found in changeWeightfor:by:\n");
//      printf("connection not found in changeWeightfor:by:\n");
      return nil;
   }
*/
	*(double *)[ht valueForKey:source] += delta;
	[source setWeightFor:self to:[self getWeightFor:source]];
	
	return self;
	
}


@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.