
###############################################################
#                                                             #
#   Copyright (c) 1989 Nicol N. Schraudolph                   #
#   Computer Science & Engineering, C-014                     #
#   University of California, San Diego                       #
#   La Jolla, CA 92093-0114                                   #
#                                                             #
#   Permission is hereby granted to copy all or any part of   #
#   this program for free distribution.   The author's name   #
#   and this copyright notice must be included in any copy.   #
#                                                             #
###############################################################

#
#  file:    wrapper
#
#  author:  Nicol N. Schraudolph
#
#  created: August 1989
#
#  purpose: awk script for processing GENESIS eval functions
#

BEGIN \
{
printf "\n/* evaluation file for GENESIS 1.4ucsd GA simulator */\n";
printf "/* produced by \"wrapper\" awk(1) script from \"%s\" */\n", FILENAME;
printf "\nextern int   GArgc;   /* number of application-specific arguments */";
printf "\nextern char *GArgv[]; /* vector of application-specific arguments */";
printf "\nextern double Ctoi(); /* double returned to facilitate 'A' option */";
printf "\n\n";
}

# reproduce input file on output:
#
{print $0}

# is an _eval() function already present?
#
/^[ \t]*_eval[ \t]*\(/ {found = 1}
/^[ \t]*double[ \t][ \t]*_eval[ \t]*\(/ {found = 1}

# are gene descriptor variables already supplied?
#
/GAgenes/ {DPE = 1}

# now look for GAeval entries:
#
/^[ \t]*\/\*[ \t][ \t]*GAeval[ \t]/ \
{
	if (len > 0 || $3 == "_eval" || NF < 5)
	{
		print "/* ^^illegal GAeval entry: ignored */";
		#continue;
	}
	found = 1;      # we have a promising GAeval line to look at
	num_real = 0;
	for (i = 4; $i != "*/"; i++)    # for each descriptor field:
	{
		# read first number: field width in bits
		#
		for (j = 1; (c = substr($i, j, 1)) ~ /[0-9]/; j++)
			width[i-3] = 10*width[i-3] + c;
		if (!width[i-3])
		{
			printf "/* ^^can't find width of field \"%s\" */\n", $i;
			exit 3;
		}

		# look for field type description
		#
		if ($i ~ /[cC]/) type[i-3] = "char";
		else if ($i ~ /[sS]/) type[i-3] = "short";
		else if ($i ~ /[iI]/) type[i-3] = "int";
		else if ($i ~ /[lL]/) type[i-3] = "long";
		else if ($i ~ /[fF]/) type[i-3] = "float";
		else if ($i ~ /[dD]/) type[i-3] = "double";
		else
		{
			printf "/* ^^can't find type of field \"%s\" */\n", $i;
			exit 2;
		}
		if ($i ~ /[uU]/ && $i !~ /[fdFD]/)
			type[i-3] = "unsigned " type[i-3];

		# read up to first colon: is there a range field?
		#
		for (j = 1; j < length($i); j++)
			if (substr($i, j, 1) == ":") break;

		if (j < length($i))     # yes: read a float into hi[]
		{
			hi[i-3] = dot = 0;
			if ((c = substr($i, ++j, 1)) == "-")
			{
				div = -1.0;     # float is negative
				j++;
			}
			else div = 1.0;
			if (c == "+") j++;  # ignore leading '+'

			for (; (c = substr($i, j, 1)) ~ /[\.0-9]/; j++)
			{
				if (c == ".")   # found the decimal point
				{
					if (dot)
					{
						printf "/* ^^too many '.' in field \"%s\" */\n", $i;
						exit 4;
					}
					else dot = 1;
				}
				else            # read one digit
				{
					hi[i-3] = 10*hi[i-3] + c;
					if (dot) div *= 10.0;
				}
			}
			hi[i-3] /= div;     # adjust for decimal point

			# same for second range field, if there is any:
			#
			if (substr($i, j, 1) == ":")
			{
				lo[i-3] = hi[i-3];
				hi[i-3] = dot = 0;
				if ((c = substr($i, ++j, 1)) == "-")
				{
					div = -1.0;     # float is negative
					j++;
				}
				else div = 1.0;
				if (c == "+") j++;  # ignore leading '+'

				for (; (c = substr($i, j, 1)) ~ /[\.0-9]/; j++)
				{
					if (c == ".")   # found the decimal point
					{
						if (dot)
						{
							printf "/* ^^too many '.' in field \"%s\" */\n", $i;
							exit 4;
						}
						else dot = 1;
					}
					else            # read one digit
					{
						hi[i-3] = 10*hi[i-3] + c;
						if (dot) div *= 10.0;
					}
				}
				hi[i-3] /= div;     # adjust for decimal point
			}
			else if ($i !~ /[uU]/) lo[i-3] = -hi[i-3];
			#
			# no second range field: make range symmetric if signed
		}

		# now read replicator, if any:
		#
		k = 1;
		for (j = length($i); (c = substr($i, j, 1)) ~ /[0-9]/; j--)
		{
			num[i-3] += k*c;
			k *= 10;
		}
		if (num[i-3]) any_num = 1;

		# look for 'b' and 'g' switches:
		#
		dpe[i-3] = 0;
		if ($i ~ /[bB]/) gray[i-3] = 0;
		else
		{
			gray[i-3] = 1;
			if (width[i-3] > maxw) maxw = width[i-3];
			if ($i !~ /[gG]/ && width[i-3] >= 2) dpe[i-3] = 1;
		}

		# convert range boundaries into (base,scale) notation:
		#
		excess = 1;
		for (j = 1; j < width[i-3]; j++) excess *= 2;
		if (hi[i-3] == 0 && lo[i-3] == 0)
		{
			hi[i-3] = 1;
			if ($i !~ /[uU]/) lo[i-3] = -excess;
		}
		else hi[i-3] = (hi[i-3] - lo[i-3])/(2*excess);

		# construct gene descriptor variables:
		#
		for (j = 0; j < num[i-3] || j == 0; j++)
		{
			len += width[i-3];
			start[num_real] = len;
			if (!dpe[i-3]) start[num_real] = -start[num_real];
			scale[num_real] = hi[i-3];
			base[num_real++] = lo[i-3];
		}
	}

	# now let's do some outputting:
	#
	if (!DPE)   # print gene descriptor variables, nicely formatted
	{
		printf "\nint GAgenes = %d;  /* the number of genes */\n", num_real;
		print "\n/* locates the end of each gene; negate to inhibit DPE */";
		printf "int GAposn[%d] = {", num_real;
		for (i = 1; i < num_real; i++)
		{
			printf "%3d, ", start[i-1];
			if (!(i % 10)) printf "\n                  ";
		}
		printf "%3d};\n", start[num_real-1];
		print "\n/* multiplication factors (see _eval() below) */";
		printf "double GAfact[%d] = {", num_real;
		for (i = 1; i < num_real; i++)
		{
			printf "%.5e, ", scale[i-1];
			if (!(i % 4)) printf "\n                     ";
		}
		printf "%.5e};\n", scale[num_real-1];
		print "\n/* displacement terms (see _eval() below) */";
		printf "double GAbase[%d] = {", num_real;
		for (i = 1; i < num_real; i++)
		{
			printf "%.5e, ", base[i-1];
			if (!(i % 4)) printf "\n                     ";
		}
		printf "%.5e};\n", base[num_real-1];
		DPE = 1;
	}
	else print "\n/* using user-supplied GA globals in good faith */";

	# print the appropriate _eval() function:
	#
	print "\n/* user's evaluation function needs unpacking and decoding */";
	print "double _eval(genome, length)";
	print "\tchar *genome;";
	print "\tint length;\n{";
	for (i = 1; type[i] != ""; i++)
	{
		printf "\tstatic %s p%d", type[i], i;   # variables to hold the genes
		if (num[i] && width[i]) printf "[%d]", num[i];
		print ";";
	}
	if (maxw) printf "\tchar tmp[%d];\n", maxw; # a char buffer for Degray()
	if (any_num) print "\tregister int i;";     # loop counter for replication
	print "\textern   char *Buff;";             # global buffer for Unpack()
	print "\tregister char *buff;";             # a pointer to the above
	print "\tregister double *f = GAfact;";
	print "\tregister double *b = GAbase;";     # pointers for fast scaling

	# report last phenotype if length is negative:
	#
	print "\n\tif (length < 0)\t/* report previous phenotype */\n\t{";
	printf "\t\tsprintf(genome, \"\\n";
	for (i = 1; type[i] != ""; i++)     # construct the formatting string
		for (j = 0; j == 0 || j < num[i]; j++)
		{
			printf "%%%d", width[i];
			if (type[i] ~ /long/) printf "l";
			if (type[i] ~ /float/ || type[i] ~ /double/) printf "g ";
			else if (type[i] ~ /unsigned/) printf "u ";
			else printf "d ";
		}
	printf "\"";
	j = i;
	for (i = 1; type[i] != ""; i++)     # print gene vars in nice format
	{
		if (num[i])
			for (j = 0; j < num[i]; j++)
			{
				if (j%6 == 0) printf ",\n\t\t\t";
				else printf ", ";
				printf "p%d[%d]", i, j;
			}
		else
		{
			if (j >= 6)
			{
				printf ",\n\t\t\t";
				j = -4;
			}
			else printf ", ";
			printf "p%d", i;
			j++;
		}
	}
	print ");\n\t\treturn((double) 0.0);\n\t}";

	# back to the decoding business:
	#
	printf "\t/*  GAlength %d  */\n", len;
	printf "\tif (length < %d)\n", len;
	printf "\t\tError(%clength error in eval%c);\n", 34, 34;
	print "\n\tUnpack(genome, buff = Buff);";

	for (i = 1; type[i] != ""; i++)     # for each descriptor:
	{
		if (num[i])     # start a loop for replication
		{
			printf "\tfor (i = 0; i < %d; ", num[i];
			printf "i++, buff += %d)\n\t", width[i];
			if (gray[i]) printf "{\n\t";
		}
		if (gray[i])    # call Degray() if necessary
		{
			printf "\tDegray";
			printf "(buff, tmp, %d);\n", width[i];
			if (num[i]) printf "\t";
		}
		printf "\tp%d", i;      # now decode the gene
		if (num[i]) printf "[i]";
		printf " = (%s) (Ctoi(", type[i];
		if (gray[i]) printf "tmp";
		else printf "buff";
		printf ", %d) * *f++ + *b++);\n", width[i];
		if (gray[i] && num[i]) print "\t}"
		if (!num[i] && type[i+1] != "")
			printf "\tbuff += %d;\n", width[i];
	}

	# invoke user's eval function with decoded genes:
	#
	printf "\treturn((double) %s(", $3;
	for (i = 1; type[i] != ""; i++)
	{
		if (!comma) comma = 1;
		else printf ", ";
		printf "p%d", i;
	}
	print "));\n}";
}

END \
{
	if (!found)     # must be old-fashioned eval() function:
	{
		print "\n/* user's eval() function needs unpacking only */";
		print "double _eval(genome, length)\n\tchar *genome;";
		print "\tint length;\n{\n\textern char *Buff;\n";
		print "\tif (length > 0)\n\t{"; 
		print "\t\tUnpack(genome, Buff, length);";
		print "\t\tgenome = Buff;\n\t}"; 
		print "\treturn(eval(genome, length));\n}";
	}
	if (!DPE)       # no data for parameter descriptor variables:
	{
		print "\n/* inserting dummy GA globals - DPE won't work */";
		print "int GAgenes = 0, *GAposn;";
		print "double  *GAfact, *GAbase;";
	}
}

