# PluginFuncs.py
# Author: Juliette Zerick (jnzerick@math.ucdavis.edu)
# EAD 221 + PHY 250 (Spring 2009)
# Purpose: These are "plugin" functions--functions that get passed in as function
#	handles to Antigen and Antibody objects. This code is what makes the
#	Antibody and Antigen objects problem-specific.

from UtilsNConstants import *
import pylab
import math
import random

# convert a chromosome to a decimal value
def chrom2coord(C):
	L = choplist(C,PRECISION)
	V = map(blist2int,L)
	C = map(scale,V)
	del L,V
	return C

# calculates Antibody-Antigen affinity--handle is stored in each Antibody
def plugin_AbAg_aff(Ab,Ag):
	v1 = chrom2coord(Ab.chromosome)
	v2 = Ag.chromosome

	dist = dist_metric(v1,v2)

	return 1.0/(dist**2)

# calcualtes Antibody-Antibody affinity--handle is stored in each Antibody
# and Antigen
def plugin_Ab_aff(Ab1,Ab2):
	v1 = chrom2coord(Ab1.chromosome)
	v2 = chrom2coord(Ab2.chromosome)
	
	# evaluate the decimal value with the function
	return dist_metric(v1,v2)

# calculates Antigen-Antigen affinity--handle is stored in each Antigen
def plugin_Ag_aff(Ag1,Ag2):
	return dist_metric(Ag1.chromosome,Ag2.chromosome)

# prints an entire Antibody--function handle is stored in the Antibody
# object.
def plugin_printAb(Ab):
	# get coordinates
	C = chrom2coord(Ab.chromosome)

	# and print it
	print "{%d}\t[%d]\t(%s)" % (Ab.gen,Ab.ID,list2str(C,","))

# prints an entire Antigen--function handle is stored in the Antibody
# object.
def plugin_printAg(Ag):
	# print it
	print "(%s)" % (list2str(C,","))

# just a helper function: it turns a list into formatted coordinates
def gen_coord(C):
	return "(%s)" % (list2str(C,","))

# this implements the string typecasting operator--function handle is
# passed in to each Antibody object
def plugin_Ab_tostr(Ab):
	C = chrom2coord(Ab.chromosome)
	return "{%d}\t[%d]\t(%s)" % (Ab.gen,Ab.ID,list2str(C,","))

# this implements the string typecasting operator--function handle is
# passed in to each Antigen object
def plugin_Ag_tostr(Ag):
	return gen_coord(Ag.chromosome)

# this is a generic function that mutates a bit string A with the given
# prob_mut mutation rate
def gen_mutate(A,prob_mut):
	# make a copy of the list before mutating it
	M = copylist(A.chromosome)

	# and flip bits at random
	for i in xrange(len(M)):
		if random.random() < prob_mut:
			M[i] = (M[i]+1)%2

	# delete the old chromosome and assign the new
	del A.chromosome
	A.chromosome = M	

# this function handles mutation of an Antibody--handle is passed in
# to each Antibody objectZ
def plugin_mutate_Ab(Ab,prob_mut):
	gen_mutate(Ab,prob_mut)
	Ab.history.feed_point(chrom2coord(Ab.chromosome))

# this function does nothing, as Antigens are not mutated in this
# implementation (they are "nudged," handled elsewhere)--nonetheless,
# the handle is passed in to each Antibody object.
def plugin_mutate_Ag(Ag,prob_mut):
	return

# this function generates a random color for sending to pylab.plot
def random_color():
	# surprisingly, yes, it WAS easier doing it this way
	H = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']

	str = "#"

	# pick six symbols from H using an N-sided coin/die
	for i in xrange(6):
		str += H[Ncointoss(15)]

	return str

# handles the plotting of a list of points in a random color,
# using a dashed line with a circular starting point and diamond end point;
# the list of points is neatly packaged by the Trajectory class, and then
# passed on to this function, whose handle is stored in every Trajectory object
def plugin_2Dplot_conn(L):
	C = random_color()

	pylab.plot([L[0][0]],[L[1][0]],'.',color=C,antialiased=True)

	if len(L[0])>1:
		pylab.plot(L[0],L[1],'--',color=C,antialiased=True)

	pylab.plot([L[0][-1]],[L[1][-1]],'D',color=C,antialiased=True)

# handles the plotting of a list of points using blue dots (or a random
# color, if the appropraite line is uncommented) ; the list of points
# is neatly packaged by the Trajectory class, and then passed on to
# this function, whose handle is stored in every Trajectory object
def plugin_2Dplot_dots(L):
	# use a random color
	#pylab.plot(L[0],L[1],'.',color=random_color(),antialiased=True)

	# or plot blue dots
	pylab.plot(L[0],L[1],'b.',antialiased=True)
