# # File: connect.pl # # # # Copyright (C) 1995 Andrew H. Fagg (af0a@robotics.usc.edu) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # ############################################################ # # # # sub add_connection # # sub add_connection { local($from_layer, $from_column, $weight, $via, $to_layer, $to_column) = @_; if($parms{"d"} & $ADD_CONNECTION) { print "Adding connection: $from_layer.$from_column $weight -> $to_layer.$to_column.$via\n"; }; # Check to make sure all of the parameters # are good. if(!&member($from_layer, @LAYERS) && !&member($from_layer, @CONNECTORS) && !&member($from_layer, @OTHER_SOURCES)) { die "add_connection(): $from_layer is not a recognized source layer.\n"; } elsif(!&member($to_layer, @LAYERS) && !&member($to_layer, @CONNECTORS) && !&member($to_layer, @OTHER_SOURCES)) { die "add_connection(): $to_layer is not a recognized destination layer.\n"; } elsif($from_layer eq "") { die "add_connection(): bad from_layer ($from_column, $weight, $via, $to_layer, $to_column)"; } elsif($from_column eq "") { die "add_connection(): bad from_column ($from_layer, $weight, $via, $to_layer, $to_column)"; } elsif($weight eq "") { die "add_connection(): bad weight ($from_column, $from_layer, $via, $to_layer, $to_column)"; } elsif($via eq "") { die "add_connection(): bad via ($from_column, $from_layer, $weight, $to_layer, $to_column)"; } elsif($to_layer eq "") { die "add_connection(): bad to_layer ($from_column, $from_layer, $weight, $via, $to_column)"; } elsif($to_column eq "") { die "add_connection(): bad to_column ($from_column, $from_layer, $weight, $via, $to_layer)"; }; $net{$via, $to_layer, $to_column} .= $from_layer . "." . $from_column . ":" . $weight . ":"; }; # # sub add_to_connector # # Add a connection to a connector object # sub add_to_connector { local($from_layer, $from_column, $weight, $to_connector) = @_; if($parms{"d"} & $ADD_CONNECTION) { print "Adding connection: $from_layer.$from_column $weight -> $to_connector\n"; }; $connector{$to_connector} .= $from_layer . "." . $from_column . ":" . $weight . ":"; }; # # sub mutual_aip_support # # Possibly add a support connection from AIP unit $i to $j. # # AIP units must match in the type of grasp. # # Cases # General -> Specific: small # General -> General: med # Specific -> General: med # Specific -> Specific: med if a match in parameters (depends on degree # of match) # sub mutual_aip_support { local($i, $j) = @_; # Grasp types match? and random factor if($aip{"grasp type", $i} eq $aip{"grasp type", $j} && rand() < $AIP_AIP_SUPPORT_PROB) { if($parms{"d"} & $AIP_CONNECTION) { print "mutual_aip_support(): connecting $i -> $j\n"; }; # unit i is general if($aip{"aperture", $i} == -1) { # unit j is general if($aip{"aperture", $j} == -1) { &add_connection("AIP", $i, $AIP_AIP_GG_SUPPORT_GAIN * (1 - $AIP_AIP_GG_SUPPORT_MOD * rand()), "support connector", "AIP", $j); } else # unit j is specific { &add_connection("AIP", $i, $AIP_AIP_GS_SUPPORT_GAIN * (1 - $AIP_AIP_GS_SUPPORT_MOD * rand()), "support connector", "AIP", $j); }; } else # unit i is specific { # unit j is general if($aip{"aperture", $j} == -1) { &add_connection("AIP", $i, $AIP_AIP_SG_SUPPORT_GAIN * (1 - $AIP_AIP_SG_SUPPORT_MOD * rand()), "support connector", "AIP", $j); } else # unit j is specific { &add_connection("AIP", $i, $AIP_AIP_SS_SUPPORT_GAIN * (1 - $AIP_AIP_SS_SUPPORT_MOD * rand()) * &ngauss($aip{"aperture", $i}, $aip{"aperture", $j}, $AIP_AIP_SIZE_MATCH_STD), "support connector", "AIP", $j); }; } }; }; # # sub connect_aip_aip # # Establish the connections internal to AIP # # Rules: # Grasp type matches and aperture matches -> probability # of positive support. # # Grasp type matches and aperture significantly different -> # probability of negative support. # # Otherwise -> # probability of negative support. # # sub connect_aip_aip { local($i, $j, $num); print "Making internal AIP connections...\n"; $num = $aip{"num"}; # Look through each AIP unit. for($i = 0; $i < $num; ++$i) { # Self-recurrent sensory signal &add_connection("AIP", $i, $AIP_SELF_RECURRENT_GAIN * (1 - $AIP_SELF_RECURRENT_MOD * rand()), "sensory connector", "AIP", $i); # Global normalization term &add_connection("BG_AIP_RECURRENT", 0, $AIP_NORMALIZE_W, "support connector", "AIP", $i); # Input to global normalization term &add_connection("AIP", $i, 1, "sensory connector", "BG_AIP_RECURRENT", 0); # Set column threshold $net{"support threshold", "AIP", $i} = rand() * $AIP_THRESHOLD_GAIN; # Positive support connections for($j = 0; $j < $num; ++$j) { if($i != $j) { &mutual_aip_support($i, $j); }; }; }; }; sub connect_f5_f5 { local($i, $j, $num); print "Making internal F5 connections...\n"; $num = $f5{"num"}; # Look through each F5 unit. for($i = 0; $i < $num; ++$i) { # Self-recurrent sensory signal &add_connection("F5", $i, $F5_SELF_RECURRENT_GAIN * (1 - $F5_SELF_RECURRENT_MOD * rand()), "sensory connector", "F5", $i); # Global normalization term &add_connection("BG_F5_RECURRENT", 0, $F5_NORMALIZE_W, "support connector", "F5", $i); # Input to normalization term &add_connection("F5", $i, 1, "sensory connector", "BG_F5_RECURRENT", 0); # Set column threshold $net{"support threshold", "F5", $i} = rand() * $F5_THRESHOLD_GAIN; for($j = 0; $j < $num; ++$j) { if($i != $j) { }; }; }; }; sub connect_mcx { local($i, $num); print "Making internal Mcx connections...\n"; $num = $mcx{"num"}; for($i=0; $i<$num; ++$i) { $net{"support threshold", "Mcx", $i} = 0; # &add_connection("CONSTANT", 0, 1, # "priming connector connector", "Mcx", $i); }; }; sub connect_pip_aip { local($i, $mapelem, @objects, $obj, $objindex); local(@parms, $shape, $gain, $tmpindex); print "Making PIP->AIP connections...\n"; # Iterate through the AIP cells for($i=0; $i < $aip{"num"}; ++$i) { # AIP cell must be a set cell if($aip{"phase", $i} eq "set") { # Get list of objects that match this # grasp $obj = $ogmap{"sepobjects", $aip{"grasp type", $i}}; chop $obj; @objects = split(':', $obj); # Iterate through these objects; foreach $obj (@objects) { $objindex = $object{"index", $obj}; if($aip{"aperture", $i} == -1) { # No aperture specified: this is a general # AIP cell. if(rand() < $PIP_AIP_GENERAL_PROB) { # Connect all elements that specify # the object if($parms{"d"} & $PIP_CONNECTION) { print "Connecting $obj to AIP unit $i\n"; }; $shape = $object{"shape", $objindex}; # Get the parameters @parms = split(':', $shape{"parms", $shape}); # Number of "connections": ie 1+ #parameters $gain = 1/($#parms + 2); # Random factor. $gain *= (1 - $PIP_AIP_GENERAL_MOD * rand()) * $aip{"visual", $i} * $PIP_AIP_GENERAL_GAIN; # Connect shape descriptor $tmpindex = $shape{"index", $shape}; &add_connection("PIP", $tmpindex, $gain, "sensory connector", "AIP", $i); # Connect each parameter foreach $parm (@parms) { # Each parameter gets 2 connections $tmpindex = $object{"parameter index", $objindex, $parm}; $factor = $object{"parameter match", $objindex, $parm}; &add_connection("PIP", $tmpindex, $gain * $factor, "sensory connector", "AIP", $i); &add_connection("PIP", $tmpindex+1, $gain * (1 - $factor), "sensory connector", "AIP", $i); }; } } else { # Aperture specified - do these # two match? if(rand() < $PIP_AIP_SPECIFIC_PROB) { # Connect just the size elements # (width) if($parms{"d"} & $PIP_CONNECTION) { print "Connecting $obj (width) to AIP unit $i\n"; }; # Shape of the object $shape = $object{"shape", $objindex}; # Compute weight # random term $gain = (1 - $PIP_AIP_SPECIFIC_MOD * rand()) # visual cell? * $aip{"visual", $i} # general gain * $PIP_AIP_SPECIFIC_GAIN # measure of goodness of match * &ngauss($aip{"aperture", $i}, $object{"parameter", $objindex, "width"}, $SIZE_MATCH_STD); # print "$gain " . # &ngauss($aip{"aperture", $i}, # $object{"parameter", $objindex, "width"}, # $SIZE_MATCH_STD) . "\n"; # Which PIP unit to connect? $tmpindex = $object{"parameter index", $objindex, "width"}; $factor = $object{"parameter match", $objindex, "width"}; &add_connection("PIP", $tmpindex, $gain * $factor, "sensory connector", "AIP", $i); &add_connection("PIP", $tmpindex+1, $gain * (1 - $factor), "sensory connector", "AIP", $i); }; }; }; }; }; }; sub connect_sma { local($i); # SMA primes every AIP unit. for($i = 0; $i < $aip{"num"}; ++$i) { &add_connection("SMA", 0, 1, "priming connector", "AIP", $i); }; for($i = 0; $i < $f5{"num"}; ++$i) { &add_connection("SMA", 0, 1, "priming connector", "F5", $i); }; }; # # sub connect_aip_f5 # # Connections from AIP outputs to F5 support inputs. # # Connections made only if the grasps match. # # Cases: # General -> General # Specific -> Specific (matching parameter) # # sub connect_aip_f5 { local($i, $j, $k, $w); # Iterate through each pair of units. for($i = 0; $i < $aip{"num"}; ++$i) { for($j = 0; $j < $f5{"num"}; ++$j) { # Iterate for each grasp type this f5 # unit might have. for($k = 0; $k < $f5{"num", $j}; ++$k) { # Match of unit type and random factor. if($aip{"grasp type", $i} eq $f5{"grasp", $j, $k} && rand() < $AIP_F5_PROB) { # Both general units if($aip{"aperture", $i} == -1 && $f5{"grasp aperture", $j, $k} == -1) { $w = $AIP_F5_GEN_GAIN * (1-$AIP_F5_GEN_MOD*rand()) * $f5{"grasp response", $j, $k}; &add_connection("AIP", $i, $w, "support connector", "F5", $j); } # Both are specific units. elsif(&ngauss($aip{"aperture", $i}, $f5{"grasp aperture", $j, $k}, $AIP_F5_SIZE_MATCH_STD) > $CONNECTION_MIN) { $w = $AIP_F5_SPECIFIC_GAIN * (1-$AIP_F5_SPECIFIC_MOD*rand()) * $f5{"grasp response", $j, $k}; $w *= &ngauss($aip{"aperture", $i}, $f5{"grasp aperture", $j, $k}, $AIP_F5_SIZE_MATCH_STD); &add_connection("AIP", $i, $w, "support connector", "F5", $j); }; }; }; }; }; }; # # sub connect_trigger_context_f5 # # All "set" cells receive a trigger context input. Magnitude of the # connection is related to the response level. # sub connect_trigger_context_f5 { local($j, $k); for($j = 0; $j < $f5{"num"}; ++$j) { for($k = 0; $k < $f5{"num", $j}; ++$k) { if($f5{"phase response", $j, $k, "set"} > 0) { if($parms{"d"} & $CONNECTION_TRIG_F5) { print "Adding connection from TRIGGER 2 to F5 $j.\n"; } &add_connection("TRIGGER", 2, $f5{"phase response", $j, $k, "set"}, "sensory connector", "F5", $j); } } }; }; # # sub connect_trigger_go_f5 # # All "extension" cells receive a trigger go input. Magnitude of the # connection is related to the response level. # sub connect_trigger_go_f5 { local($j, $k); for($j = 0; $j < $f5{"num"}; ++$j) { for($k = 0; $k < $f5{"num", $j}; ++$k) { if($f5{"phase response", $j, $k, "extension"} > 0) { if($parms{"d"} & $CONNECTION_TRIG_F5) { print "Adding connection from TRIGGER 0 to F5 $j.\n"; } &add_connection("TRIGGER", 0, $f5{"phase response", $j, $k, "extension"}, "sensory connector", "F5", $j); } } }; }; # # sub connect_trigger2_go_f5 # # All "release" cells receive a trigger go input. Magnitude of the # connection is related to the response level. # sub connect_trigger2_go_f5 { local($j, $k); for($j = 0; $j < $f5{"num"}; ++$j) { for($k = 0; $k < $f5{"num", $j}; ++$k) { if($f5{"phase response", $j, $k, "release"} > 0) { if($parms{"d"} & $CONNECTION_TRIG_F5) { print "Adding connection from TRIGGER 1 to F5 $j.\n"; } # print "Adding connection from TRIGGER 1 to F5 $j.\n"; &add_connection("TRIGGER", 1, $f5{"phase response", $j, $k, "release"}, "sensory connector", "F5", $j); } } }; }; # # sub connect_f5_aip # # Connections from F5 outputs to AIP sensory inputs # # Connections made only if the grasps match. # # Cases: # General -> General # Specific -> Specific (matching parameter) # # Temporal constraints: # AIP "set" cells may receive any inputs. # "early" cells may not receive "set" input # "late" cells may not receive "set" or "extension" input. # # sub connect_f5_aip { local($i, $j, $k, $w); # Iterate through each pair of units. for($i = 0; $i < $aip{"num"}; ++$i) { for($j = 0; $j < $f5{"num"}; ++$j) { # Iterate for each grasp type this f5 # unit might have. for($k = 0; $k < $f5{"num", $j}; ++$k) { # Match of unit type, temporal aspects, # and random factor. if($aip{"grasp type", $i} eq $f5{"grasp", $j, $k} && ($f5{"phase last", $j, $k} ne "release") && ($aip{"phase", $i} eq "set" || ($aip{"phase", $i} eq "early" && $f5{"phase first", $j, $k} ne "set") || ($aip{"phase", $i} eq "late" && ($f5{"phase first", $j, $k} ne "set" && $f5{"phase first", $j, $k} ne "extension"))) && rand() < $F5_AIP_PROB) { # Both general units if($aip{"aperture", $i} == -1 && $f5{"grasp aperture", $j, $k} == -1) { $w = $F5_AIP_GEN_GAIN * (1-$F5_AIP_GEN_MOD*rand()) * $f5{"grasp response", $j, $k}; $w *= $aip{"motor", $i}; if($parms{"d"} & $CONNECTION_F5_AIP) { print "G-Connecting F5 $j to AIP $i ($w).\n"; }; &add_connection("F5", $j, $w, "sensory connector", "AIP", $i); } # Both are specific units. elsif(&ngauss($aip{"aperture", $i}, $f5{"grasp aperture", $j, $k}, $AIP_F5_SIZE_MATCH_STD) > $CONNECTION_MIN) { $w = $F5_AIP_SPECIFIC_GAIN * (1-$F5_AIP_SPECIFIC_MOD*rand()) * $f5{"grasp response", $j, $k}; $w *= &ngauss($aip{"aperture", $i}, $f5{"grasp aperture", $j, $k}, $AIP_F5_SIZE_MATCH_STD); $w *= $aip{"motor", $i}; if($parms{"d"} & $CONNECTION_F5_AIP) { print "S-Connecting F5 $j to AIP $i ($w).\n"; }; &add_connection("F5", $j, $w, "sensory connector", "AIP", $i); }; }; }; }; }; }; # # sub phase_cmp # # Compare 2 f5 phases. # Return = 1 if $p1 before $p2 # = 0 if $p1 == $p2 # = -1 if $p1 after $p2 # sub phase_cmp { local($p1, $p2) = @_; # print "PH: $p1 $p2:"; if($p1 eq $p2) { # print "EQ\n"; return 0; }; if($F5_PHASE_INDEX{$p1} < $F5_PHASE_INDEX{$p2}) { # print "before\n"; return 1; } else { # print "after\n"; return -1; } }; # # sub connect_f5_f5_int # # Internal F5 connections. # # Rules: # - A cell whose first phase comes after another's last phase will # send an inhibitory connection. # - Compatible cells that share phase will send positive connections # Four cases: G-G, S-G, G-S, S-S # # THIS ROUTINE IS NOW OBSOLETE. Functionality is now distributed # between connect_f5_f5_int_support() and the BG structures. # sub connect_f5_f5_int { local($i, $ig, $j, $jg, $w); local($comp); die "Why are you still calling connect_f5_f5_int()?"; # Loop throug each pair of f5xgrasp x f5xgrasp for($i = 0; $i < $f5{"num"}; ++$i) { for($ig = 0; $ig < $f5{"num", $i}; ++$ig) { for($j = 0; $j < $f5{"num"}; ++$j) { # print "COMPING $i $j " . $f5{"phase first", $i, $ig} . "\n"; if($i != $j) { for($jg = 0; $jg < $f5{"num", $j}; ++$jg) { # Case 1: reverse inhibition if(&phase_cmp($f5{"phase first", $i, $ig}, $f5{"phase first", $j, $jg}) < 0) { if(rand() < $F5_F5_REVERSE_INHIBITION_PROB) { $w = $F5_F5_REVERSE_INHIBITION_GAIN * (1-$F5_F5_REVERSE_INHIBITION_MOD *rand()); if($parms{"d"} & $CONNECTION_F5_F5) { print "Adding internal F5 reverse connection: $i -> $j (-$w)\n"; }; &add_connection("F5", $i, -$w, "support connector", "F5", $j); } } # Case 2 - same grasp/share phase elsif($f5{"grasp", $i, $ig} eq $f5{"grasp", $j, $jg}) { # same grasp # Scan phases and find the pair of max # compatibility. $comp = 0; foreach $phase (@F5_PHASES) { $comp = &max( $f5{"phase response", $i, $ig, $phase} * $f5{"phase response", $j, $jg, $phase}, $comp); }; if($comp > 0) # There is a match in phase. { # General->General case if($f5{"grasp aperture", $i, $ig} == -1 && $f5{"grasp aperture", $j, $jg} == -1) { # random factor if(rand() < $F5_F5_GG_MUTUAL_PROB) { $w = $comp * $F5_F5_GG_MUTUAL_GAIN * (1-$F5_F5_GG_MUTUAL_MOD*rand()); if($parms{"d"} & $CONNECTION_F5_F5) { print "Adding internal F5 GG connection: $i -> $j ($w)\n"; }; &add_connection("F5", $i, $w, "support connector", "F5", $j); } } # General->Specific case elsif($f5{"grasp aperture", $i, $ig} == -1 && $f5{"grasp aperture", $j, $jg} != -1) { # random factor if(rand() < $F5_F5_GS_MUTUAL_PROB) { $w = $comp * $F5_F5_GS_MUTUAL_GAIN * (1-$F5_F5_GS_MUTUAL_MOD*rand()); if($parms{"d"} & $CONNECTION_F5_F5) { print "Adding internal F5 GS connection: $i -> $j ($w)\n"; }; &add_connection("F5", $i, $w, "support connector", "F5", $j); } } # Specific-> General case elsif($f5{"grasp aperture", $i, $ig} != -1 && $f5{"grasp aperture", $j, $jg} == -1) { # random factor if(rand() < $F5_F5_SG_MUTUAL_PROB) { $w = $comp * $F5_F5_SG_MUTUAL_GAIN * (1-$F5_F5_SG_MUTUAL_MOD*rand()); if($parms{"d"} & $CONNECTION_F5_F5) { print "Adding internal F5 SG connection: $i -> $j ($w)\n"; }; &add_connection("F5", $i, $w, "support connector", "F5", $j); } } # Specific->Specific case elsif($f5{"grasp aperture", $i, $ig} != -1 && $f5{"grasp aperture", $j, $jg} != -1) { # random factor if(rand() < $F5_F5_SS_MUTUAL_PROB) { $w = $comp * $F5_F5_SS_MUTUAL_GAIN * (1-$F5_F5_SS_MUTUAL_MOD*rand()); $w *= &ngauss($f5{"grasp aperture", $i, $ig}, $f5{"grasp aperture", $j, $jg}, $F5_F5_SS_MUTUAL_STD); if($parms{"d"} & $CONNECTION_F5_F5) { print "Adding internal F5 SS connection: $i -> $j ($w)\n"; }; &add_connection("F5", $i, $w, "support connector", "F5", $j); } } } }; } } } } }; }; # # sub connect_f5_f5_int_support # # Internal F5 connections. Handles only the connecting of # compatible F5 cells (same type, same phase). # # Rules: # - Compatible cells that share phase will send positive connections # Four cases: G-G, S-G, G-S, S-S # sub connect_f5_f5_int_support { local($i, $ig, $j, $jg, $w); local($comp); print "Making F5->F5 connections...\n"; # Loop throug each pair of f5xgrasp x f5xgrasp for($i = 0; $i < $f5{"num"}; ++$i) { for($ig = 0; $ig < $f5{"num", $i}; ++$ig) { for($j = 0; $j < $f5{"num"}; ++$j) { # print "COMPING $i $j " . $f5{"phase first", $i, $ig} . "\n"; if($i != $j) { for($jg = 0; $jg < $f5{"num", $j}; ++$jg) { # Do the cells share the same grasp? if($f5{"grasp", $i, $ig} eq $f5{"grasp", $j, $jg}) { # same grasp # Scan phases and find the pair of max # compatibility. $comp = 0; foreach $phase (@F5_PHASES) { $comp = &max( $f5{"phase response", $i, $ig, $phase} * $f5{"phase response", $j, $jg, $phase}, $comp); }; if($comp > 0) # There is a match in phase. { # General->General case if($f5{"grasp aperture", $i, $ig} == -1 && $f5{"grasp aperture", $j, $jg} == -1) { # random factor if(rand() < $F5_F5_GG_MUTUAL_PROB) { $w = $comp * $F5_F5_GG_MUTUAL_GAIN * (1-$F5_F5_GG_MUTUAL_MOD*rand()); if($parms{"d"} & $CONNECTION_F5_F5) { print "Adding internal F5 GG connection: $i -> $j ($w)\n"; }; &add_connection("F5", $i, $w, "support connector", "F5", $j); } } # General->Specific case elsif($f5{"grasp aperture", $i, $ig} == -1 && $f5{"grasp aperture", $j, $jg} != -1) { # random factor if(rand() < $F5_F5_GS_MUTUAL_PROB) { $w = $comp * $F5_F5_GS_MUTUAL_GAIN * (1-$F5_F5_GS_MUTUAL_MOD*rand()); if($parms{"d"} & $CONNECTION_F5_F5) { print "Adding internal F5 GS connection: $i -> $j ($w)\n"; }; &add_connection("F5", $i, $w, "support connector", "F5", $j); } } # Specific-> General case elsif($f5{"grasp aperture", $i, $ig} != -1 && $f5{"grasp aperture", $j, $jg} == -1) { # random factor if(rand() < $F5_F5_SG_MUTUAL_PROB) { $w = $comp * $F5_F5_SG_MUTUAL_GAIN * (1-$F5_F5_SG_MUTUAL_MOD*rand()); if($parms{"d"} & $CONNECTION_F5_F5) { print "Adding internal F5 SG connection: $i -> $j ($w)\n"; }; &add_connection("F5", $i, $w, "support connector", "F5", $j); } } # Specific->Specific case elsif($f5{"grasp aperture", $i, $ig} != -1 && $f5{"grasp aperture", $j, $jg} != -1) { # random factor if(rand() < $F5_F5_SS_MUTUAL_PROB) { $w = $comp * $F5_F5_SS_MUTUAL_GAIN * (1-$F5_F5_SS_MUTUAL_MOD*rand()); $w *= &ngauss($f5{"grasp aperture", $i, $ig}, $f5{"grasp aperture", $j, $jg}, $F5_F5_SS_MUTUAL_STD); if($parms{"d"} & $CONNECTION_F5_F5) { print "Adding internal F5 SS connection: $i -> $j ($w)\n"; }; &add_connection("F5", $i, $w, "support connector", "F5", $j); } } } }; } } } } }; }; # # sub connect_f5_bg_phase # # A single F5 cell sends outputs to: # The phase (inhibitory bank) prior to the cell's first phase # The phase (excitatory bank) following the cell's last phase # It receives the following connections: # A positive projection (excitatory bank) from the phase # corresponding to the cell's first phase. # An inhibitory projection (inhibitory bank) from the phase # corresponding to the cell's last phase. # sub connect_f5_bg_phase { local($i, $pg); local($p); local($phase, $phase_index, $w); print "Making F5<->BG_Phase connections...\n"; # Loop through each F5 unit for($i = 0; $i < $f5{"num"}; ++$i) { $pg = $f5{"primary grasp", $i}; # Connection from F5 to BG_GRASP (neg bank) $phase = $f5{"phase first", $i, $pg}; $phase_index = $F5_PHASE_INDEX{$phase}; # If set unit(index=0, then nothing # to connect to). if($phase_index > 0) { $w = $F5_BGP_REVERSE_GAIN * (1 - $F5_BGP_REVERSE_MOD * rand()); &add_connection("F5", $i, $w, "sensory connector", "BG_PHASE", $phase_index + $#F5_PHASES); }; # Connection from F5 to BG_GRASP (pos bank) $phase = $f5{"phase last", $i, $pg}; $phase_index = $F5_PHASE_INDEX{$phase}; # If release unit(then nothing # to connect to). if($phase_index < $#F5_PHASES) { $w = $F5_BGP_FORWARD_GAIN * (1 - $F5_BGP_FORWARD_MOD * rand()); &add_connection("F5", $i, $w, "sensory connector", "BG_PHASE", $phase_index + 1); }; # Positive connection from the # excitatory bank foreach $phase (@F5_PHASES) { if($f5{"phase response", $i, $pg, $phase} > 0) { $phase_index = $F5_PHASE_INDEX{$phase}; $w = $BGP_F5_FORWARD_GAIN * (1 - $BGP_F5_FORWARD_MOD * rand()) * $f5{"phase response", $i, $pg, $phase}; &add_connection("BG_PHASE", $phase_index, $w, "support connector", "F5", $i); }; }; # Original algorithm - connect only first # phase # $phase = $f5{"phase first", $i, $pg}; # $phase_index = $F5_PHASE_INDEX{$phase}; # $w = $BGP_F5_FORWARD_GAIN * (1 - $BGP_F5_FORWARD_MOD * rand()); # &add_connection("BG_PHASE", $phase_index, # $w, # "support connector", # "F5", $i); # Negative connection from the # inhibitory bank $phase = $f5{"phase last", $i, $pg}; $phase_index = $F5_PHASE_INDEX{$phase}; $w = -$BGP_F5_REVERSE_GAIN * (1 - $BGP_F5_REVERSE_MOD * rand()); &add_connection("BG_PHASE", ($phase_index + $#F5_PHASES + 1), $w, "support connector", "F5", $i); }; }; # # sub connect_f5_bg_grasp # # Connect the BG grasp layer to F5. # # Rule: # Connect a BG cell to an F5 cell if its grasp type matches the # F5 cell's primary grasp, and the F5 cell does not have an # aperture responsiveness (ie aperture = -1). # sub connect_f5_bg_grasp { local($i); local($j, $w); print "Making BG_Grasp->F5 connections...\n"; # Loop through each F5 unit. for($i = 0; $i < $f5{"num"}; ++$i) { # Only consider the primary grasp of # this unit. $j = $f5{"primary grasp", $i}; # Only non-aperture specific cells are # connected. if($f5{"grasp aperture", $i, $j} == -1) { # print "$i primary grasp: $j\n"; # print $f5{"grasp", $i, $j} . "\n"; # print $grasp{"type index", $f5{"grasp", $i, $j}} . "\n"; $w = $BGG_F5_SUPPORT_GAIN * (1 - $BGG_F5_SUPPORT_MOD*rand()); &add_connection("BG_GRASP", $grasp{"type index", $f5{"grasp", $i, $j}}, $w, "support connector", "F5", $i); }; }; }; # # sub init_bg # # Set up the correct number of units in each BG bank. # sub init_bg { local($i); $net{"num", "BG_GRASP"} = ($#GRASP_TYPES+1); $net{"num", "BG_PHASE"} = ($#F5_PHASES+1)*2; $net{"num", "BG_F5_RECURRENT"} = 1; $net{"num", "BG_AIP_RECURRENT"} = 1; # Set up thresholds for each unit. for($i = 0; $i < $net{"num", "BG_GRASP"}; ++$i) { $net{"support threshold", "BG_GRASP", $i} = 0; }; for($i = 0; $i < $net{"num", "BG_PHASE"}; ++$i) { $net{"support threshold", "BG_PHASE", $i} = 0; }; for($i = 0; $i < $net{"num", "BG_F5_RECURRENT"}; ++$i) { $net{"support threshold", "BG_F5_RECURRENT", $i} = 0; }; for($i = 0; $i < $net{"num", "BG_AIP_RECURRENT"}; ++$i) { $net{"support threshold", "BG_AIP_RECURRENT", $i} = 0; }; }; # # sub connect_f5_bg # # Make connections between F5 and BG - two classes: # phase-related and grasp related. # sub connect_f5_bg { print "Making F5<->BG connections...\n"; &init_bg(); &connect_f5_bg_phase(); &connect_f5_bg_grasp(); }; # # sub connect_mcx_spinal # # Connect the mcx units to the spinal cord. # This connection scheme simulates projection to a spatial # coding for the desired position of the joint. In the interest # of efficiency, we eliminate the layer that explicitly # represents the spatially coded value, and instead compute it # directly. # The computation that we ultimately would perform is # sum (degree * preferred * activity) / sum(degree * activity) # # For each joint, there are 2 connectors, one whose weights are # 'degree * preferred' and the other whose weights are just 'degree'. # After we evaluate the connector state (activity * w), we divide the # result from the first connector by the result from the second. # # sub connect_mcx_spinal { local($i); local($j); local($deg, $pref); # Loop through each mcx unit for($i = 0; $i < $mcx{"num"}; ++$i) { # Loop over each joint that it projects to. for($j = 0; $j < $mcx{"num", $i}; ++$j) { # Figure out which connector $deg = $joints{"degree", $mcx{"joint", $i, $j}}; $pref = $joints{"preferred", $mcx{"joint", $i, $j}}; # Create the connections &add_to_connector("Mcx", $i, $mcx{"activity", $i, $j}, $deg); &add_to_connector("Mcx", $i, $mcx{"activity", $i, $j} * $mcx{"position", $i, $j}, $pref); }; }; }; # # sub joint_2_tip_pad_index # # Given the joint name, return the index of the finger's corresponding # tip pad. # sub joint_2_tip_pad_index { local($joint) = @_; if(&member($joint, ("t0", "t1", "t2"))) { return($pads{"index", "t0"}) } elsif(&member($joint, ("i0", "i1", "i2"))) { return($pads{"index", "i2"}); } elsif(&member($joint, ("m0", "m1", "m2"))) { return($pads{"index", "m2"}); } elsif(&member($joint, ("r0", "r1", "r2"))) { return($pads{"index", "r2"}); } elsif(&member($joint, ("l0", "l1", "l2"))) { return($pads{"index", "l2"}); } else { die "joint_2_tip_pad_index(): Bad joint name specified ($joint)\n"; }; }; # # sub connect_SI_mcx(); # # The three types of mcx cells receive different inputs: # Position: receive a constant input (so any support received # from F5 serves to drive the hand to a particular position) # Force: receives input from a finger tip pad. The first $#PADS+1 # units in SI respond to forces at the finger tips # Inverse force: receives input from the inverse force sensor # of the finger tip. The second $#PADS+1 units in SI receive # these inputs. # sub connect_SI_mcx { local($i); print "Making SI->Mcx connections...\n"; for($i = 0; $i < $mcx{"num"}; ++$i) { if($mcx{"type", $i} eq "p") { &add_connection("CONSTANT", 0, 1, "sensory connector", "Mcx", $i); } elsif($mcx{"type", $i} eq "f") { &add_connection("SI", &joint_2_tip_pad_index($mcx{"joint", $i, 0}) + ($#JOINTS+1)*$gauss_position_size, 1, "sensory connector", "Mcx", $i); } elsif($mcx{"type", $i} eq "if") { &add_connection("SI", &joint_2_tip_pad_index($mcx{"joint", $i, 0}) + $#PADS + 1 + ($#JOINTS+1)*$gauss_position_size, 1, "sensory connector", "Mcx", $i); } else { die "connect_SI_mcx(): Illegal type specified for unit $i (". $mcx{"type", $i} . ").\n"; }; }; }; # # sub init_sii # # Initialize sii structure: assign one SII unit for each grasp x SII_TYPE. # # # sub init_sii { local($i); local($type); $sii{"num"} = 0; for($i = 0; $i < $grasp{"num"}; ++$i) { foreach $type (@SII_TYPES) { $grasp{"SII", $type, $i} = $sii{"num"}; $sii{"grasp", $sii{"num"}} = $i; $sii{"type", $sii{"num"}} = $type; $net{"support threshold", "SII", $sii{"num"}} = 0; ++$sii{"num"}; }; }; $net{"num", "SII"} = $sii{"num"}; print "Created " . $sii{"num"} . " SII units.\n"; }; # # sub connect_f5_sii # # SII units are connected using the following rules: # F5 extension cells prime SII max extent cells # F5 flexion cells are activated by SII max extent cells and # prime SII contact cells # F5 hold cells are activated by contact cells # F5 release prime 'SII release cells and are in turn inhibited by them # sub connect_f5_sii { local($i); local($gr, $phase); local($grasp_i, $aperture); local($elem); print "Making F5<->SII connections...\n"; # Loop for each F5 unit for($i = 0; $i < $f5{"num"}; ++$i) { &analyze_f5_unit($i); # Compute primary grasp # Which g table to look at in this # F5 unit? $grasp_i = $f5{"primary grasp", $i}; $phase = $f5{"primary phase", $i}; # What is the type of grasp $gr = $f5{"grasp", $i, $grasp_i}; # Grasp aperture $aperture = $f5{"grasp aperture", $i, $grasp_i}; # Only aperture-specific units exchange # connections with the SII units. if($aperture != -1) { # Compute the index into the $grasp struct # print "grasp_i = $grasp_i\n"; # print "phase = $phase\n"; # print "gr = $gr\n"; # print "aperture = $aperture\n"; $grasp_ref = &translate_grasp_parms_2_id($gr, $aperture); # print "grasp_ref = $grasp_ref\n"; # if(! defined $grasp{"SII", "contact", $grasp_ref}) # { # die "undefined contact unit $i\n"; # }; if($phase eq "extension") { $elem = $grasp{"SII", "maximum extent", $grasp_ref}; # Extension units prime SII # maximum extent units. if(rand() < $F5_SII_PROB) { # print "Connecting F5.$i -> SII.$elem\n"; &add_connection("F5", $i, $F5_SII_GAIN * (1 - $F5_SII_MOD*rand()), "priming connector", "SII", $elem); }; } elsif($phase eq "flexion") { # Flexion units prime SII # contact units and are activated. # by maximum extent units. # Contact $elem = $grasp{"SII", "contact", $grasp_ref}; if(rand() < $F5_SII_PROB) { # print "Connecting F5.$i -> SII.$elem\n"; &add_connection("F5", $i, $F5_SII_GAIN * (1 - $F5_SII_MOD*rand()), "priming connector", "SII", $elem); }; # Maximum extent $elem = $grasp{"SII", "maximum extent", $grasp_ref}; if(rand() < $SII_F5_PROB) { # print "Connecting SII.$elem -> F5.$i\n"; # $parms{"d"} |= 0x8; &add_connection("SII", $elem, $SII_F5_GAIN * (1 - $SII_F5_MOD*rand()), "sensory connector", "F5", $i); # $parms{"d"} &= ~0x8; }; } elsif($phase eq "hold") { # Hold units are activated # by contact extent units. # Maximum extent $elem = $grasp{"SII", "contact", $grasp_ref}; if(rand() < $SII_F5_PROB) { # print "Connecting SII.$elem -> F5.$i\n"; &add_connection("SII", $elem, $SII_F5_GAIN * (1 - $SII_F5_MOD*rand()), "sensory connector", "F5", $i); }; # Contact # Added this to stabilize the hold phase # of movement. $elem = $grasp{"SII", "contact", $grasp_ref}; if($hold_prime_contact_flag && rand() < $F5_SII_PROB) { print "SPECIAL Connecting F5.$i -> SII.$elem\n"; &add_connection("F5", $i, $F5_SII_GAIN * (1 - $F5_SII_MOD*rand()), "priming connector", "SII", $elem); }; } elsif($phase eq "release") { # Release units prime SII # release units and are inhibited by them also. # F5 primes SII unit $elem = $grasp{"SII", "release", $grasp_ref}; if(rand() < $F5_SII_PROB) { # print "Connecting F5.$i -> SII.$elem\n"; &add_connection("F5", $i, $F5_SII_GAIN * (1 - $F5_SII_MOD*rand()), "priming connector", "SII", $elem); }; # SII unit inhibits F5 unit $elem = $grasp{"SII", "release", $grasp_ref}; # print "Connecting SII.$elem -> F5.$i\n"; # $parms{"d"} |= 0x8; &add_connection("SII", $elem, $SII_F5_INVERSE_GAIN * (1 - $SII_F5_MOD*rand()), "sensory connector", "F5", $i); # $parms{"d"} &= ~0x8; } }; }; }; # # sub add_position_sii_connection_set # # Connect the appropriate SI joint units to the specified SII unit ($i) # so that this SII units recognizes the configuration defined by # $grasp_ref and $type. # The first SI units represent the joint positions using a distributed # coding. The first $gauss_position_size of these are for the first # joint, etc. # We connect the SII unit to the two SI units that will be most active # when the joint is in that configuration. # sub add_position_sii_connection_set { local($i, $grasp_ref, $type, $gain) = @_; local($j, $pos); local($index, $match); # Loop through all the joints. foreach $j (@JOINTS) { # Get the position for this joint $pos = $grasp{$type, $grasp_ref, $j}; ($index, $match) = &compute_max_gauss($pos, $gauss_position_min, $gauss_position_max, $gauss_position_std, $gauss_position_size, $gauss_position_pad); # Make the connections &add_connection("SI", $gauss_position_size * $joints{"index", $j} + $index, $match * $gain/2, "sensory connector", "SII", $i); &add_connection("SI", $gauss_position_size * $joints{"index", $j} + $index+1, (1-$match) * $gain/2, "sensory connector", "SII", $i); }; }; # # sub add_pad_sii_connection_set # # Connect SI tactile units to the specified SII unit ($i). # Tactile units follow the joint position units in the SI array. # # sub add_pad_sii_connection_set { local($i, $grasp_ref, $gain, $offset) = @_; local($pad, $pos); local($index); local($count) = 0; # Loop through all the pads foreach $pad (@PADS) { # Expecting tactile input for this grasp? if($grasp{"tactile mask", $grasp_ref, $pad}) { # Yes - which SI unit? $index = ($#JOINTS+1)*$gauss_position_size + $count + $offset; # Add the connection &add_connection("SI", $index, $gain/2, "sensory connector", "SII", $i); }; ++$count; }; }; # # sub connect_si_sii # # Make all connections from SI to SII. # SII maximum extent cells receive inputs from just SI joint units # SII contact cells receive inputs from joint and pad units # SII release cells receive inputs from the pad units only # sub connect_si_sii { local($i); local($gr, $pads); local($aperture); print "Making SI->SII connections...\n"; # Loop through each SII unit for($i = 0; $i < $sii{"num"}; ++$i) { # print "SII.$i\n"; # Compute the grasp ID $grasp_ref = $sii{"grasp", $i}; # Number of pads that we expect to # make contact $pads = &count_pads($grasp_ref); # print "GP = $grasp_ref $pads\n"; # Maximum extent cells if($sii{"type", $i} eq "maximum extent") { # print "Adding max\n"; &add_position_sii_connection_set($i, $grasp_ref, "preshape pos", $SI_SII_GAIN/($#JOINTS+1)); } # Contact cells elsif($sii{"type", $i} eq "contact") { # print "Adding contact\n"; &add_position_sii_connection_set($i, $grasp_ref, "final pos", $SI_SII_GAIN/($#JOINTS+1+$pads)); &add_pad_sii_connection_set($i, $grasp_ref, $SI_SII_PAD_ADD_GAIN * $SI_SII_GAIN/($#JOINTS+1+$pads), 0); } # Release cells elsif($sii{"type", $i} eq "release") { # print "Adding release\n"; # Connect to inverse-force cells # $parms{"d"} |= 0x8; &add_pad_sii_connection_set($i, $grasp_ref, $SI_SII_PAD_RELEASE_GAIN * $SI_SII_GAIN/($pads), $#PADS+1); &add_pad_sii_connection_set($i, $grasp_ref, -$SI_SII_PAD_RELEASE_GAIN * $SI_SII_GAIN/($pads), 0); # $parms{"d"} &= ~0x8; }; }; }; # # sub connect_th_si # # Connect the thalamic structures to SI. The first elements are # the joints, the second are the pad forces (and inverse forces). # sub connect_th_si { local($i); print "Making TH->SI connections...\n"; # Position cells for($i = 0; $i < ($#JOINTS+1)*$gauss_position_size; ++$i) { &add_connection("TH_FINGER_POS", $i, 1, "sensory connector", "SI", $i); }; for($i = 0; $i < ($#PADS+1)*2; ++$i) { &add_connection("TH_PAD_FORCES", $i, 1, "sensory connector", "SI", $i + ($#JOINTS+1)*$gauss_position_size); }; }; # # sub compute_sii # # Compute attributes and connectivity for SII units. # # sub compute_sii { &init_sii(); &connect_f5_sii(); &connect_si_sii(); }; # # sub compute_si # # Set up layer SI # sub compute_si { local($i); # Set threshold for($i = 0; $i < ($#JOINTS+1)*$gauss_position_size + ($#PADS+1)*2; ++$i) { $net{"support threshold", "SI", $i} = 0; }; # Initialize layer structure $net{"num", "SI"} = ($#JOINTS+1)*$gauss_position_size + ($#PADS+1)*2; # Connections from TH &connect_th_si(); }; # # sub connect_f5_measures # # Measures for 'snooping' on the networks. # # All F5 cells connect to the grasp that corresponds to their # primary grasp. # All F5 cells that code for an aperture project to the aperture # measure. # sub connect_f5_measures { local($i); local($pg); print "Making F5->measure connections\n"; # Loop over each F5 unit. for($i = 0; $i < $f5{"num"}; ++$i) { # Connect to one of the grasp connectors. # (to the one corrsponding to the primary # grasp). $pg = $f5{"primary grasp", $i}; &add_to_connector("F5", $i, 1, $f5{"grasp", $i, $pg}); # If this cell represents an aperture, then # connect to the aperture connector. if($f5{"grasp aperture", $i, $pg} != -1) { &add_to_connector("F5", $i, $f5{"grasp aperture", $i, $pg}, "GRASP_APERTURE"); }; }; }; # # sub connect_f2() # # For each F2 unit: # - Add a connection from the corresponding ABSTRACT input # - Add a connection to the BG_GRASP unit that will activate the # corresponding program. # - Add a priming connection from F6 # sub connect_f2 { local($i); # Initialize the F2 layer $net{"num", "F2"} = $#GRASP_TYPES + 1; # Loop through each grasp type for($i = 0; $i <= $#GRASP_TYPES; ++$i) { # IS -> F2 &add_connection("ABSTRACT", $i, $ABSTRACT_F2_GAIN, "sensory connector", "F2", $i); # F2 -> BG &add_connection("F2", $i, $F2_BG_GAIN, "sensory connector", "BG_GRASP", $i); # F6 -> F2 &add_connection("SMA", 0, 1, "priming connector", "F2", $i); # Set the threshold $net{"support threshold", "F2", $i} = 0; }; }; # # sub connect_f6() # # For each F6 unit: # - Add a connection to the BG_GRASP unit that will activate the # corresponding program. # sub connect_f6 { local($i); # Loop through each grasp type for($i = 0; $i <= $#GRASP_TYPES; ++$i) { # F6 -> BG &add_connection("F6", $i, $F6_BG_GAIN, "sensory connector", "BG_GRASP", $i); }; }; # # sub connect_46_f5 # # Connect one A46 cell to each of the F5 support inptus. # # sub connect_46_f5 { local($i); print "Making A46->F5 connections...\n"; for($i = 0; $i < $f5{"num"}; ++$i) { &add_connection("A46", $i, 1, "support connector", "F5", $i); }; }; # # sub establish_connections # # Connect the network # sub establish_connections { local($base) = @_; print "######################################################\n"; print "Connecting Network...\n"; &connect_aip_aip(); &connect_f5_f5(); &connect_mcx(); &connect_pip_aip(); &connect_sma(); &connect_aip_f5(); &connect_trigger_context_f5(); &connect_trigger_go_f5(); &connect_trigger2_go_f5(); &connect_f5_aip(); &connect_f5_f5_int_support(); &connect_f5_bg(); &connect_mcx_spinal(); &connect_SI_mcx(); &connect_f2(); &connect_f6(); &connect_46_f5(); &connect_f5_measures(); &compute_sii(); &compute_si(); }; 1;