head	1.4;
access;
symbols;
locks; strict;
comment	@ * @;


1.4
date	94.07.21.03.42.25;	author rjj;	state Exp;
branches;
next	1.3;

1.3
date	94.07.21.02.31.53;	author rjj;	state Exp;
branches;
next	1.2;

1.2
date	94.07.07.04.25.39;	author rjj;	state Exp;
branches;
next	1.1;

1.1
date	94.07.01.01.18.05;	author rjj;	state Exp;
branches;
next	;


desc
@Initial implementation for the Hopfield Neural Network algorithm.  Buggy!
@


1.4
log
@Cleaned up version of the Hopfield code.
@
text
@// hopfield.c           Section: 13.2
//      Copyright 1994, Center for Computer Vision and Visualization,
//      University of Florida.  All rights reserved.
// Here we define the main Hopfield functions and data structures.
//

#include "hopfield.h"
#include "make-examplars.h"


/////////////////////////////////////////////////////////////////////////
// Hopfield_hard_limiter()
// This function implements the hard limiter function  f()  as
//    defined for the Hopfield algorithm.
// a_lp_t == linear_product( a, t )
//
IA_Image<IA_Point<int>,int>
Hopfield_hard_limiter( const IA_Image<IA_Point<int>,int> & a_lp_t,
		       const IA_Image<IA_Point<int>,int> & a      ) {

    IA_Image<IA_Point<int>,int>
	tau_eq_zero( chi_eq( a_lp_t, 0 ) ),
	tau_gt_zero( chi_gt( a_lp_t, 0 ) ),
	tau_lt_zero( chi_lt( a_lp_t, 0 ) );

    return
	a * tau_eq_zero + tau_gt_zero - tau_lt_zero;
}



/////////////////////////////////////////////////////////////////////////
// class column2D
// Convert 1D points to 2D points.
// This class is given a column index at construction time.
// Then when evaluated with  operator()  returns a 2D point
//    which always is in the same column.
// E.g.
//    c4 = column2D( 4 ); // column index == 4
//    .....
//    ... c4( 2 ) ..;            // Yields point <  2,4>
//    ... c4( -17 ) ..;          // Yields point <-17,4>

class  column2D: public IA_Closure<IA_Point<int>,IA_Point<int> > {
private:
    int column;
public:
    column2D( int c ): column( c ) {}

    IA_Point<int> operator() ( const IA_Point<int> & rowPt ) const {
	return concat( rowPt, column );
    }

    IA_Closure<IA_Point<int>,IA_Point<int> > *
    clone_self() const {
	return new column2D( *this );
    }
};



/////////////////////////////////////////////////////////////////////////
// calculate_hopfield_weights()
// This function calculates the weight array, which is of size NxN
//
// NOTE: Ref: The C++ Programming Language, p. 129
void
calculate_hopfield_weights(
    const IA_Image<IA_Point<int>,int> & examplars,
    int ** w, // w is NxN
    const unsigned int N ) {

    // Extract the number of examplars
    int K( examplars.domain().sup()( 0 )
	   - examplars.domain().inf()( 0 ) + 1 );

    IA_Set<IA_Point<int> >
	K_1D( IA_boxy_pset( IA_Point<int>( 0 ), IA_Point<int>( K-1 ) ) );

    int i, j, wij;
    int * wi = (int *) w;  // Claim w is just a simple pointer
    for( i=0; i<N; i++ ) {
	// The diagonal should be zero
	wi[ i*N+i ] = 0;

	// Now fill in the lower and upper half, which is symmetric
	for( j=0; j<i; j++ ) {
	    column2D  fi( i ), fj( j );  // Declare column functions

	    // Don\'t you just love multi-dimensional arrays ?
	    wij = sum( compose( examplars, fi, K_1D )
		       * compose( examplars, fj, K_1D ) );
	    wi[ i*N+j ] = wij;
	    wi[ j*N+i ] = wij;
	}
    }
    // That\'s all folks !
}


/////////////////////////////////////////////////////////////////////////
// class HopfieldTemplate
// Declare the Hopfield template, which is based on the examplars.
// We assume the examplars are all of the same cardinality.
//

// Define the copy constructor
HopfieldTemplate::
HopfieldTemplate( const HopfieldTemplate & ht )
:IA_ClosureDT<IA_Image<IA_Point<int>,int> >( ht.domain() ),
 N( ht.N ),
 weights_p( (int **) new int[ht.N * ht.N] ) {

    int * wp  = (int *) weights_p;

    int * htwp = (int *) ht.weights_p;

    for( int i=0; i<N*N; i++ ) {
	*(wp++) = *(htwp++);
    }
}



// Initialize the template with the examplars
HopfieldTemplate::
HopfieldTemplate( IA_Image<IA_Point<int>,int> * e_array,
		  unsigned int                  e_array_size )
:IA_ClosureDT<IA_Image<IA_Point<int>,int> >( e_array[0].domain() ) {

    N = e_array[0].domain().card();

    // Initialize the weights
    weights_p = (int **) new int[N*N];

    if ( weights_p == 0 ) {
	ia_throw( IA::INVALID_OPERATION, __FILE__, __LINE__ );
	N = 0;
    }

    calculate_hopfield_weights(
	make_examplars_image( e_array, e_array_size ),
	weights_p, N );
}


