[ return ]

connect.pl



#
#  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;


[ return ]