HELP SENSES_TO_FEATURE_VECTOR                Jocelyn Paine November 1992


This module defines procedures for interfacing Bug's senses with neural
networks. Many types of net code their inputs by ``feature vectors''.
Typically, given some value, such as the character at a particular
retinal location, this would be represented as a vector, all but one of
whose elements is zero. The remaining element, its position depending on
the value, would be 1.

Building such vectors is easy for Bug's energy, inventory, and smell.
For the retina, it's a little more work, so I've provided routines to
help. You can load this library by doing
    lib senses_to_feature_vector;


Introduction
------------

The idea is illustrated by the example below:
    define encode( c );
        lvars c;
        switchon c
            case = `*` then {1 0 0 0 0 0 0};
            case = `#` then {0 1 0 0 0 0 0};
            case = `@` then {0 0 1 0 0 0 0};
            case = `T` then {0 0 0 0 1 0 0};
            case = `k` then {0 0 0 0 0 1 0};
            case = ` ` then {0 0 0 0 0 0 1};
            else
                mishap('encode: illegal character', [% c %] );
        endswitchon;
    enddefine;

This defines 'encode', a routine which maps each character into 7
inputs, all but one of which are off. The position of the on one depends
on the character. To encode the entire retina, we'd need an input vector
capable of holding 5*7 of these:
    initv( 5*7*7 ) -> v;

We could then use one of the routines from this module to call 'encode'
as necessary:
    retina_into_feature_vector( retina(), 1, encode, v );
    v =>
    ** {0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0
        0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0
        1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0
        0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0
        0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0
        0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0
        0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1
        0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1}


As another example, 'encode2' below just distinguishes between spaces
and everything else:
    define encode2( c );
        lvars c;
        switchon c
            case = ` ` then {0 1};
            else {1 0}
        endswitchon;
    enddefine;

We can apply this to the whole retina by doing:
    retina_to_feature_vector( retina(), encode2 ) =>
    ** {0 1 0 1 1 0 0 1 0 1 1 0 0 1 0 1 0 1 0 1 0 1 0 1 1 0 0 1 0 1 0
        1 0 1 0 1 0 1 1 0 0 1 0 1 0 1 0 1 1 0 0 1 1 0 0 1 0 1 0 1 0 1
        0 1 0 1 1 0 0 1}


Note the difference. retina_into_feature_vector copies into an existing
array, but retina_to_feature_vector builds a new one.


Exported procedures
-------------------

PUBLIC retina_into_feature_vector( retina, base, proc, v ):

This copies the feature vector resulting from encoding retina into the
existing vector v, starting at v(base). proc must be a procedure of one
argument and one result, proc(c). It converts a character into a vector,
as exemplified by encode and encode2 above. v can be any one-dimensional
array with a suitable datatype.

retina_into_feature_vector runs through the elements of retina, in
the order
    retina(1,1)
    retina(1,2)
    retina(1,3)
    ...
    retina(2,1)
    ...
It applies proc to each, and copies the resulting vector into v,
starting from the last free position. v must be large enough to hold the
results; elements of v that lie below v(base) or above the final result
will be untouched.


PUBLIC retina_to_feature_vector( retina, proc ):

This copies the feature vector resulting from encoding retina into a new
vector v. v will have a lower bound of 1, and an upper bound that's just
sufficient to accomodate all the results. As above, proc must be a
procedure of one argument and one result, proc(c) which converts a
character into a vector.
