Example #1
0
    def halt(population, generation_count):
        """
        Given a population of candidate solutions and generation count (the
        number of epochs the algorithm has run) will return a boolean to
        indicate if an acceptable solution has been found within the
        referenced population.
        """
        fittest = population[0]
        max_fitness = MAX_REWARD
        for i in range(len(fittest.chromosome)):
            # Check for dissonances. Each dissonance should have incremented
            # the fitness because it has been "placed" correctly.
            cantus_firmus_note = cantus_firmus[i / 4]
            melody_note = fittest.chromosome[i]
            interval = melody_note - cantus_firmus_note
            if interval in DISSONANCES:
                max_fitness += REWARD_STEPWISE_MOTION
            else:
                if i > 0 and i < (len(fittest.chromosome) - 2):
                    if is_stepwise_motion(fittest.chromosome, i):
                        max_fitness += REWARD_STEPWISE_MOTION

        return (fittest.fitness >= max_fitness or
            generation_count > DEFAULT_MAX_GENERATION)
Example #2
0
    def halt(population, generation_count):
        """
        Given a population of candidate solutions and generation count (the
        number of epochs the algorithm has run) will return a boolean to
        indicate if an acceptable solution has been found within the
        referenced population.
        """
        fittest = population[0]
        max_fitness = MAX_REWARD
        for i in range(len(fittest.chromosome)):
            # Check for dissonances. Each dissonance should have incremented
            # the fitness because it has been "placed" correctly.
            cantus_firmus_note = cantus_firmus[i / 4]
            melody_note = fittest.chromosome[i]
            interval = melody_note - cantus_firmus_note
            if interval in DISSONANCES:
                max_fitness += REWARD_STEPWISE_MOTION
            else:
                if i > 0 and i < (len(fittest.chromosome) - 2):
                    if is_stepwise_motion(fittest.chromosome, i):
                        max_fitness += REWARD_STEPWISE_MOTION

        return (fittest.fitness >= max_fitness
                or generation_count > DEFAULT_MAX_GENERATION)
Example #3
0
    def fitness_function(genome):
        """
        Given a candidate solution will return its fitness score assuming
        the cantus_firmus in this closure. Caches the fitness score in the
        genome.
        """
        # Save some time!
        if genome.fitness is not None:
            return genome.fitness

        # The fitness score to be returned.
        fitness_score = 0.0
        # Counts the number of repeated notes.
        repeats = 0
        # Counts the amount of parallel motion.
        parallel_motion = 0
        # Counts the number of jumps in the melodic contour.
        jump_contour = 0

        contrapunctus = genome.chromosome

        # Make sure the solution starts correctly (at a 5th or octave).
        first_interval = contrapunctus[0] - cantus_firmus[0]
        if first_interval == 7 or first_interval == 4:
            fitness_score += REWARD_FIRST
        else:
            fitness_score -= PUNISH_FIRST

        # Make sure the solution finishes correctly (at an octave).
        if contrapunctus[-1] - cantus_firmus[-1] == 7:
            fitness_score += REWARD_LAST
        else:
            fitness_score -= PUNISH_LAST

        # Ensure the penultimate note is step wise onto the final note.
        if abs(contrapunctus[-1] - contrapunctus[-2]) == 1:
            fitness_score += REWARD_LAST_STEP
        else:
            fitness_score -= PUNISH_LAST_STEP

        # Reward contrary motion onto the final note.
        cantus_firmus_motion = cantus_firmus[-1] - cantus_firmus[-2]
        contrapunctus_motion = contrapunctus[-1] - contrapunctus[-2]

        if ((cantus_firmus_motion < 0 and contrapunctus_motion > 0) or
            (cantus_firmus_motion > 0 and contrapunctus_motion < 0)):
            fitness_score += REWARD_LAST_MOTION
        else:
            fitness_score -= PUNISH_LAST_MOTION

        # Make sure the penultimate note isn't a repeated note.
        penultimate_preparation = abs(contrapunctus[-2] - contrapunctus[-3])
        if penultimate_preparation == 0:
            fitness_score -= PUNISH_REPEATED_PENULTIMATE
        else:
            # Make sure the movement to the penultimate note isn't from too
            # far away (not greater than a third).
            if penultimate_preparation < 2:
                fitness_score += REWARD_PENULTIMATE_PREPARATION
            else:
                fitness_score -= PUNISH_PENULTIMATE_PREPARATION

        # Check the fitness of the body of the solution.
        last_notes = (contrapunctus[0], cantus_firmus[0])
        last_interval = last_notes[0] - last_notes[1]
        for i in range(1, len(contrapunctus) - 1):
            contrapunctus_note = contrapunctus[i]
            cantus_firmus_note = cantus_firmus[i / 4]
            current_notes = (contrapunctus_note, cantus_firmus_note)
            current_interval = contrapunctus_note - cantus_firmus_note

            # Punish parallel fifths or octaves.
            if ((current_interval == 4 or current_interval == 7) and
                (last_interval == 4 or last_interval == 7)):
                fitness_score -= PUNISH_PARALLEL_FIFTHS_OCTAVES

            # Check for parallel motion.
            if is_parallel(last_notes, current_notes):
                parallel_motion += 1

            # Check if the melody is a repeating note.
            if contrapunctus_note == last_notes[0]:
                repeats += 1

            # Check the melodic contour.
            contour_leap = abs(current_notes[0] - last_notes[0])
            if contour_leap >= 2:
                jump_contour += contour_leap - 2

            # Ensure dissonances are part of a step-wise movement.
            if i % 2 and current_interval in DISSONANCES:
                # The current_note is a dissonance on the third beat of a bar.
                # Check that both the adjacent notes are only a step away.
                if is_stepwise_motion(contrapunctus, i):
                    fitness_score += REWARD_STEPWISE_MOTION
                else:
                    fitness_score -= PUNISH_STEPWISE_MOTION
            else:
                if is_stepwise_motion(contrapunctus, i):
                    fitness_score += REWARD_STEPWISE_MOTION

            last_notes = current_notes
            last_interval = current_interval

        # Punish too many (> 1/3) repeated notes.
        if repeats > repeat_threshold:
            fitness_score -= PUNISH_REPEATS

        # Punish too many (> 1/3) parallel movements.
        if parallel_motion > repeat_threshold:
            fitness_score -= PUNISH_PARALLEL

        # Punish too many large leaps in the melody.
        if jump_contour > jump_threshold:
            fitness_score -= PUNISH_LEAPS

        genome.fitness = fitness_score

        return fitness_score
