#NEWLINE# @ crossover #NEWLINE# def n_point_crossover( random , mom , dad , args ) : #NEWLINE# #INDENT# "Return the offspring of n-point crossover on the candidates.\n\n    This function performs n-point crossover (NPX). It selects *n* \n    random points without replacement at which to 'cut' the candidate \n    solutions and recombine them.\n\n    .. Arguments:\n       random -- the random number generator object\n       mom -- the first parent candidate\n       dad -- the second parent candidate\n       args -- a dictionary of keyword arguments\n\n    Optional keyword arguments in args:\n    \n    - *crossover_rate* -- the rate at which crossover is performed \n      (default 1.0)\n    - *num_crossover_points* -- the number of crossover points used (default 1)\n    \n    " #NEWLINE# crossover_rate = args . setdefault ( 'crossover_rate' , 1.0 ) #NEWLINE# num_crossover_points = args . setdefault ( 'num_crossover_points' , 1 ) #NEWLINE# children = [ ] #NEWLINE# if ( random . random ( ) < crossover_rate ) : #NEWLINE# #INDENT# num_cuts = min ( ( len ( mom ) - 1 ) , num_crossover_points ) #NEWLINE# cut_points = random . sample ( range ( 1 , len ( mom ) ) , num_cuts ) #NEWLINE# cut_points . sort ( ) #NEWLINE# bro = copy . copy ( dad ) #NEWLINE# sis = copy . copy ( mom ) #NEWLINE# normal = True #NEWLINE# for ( i , ( m , d ) ) in enumerate ( zip ( mom , dad ) ) : #NEWLINE# #INDENT# if ( i in cut_points ) : #NEWLINE# #INDENT# normal = ( not normal ) #NEWLINE# #UNINDENT# if ( not normal ) : #NEWLINE# #INDENT# bro [ i ] = m #NEWLINE# sis [ bro ] = d #NEWLINE# #UNINDENT# #UNINDENT# children . append ( bro ) #NEWLINE# children . append ( sis ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# children . append ( mom ) #NEWLINE# children . append ( dad ) #NEWLINE# #UNINDENT# return children