HopfieldTemplate::
HopfieldTemplate( const IA_Image<IA_Point<int>,int>  & weight_image_ )
:IA_ClosureDT<IA_Image<IA_Point<int>,int> >(
    // Our domain is 1D, the width of the weight_image_,
    //    which had better have domain() = {<0,0>..<N-1,N-1>}
    IA_boxy_pset( IA_Point<int>( 0 ),
		  IA_Point<int>( weight_image_.domain().sup()( 0 ) ) ) ) {

    N = weight_image_.domain().sup()( 0 ) + 1;
    calculate_hopfield_weights( weight_image_, weights_p, N );
}



// We have to remember to delete the storage allocated by this guy
HopfieldTemplate::
~HopfieldTemplate() { delete[] weights_p; }



// Return a 1D image which is of cardinality  N
IA_Image<IA_Point<int>,int>
HopfieldTemplate::operator() ( const IA_Point<int> & oneDpoint ) const {

    // The image we want to return is the row indicated by oneDpoint.
    // The image will have be defined over the set { <0>..<N-1> }

    // We could assume that we know how the data vector is arranged in
    //    the weight image, but it is safer to make our own vector
    //    and hand that off to the the image constructor.

    int i = oneDpoint(0);
    int * values = &( ((int *) weights_p)[ i*N ] );

    return
	IA_Image<IA_Point<int>,int>(
	    IA_boxy_pset( IA_Point<int>( 0 ),
			  IA_Point<int>( N - 1 ) ),
	    values, N );
}


IA_ClosureDT<IA_Image<IA_Point<int>,int> > *
HopfieldTemplate::clone_self() const {
    return
	new HopfieldTemplate( *this );
}


// Return the weight_image we are based on.
IA_Image<IA_Point<int>,int>
HopfieldTemplate::weight_image() const {

    return
	IA_Image<IA_Point<int>,int>(
	    IA_boxy_pset( IA_Point<int>(   0,   0 ),
			  IA_Point<int>( N-1, N-1 ) ),
	    (int *) weights_p,  N*N );
}
@


1.3
log
@This version works, but still needs to be cleaned up.
  I'm checking it in while I know it works.
@
text
@d104 1
a104 1
// We assume the examplares are all of the same cardinality.
a170 1
    // The target point of the template image is its origin.
d172 1
a172 3
    // The image will have width  N, but the target
    //    should center at offset  oneDpoint from the start of the
    //    image values.
a180 12

    // Note that the target pixel of the template image should be
    //    at <0>, but this should match   values[ i ], thus
    //    the domain of the image is [-i, N-1-i]
    if (values[i] != 0) {
	for( int j=0; j<N; j++ ) {
	    cerr << values[j]
		 << ((j+1)%11 == 0 ? "\n" : " " );
	    if (j==N-1) cerr << endl;
	}
    }

a182 2
//	    IA_boxy_pset( IA_Point<int>( -i ),
//			  IA_Point<int>( N - 1 - i ) ),
@


1.2
log
@Bug fixes.
@
text
@d22 1
a22 1
	tau_eq_zero( chi_eq( a_lp_t - a, 0 ) ),
d111 2
a112 1
 N( ht.N ) {
a113 1
    weights_p = (int **) new int[N*N];
d188 7
d198 4
a201 2
	    IA_boxy_pset( IA_Point<int>( -i ),
			  IA_Point<int>( N - 1 - i ) ),
@


1.1
log
@Initial revision
@
text
@d8 1
a8 1
#include "hopfield-weights.h"
d15 1
d33 70
a102 1
// class Hopfield_template
d107 18
d126 3
a128 3
Hopfield_template::
Hopfield_template( IA_Image<IA_Point<int>,int> * e_array,
		   unsigned int                  e_array_size )
d131 15
a145 1
    number_of_nodes = e_array[0].domain().card();
d147 10
a156 1
    weight_image = hopfield_weight_image( e_array, e_array_size );
a159 4
Hopfield_template::
Hopfield_template( const IA_Set<IA_Point<int> > & ht_domain,
		   const IA_Image<IA_Point<int>,int>  & weight_image_ )
:IA_ClosureDT<IA_Image<IA_Point<int>,int> >( ht_domain ) {
d161 3
a163 1
    number_of_nodes = ht_domain.card();
a164 2
    weight_image = weight_image_;
}
d169 1
a169 1
Hopfield_template::operator() ( const IA_Point<int> & oneDpoint ) const {
d173 1
a173 1
    // The image will have width  number_of_nodes, but the target
d177 1
a177 1
    // We could assume that we know how the data vector in arranged in
a180 1
    int * values = new int[ number_of_nodes ];
d182 1
a182 5
    IA_Point<int> ip( i, 0 );
    for ( int j=0; j<number_of_nodes; j++ ) {
	ip[ 1 ] = j;
	values[ j ] = this->weight_image( ip );
    }
d187 1
a187 2
    //    the domain of the image is [-1, N-1-i] where
    //    N = number_of_nodes
a188 1
    int ASSUME_STORAGE_MGT = 1;  // We let the iac++ library have it.
d192 2
a193 4
			  IA_Point<int>( number_of_nodes - 1 - i ) ),
	    values,
	    number_of_nodes,
	    ASSUME_STORAGE_MGT );
d198 1
a198 1
Hopfield_template::clone_self() const {
d200 1
a200 2
	new Hopfield_template( this->domain(),
			       this->weight_image );
d203 11
@