Example #4
0
    def fitness_function(genome):
        """
        Given a candidate solution will return its fitness score assuming
        the cantus_firmus in this closure. Caches the fitness score in the
        genome.
        """
        # Save some time!
        if genome.fitness is not None:
            return genome.fitness

        # The fitness score to be returned.
        fitness_score = 0.0
        # Counts the number of repeated notes.
        repeats = 0
        # Counts the amount of parallel motion.
        parallel_motion = 0
        # Counts the number of jumps in the melodic contour.
        jump_contour = 0

        contrapunctus = genome.chromosome

        # Make sure the solution starts correctly (at a 5th or octave).
        first_interval = contrapunctus[0] - cantus_firmus[0]
        if first_interval == 7 or first_interval == 4:
            fitness_score += REWARD_FIRST
        else:
            fitness_score -= PUNISH_FIRST

        # Make sure the solution finishes correctly (at an octave).
        if contrapunctus[-1] - cantus_firmus[-1] == 7:
            fitness_score += REWARD_LAST
        else:
            fitness_score -= PUNISH_LAST

        # Ensure the penultimate note is step wise onto the final note.
        if abs(contrapunctus[-1] - contrapunctus[-2]) == 1:
            fitness_score += REWARD_LAST_STEP
        else:
            fitness_score -= PUNISH_LAST_STEP

        # Reward contrary motion onto the final note.
        cantus_firmus_motion = cantus_firmus[-1] - cantus_firmus[-2]
        contrapunctus_motion = contrapunctus[-1] - contrapunctus[-2]

        if ((cantus_firmus_motion < 0 and contrapunctus_motion > 0)
                or (cantus_firmus_motion > 0 and contrapunctus_motion < 0)):
            fitness_score += REWARD_LAST_MOTION
        else:
            fitness_score -= PUNISH_LAST_MOTION

        # Make sure the penultimate note isn't a repeated note.
        penultimate_preparation = abs(contrapunctus[-2] - contrapunctus[-3])
        if penultimate_preparation == 0:
            fitness_score -= PUNISH_REPEATED_PENULTIMATE
        else:
            # Make sure the movement to the penultimate note isn't from too
            # far away (not greater than a third).
            if penultimate_preparation < 2:
                fitness_score += REWARD_PENULTIMATE_PREPARATION
            else:
                fitness_score -= PUNISH_PENULTIMATE_PREPARATION

        # Check the fitness of the body of the solution.
        last_notes = (contrapunctus[0], cantus_firmus[0])
        last_interval = last_notes[0] - last_notes[1]
        for i in range(1, len(contrapunctus) - 1):
            contrapunctus_note = contrapunctus[i]
            cantus_firmus_note = cantus_firmus[i / 4]
            current_notes = (contrapunctus_note, cantus_firmus_note)
            current_interval = contrapunctus_note - cantus_firmus_note

            # Punish parallel fifths or octaves.
            if ((current_interval == 4 or current_interval == 7)
                    and (last_interval == 4 or last_interval == 7)):
                fitness_score -= PUNISH_PARALLEL_FIFTHS_OCTAVES

            # Check for parallel motion.
            if is_parallel(last_notes, current_notes):
                parallel_motion += 1

            # Check if the melody is a repeating note.
            if contrapunctus_note == last_notes[0]:
                repeats += 1

            # Check the melodic contour.
            contour_leap = abs(current_notes[0] - last_notes[0])
            if contour_leap >= 2:
                jump_contour += contour_leap - 2

            # Ensure dissonances are part of a step-wise movement.
            if i % 2 and current_interval in DISSONANCES:
                # The current_note is a dissonance on the third beat of a bar.
                # Check that both the adjacent notes are only a step away.
                if is_stepwise_motion(contrapunctus, i):
                    fitness_score += REWARD_STEPWISE_MOTION
                else:
                    fitness_score -= PUNISH_STEPWISE_MOTION
            else:
                if is_stepwise_motion(contrapunctus, i):
                    fitness_score += REWARD_STEPWISE_MOTION

            last_notes = current_notes
            last_interval = current_interval

        # Punish too many (> 1/3) repeated notes.
        if repeats > repeat_threshold:
            fitness_score -= PUNISH_REPEATS

        # Punish too many (> 1/3) parallel movements.
        if parallel_motion > repeat_threshold:
            fitness_score -= PUNISH_PARALLEL

        # Punish too many large leaps in the melody.
        if jump_contour > jump_threshold:
            fitness_score -= PUNISH_LEAPS

        genome.fitness = fitness_score

        return fitness_score