text: 
  import numpy as np
  import random
  
  import logging
  logger = logging.getLogger(__name__)
  
  from .param import GeneticParam
  
  class MergedParams(object):
  	'''
  		Overlay static parameter dictionary with a dictionary of 'dynamic' genetic parameters
  
  		This lets the parameters being optimized override those in the static base
  	'''
  
  	def __init__(self, fixed, dynamic):
  		self.fixed = fixed
  		self.dynamic = dynamic
  
  	def __getitem__(self, key):
  		if key in self.dynamic:
  			return self.dynamic[key].value
  
  		if key in self.fixed:
  			return self.fixed[key]
  
  		avail = list(self.fixed.keys()) + list(self.dynamic.keys())
  		raise KeyError("{} not found, available keys: {}".format(key, avail))
  
  	def get(self, key, default=None):
  		try:
  			return self.__getitem__(key)
  
  		except Exception as ex:
  			if default is not None:
  				return default
  			else:
  				raise ex
  
  	def __setitem__(self, key, value):
  		if instanceof(value, GeneticParam):
  			self.dynamic[key] = value
  		else:
  			self.fixed[key] = value
  
  	@property
  	def __dict__(self):
  		r = {}
  
  		for key, value in self.fixed.items():
  			r[key] = value
  
  		for key, value in self.dynamic.items():
  			r[key] = value.value
  
  		return r
  
  
  class ParamSet(dict):
  	def mutate(self, heat):
  		return type(self)({
  			k: v.mutate(heat) for k, v in self.items()
  		})
  
  	def dist(self, other):
  		np.linalg.norm([
  			v.dist(other[k]) for k, v in self.items()
  		])
  
  	def breed(self, other, heat):
  		def cross(a,b):
  			choice = a if random.random() >= 0.5 else b
  			return choice.mutate(heat)
  
  		return type(self)({
  			k: cross(v, other[k]) for k, v in self.items()
  		})
  
  class ParamSpec(dict):
  	def realize(self):
  		return ParamSet({
  			k: v() for k, v in self.items()
  		})
  