def n_point_crossover(random, mom, dad, args):
    """Return the offspring of n-point crossover on the candidates.

    This function performs n-point crossover (NPX). It selects *n* 
    random points without replacement at which to 'cut' the candidate 
    solutions and recombine them.

    .. Arguments:
       random -- the random number generator object
       mom -- the first parent candidate
       dad -- the second parent candidate
       args -- a dictionary of keyword arguments

    Optional keyword arguments in args:
    
    - *crossover_rate* -- the rate at which crossover is performed 
      (default 1.0)
    - *num_crossover_points* -- the number of crossover points used (default 1)
    
    """
    crossover_rate = args.setdefault('crossover_rate', 1.0)
    num_crossover_points = args.setdefault('num_crossover_points', 1)
    children = []
    if random.random() < crossover_rate:
        num_cuts = min(len(mom)-1, num_crossover_points)
        cut_points = random.sample(range(1, len(mom)), num_cuts)
        cut_points.sort()
        bro = copy.copy(dad)
        sis = copy.copy(mom)
        normal = True
        for i, (m, d) in enumerate(zip(mom, dad)):
            if i in cut_points:
                normal = not normal
            if not normal:
                bro[i] = m
                sis[i] = d
                normal = not normal
        children.append(bro)
        children.append(sis)
    else:
        children.append(mom)
        children.append(dad)
    return children
Return the offspring of n-point crossover on the candidates.

    This function performs n-point crossover (NPX). It selects *n* 
    random points without replacement at which to 'cut' the candidate 
    solutions and recombine them.

    .. Arguments:
       random -- the random number generator object
       mom -- the first parent candidate
       dad -- the second parent candidate
       args -- a dictionary of keyword arguments

    Optional keyword arguments in args:
    
    - *crossover_rate* -- the rate at which crossover is performed 
      (default 1.0)
    - *num_crossover_points* -- the number of crossover points used (default 1)