/* SENSES_TO_FEATURE_VECTOR.P */ section $-senses_to_feature_vector => retina_into_feature_vector, retina_to_feature_vector; /* SPECIFICATION ------------- 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. 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. 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. */ /* IMPLEMENTATION -------------- I don't think there's much to say about this. If Bug acquires any other senses that are complicated to convert, the conversion routines should be added to this module. */ needs retina; define retina_into_feature_vector( retina, base, proc, v ); lvars retina, base, proc, v; lvars xmax, ymax, x, y, i, fv, fv_size; retina_bounds( retina ) -> ymax -> xmax; for x to xmax do for y to ymax do proc( retina( x, y ) ) -> fv; datalength( fv ) -> fv_size; for i to fv_size do fv(i) -> v(base + i-1); endfor; base + fv_size -> base; endfor; endfor; enddefine; define retina_to_feature_vector( retina, proc ); lvars retina, proc; lvars xmax, ymax, x, y, i, c, fv, fv_size; retina_bounds( retina ) -> ymax -> xmax; {% for x to xmax do for y to ymax do proc( retina( x, y ) ).explode endfor; endfor; %} enddefine; endsection;