Beispiel #1
0
    def mutate_gene(self, genome, p_add, p_delete):
        """
        Mutate only a single gene.
        """

        if p_add < 0 or p_delete < 0:
            raise Exception("Mutation parameters must not be negative.")

        if p_add + p_delete > 1:
            raise Exception("Sum of the mutation probabilities must be less than 1.")

        mutated_individual = BehaviorTreeStringRepresentation([])
        max_attempts = 100
        attempts = 0
        while (not mutated_individual.is_valid() or mutated_individual.bt == genome) and attempts < max_attempts:
            mutated_individual.set(genome)
            index = random.randint(0, len(genome) - 1)
            mutation = random.random()

            if mutation < p_delete:
                mutated_individual.delete_node(index)
            elif mutation < p_delete + p_add:
                mutated_individual.add_node(index)
            else:
                mutated_individual.change_node(index)

            mutated_individual.close()
            mutated_individual.trim()
            attempts += 1

        if attempts >= max_attempts and (not mutated_individual.is_valid() or mutated_individual.bt == genome):
            mutated_individual = BehaviorTreeStringRepresentation([])

        return mutated_individual.bt
    def test_swap_subtrees(self):

        btsr_1 = BehaviorTreeStringRepresentation(
            ['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')'])
        btsr_2 = BehaviorTreeStringRepresentation(
            ['s(', 'a0', 'f(', 'a0', 'a0', ')', 's(', 'a0', 'a0', ')', ')'])
        btsr_1.swap_subtrees(btsr_2, 6, 6)

        self.assertEqual(
            btsr_1.bt,
            ['s(', 'a0', 'f(', 'a0', 'a0', ')', 's(', 'a0', 'a0', ')', ')'])
        self.assertEqual(btsr_2.bt,
                         ['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')'])

        # Invalid subtree because it's an up node, no swap
        btsr_1.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')'])
        btsr_2.set(
            ['s(', 'a0', 'f(', 'a0', 'a0', ')', 's(', 'a0', 'a0', ')', ')'])
        btsr_1.swap_subtrees(btsr_2, 5, 6)

        self.assertEqual(btsr_1.bt,
                         ['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')'])
        self.assertEqual(
            btsr_2.bt,
            ['s(', 'a0', 'f(', 'a0', 'a0', ')', 's(', 'a0', 'a0', ')', ')'])
    def test_depth(self):
        """ Tests bt_depth function """

        btsr = BehaviorTreeStringRepresentation([])

        # Normal correct tree
        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')'])
        self.assertEqual(btsr.depth(), 2)

        # Goes to 0 before last node - invalid
        btsr.set(
            ['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')', 's(', 'a0', ')'])
        self.assertEqual(btsr.depth(), -1)

        # Goes to 0 before last node  - invalid
        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', ')', 'a0', ')'])
        self.assertEqual(btsr.depth(), -1)

        # Goes to 0 before last node - invalid
        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0'])
        self.assertEqual(btsr.depth(), -1)

        # Just an action node - no depth
        btsr.set(['a0'])
        self.assertEqual(btsr.depth(), 0)
    def test_trim(self):
        """ Tests trim function """

        btsr = BehaviorTreeStringRepresentation([])

        btsr.set(
            ['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', 's(', 'a0', ')', ')'])
        btsr.trim()
        self.assertEqual(btsr.bt,
                         ['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', 'a0', ')'])

        btsr.set(['s(', 'a0', 'f(', ')', 'a0', 's(', 'a0', ')', ')'])
        btsr.trim()
        self.assertEqual(btsr.bt, ['s(', 'a0', 'a0', 'a0', ')'])

        btsr.set(
            ['s(', 'a0', 'f(', 'a1', 's(', 'a2', ')', 'a3', ')', 'a4', ')'])
        btsr.trim()
        self.assertEqual(btsr.bt,
                         ['s(', 'a0', 'f(', 'a1', 'a2', 'a3', ')', 'a4', ')'])

        btsr.set(['s(', 'a0', 'f(', 's(', 'a2', 'a3', ')', ')', 'a4', ')'])
        btsr.trim()
        self.assertEqual(btsr.bt, ['s(', 'a0', 'a2', 'a3', 'a4', ')'])

        btsr.set(['s(', 'a0', ')'])
        btsr.trim()
        self.assertEqual(btsr.bt, ['s(', 'a0', ')'])
    def test_close(self):
        """ Tests close function """

        btsr = BehaviorTreeStringRepresentation([])

        btsr.close()
        self.assertEqual(btsr.bt, [])

        # Correct tree with just one action
        btsr.set(['a0']).close()
        self.assertEqual(btsr.bt, ['a0'])

        # Correct tree
        btsr.set(['s(', 's(', 'a0', ')', ')']).close()
        self.assertEqual(btsr.bt, ['s(', 's(', 'a0', ')', ')'])

        # Missing up at end
        btsr.set(['s(', 's(', 'a0', ')', 's(', 'a0', 's(', 'a0']).close()
        self.assertEqual(
            btsr.bt,
            ['s(', 's(', 'a0', ')', 's(', 'a0', 's(', 'a0', ')', ')', ')'])

        # Too many up at end
        btsr.set(['s(', 'a0', ')', ')', ')']).close()
        self.assertEqual(btsr.bt, ['s(', 'a0', ')'])

        # Too many up but not at the end
        btsr.set(['s(', 's(', 'a0', ')', ')', ')', 'a1', ')']).close()
        self.assertEqual(btsr.bt, ['s(', 's(', 'a0', ')', 'a1', ')'])
Beispiel #6
0
    def test_mutate_gene(self):

        gp_operators = Operators()
        genome = ['s(', 'c0', ')']

        with self.assertRaises(Exception):
            gp_operators.mutate_gene(genome, p_add=-1, p_delete=1)

        with self.assertRaises(Exception):
            gp_operators.mutate_gene(genome, p_add=1, p_delete=1)

        for _ in range(10):
            mutated_genome = gp_operators.mutate_gene(genome,
                                                      p_add=1,
                                                      p_delete=0)
            self.assertGreaterEqual(len(mutated_genome), len(genome))

            mutated_genome = gp_operators.mutate_gene(genome,
                                                      p_add=0,
                                                      p_delete=1)
            self.assertLessEqual(len(mutated_genome), len(genome))

            mutated_genome = gp_operators.mutate_gene(genome,
                                                      p_add=0,
                                                      p_delete=0)
            btsr = BehaviorTreeStringRepresentation(mutated_genome)
            self.assertNotEqual(mutated_genome, genome)
            self.assertTrue(btsr.is_valid())

            mutated_genome = gp_operators.mutate_gene(genome,
                                                      p_add=0.3,
                                                      p_delete=0.3)
            btsr.set(mutated_genome)
            self.assertNotEqual(mutated_genome, genome)
            self.assertTrue(btsr.is_valid())
Beispiel #7
0
    def test_crossover_genome(self):

        gp_operators = Operators()
        genome1 = ['s(', 'c0', 'f(', 'c0', 'a0', ')', 'a0', ')']
        genome2 = ['f(', 'c1', 's(', 'c1', 'a1', ')', 'a1', ')']
        offspring1, offspring2 = gp_operators.crossover_genome(genome1,
                                                               genome2,
                                                               replace=True)

        self.assertNotEqual(offspring1, [])
        self.assertNotEqual(offspring2, [])
        self.assertNotEqual(offspring1, genome1)
        self.assertNotEqual(offspring1, genome2)
        self.assertNotEqual(offspring2, genome1)
        self.assertNotEqual(offspring2, genome2)

        btsr_1 = BehaviorTreeStringRepresentation(offspring1)
        self.assertTrue(btsr_1.is_valid())
        btsr_1 = btsr_1.set(offspring2)
        self.assertTrue(btsr_1.is_valid())

        genome1 = ['a0']
        genome2 = ['a1']
        offspring1, offspring2 = gp_operators.crossover_genome(genome1,
                                                               genome2,
                                                               replace=True)
        self.assertEqual(offspring1, genome2)
        self.assertEqual(offspring2, genome1)

        genome1 = []
        offspring1, offspring2 = gp_operators.crossover_genome(genome1,
                                                               genome2,
                                                               replace=True)
        self.assertEqual(offspring1, [])
        self.assertEqual(offspring2, [])

        for i in range(10):
            random.seed(i)
            offspring1, offspring2 = gp_operators.crossover_genome(
                gp_operators.random_genome(10),
                gp_operators.random_genome(10),
                replace=True)
            btsr_1 = btsr_1.set(offspring1)
            self.assertTrue(btsr_1.is_valid())
            btsr_1 = btsr_1.set(offspring2)
            self.assertTrue(btsr_1.is_valid())

        genome1 = ['s(', 'f(', 'c0', 'a0', ')', 'a0', ')']
        genome2 = ['f(', 's(', 'c1', 'a1', ')', 'a1', ')']
        offspring1, offspring2 = gp_operators.crossover_genome(genome1,
                                                               genome2,
                                                               replace=False)
        self.assertNotEqual(offspring1, genome1)
        self.assertNotEqual(offspring2, genome2)

        for gene in genome1:
            self.assertTrue(gene in offspring1)
        for gene in genome2:
            self.assertTrue(gene in offspring2)
    def test_find_children(self):
        """ Tests find_children function """

        btsr = BehaviorTreeStringRepresentation([])
        btsr.set(['s(', 'a0', 'f(', 'a0', ')', 'a0', ')'])

        self.assertEqual(btsr.find_children(0), [1, 2, 5])
        self.assertEqual(btsr.find_children(1), [])
        self.assertEqual(btsr.find_children(2), [3])
        self.assertEqual(btsr.find_children(3), [])
        self.assertEqual(btsr.find_children(4), [])
        self.assertEqual(btsr.find_children(5), [])
    def test_find_parent(self):
        """ Tests find_parent function """

        btsr = BehaviorTreeStringRepresentation([])
        btsr.set(['s(', 'a0', 'f(', 'a0', ')', 'a0', ')'])

        self.assertEqual(btsr.find_parent(0), None)
        self.assertEqual(btsr.find_parent(1), 0)
        self.assertEqual(btsr.find_parent(2), 0)
        self.assertEqual(btsr.find_parent(3), 2)
        self.assertEqual(btsr.find_parent(4), 2)
        self.assertEqual(btsr.find_parent(5), 0)
Beispiel #10
0
    def crossover_genome(self, genome1, genome2, replace):
        """
        Do crossover between genomes at random points
        """

        bt1 = BehaviorTreeStringRepresentation(genome1)
        bt2 = BehaviorTreeStringRepresentation(genome2)
        offspring1 = BehaviorTreeStringRepresentation([])
        offspring2 = BehaviorTreeStringRepresentation([])

        if bt1.is_valid() and bt2.is_valid():
            max_attempts = 100
            attempts = 0
            found = False
            while not found and attempts < max_attempts:
                offspring1.set(bt1.bt)
                offspring2.set(bt2.bt)
                cop1 = -1
                cop2 = -1
                if len(genome1) == 1:
                    cop1 = 0  # Change whole tree
                else:
                    while not offspring1.is_subtree(cop1):
                        cop1 = random.randint(1, len(genome1) - 1)
                if len(genome2) == 1:
                    cop2 = 0  # Change whole tree
                else:
                    while not offspring2.is_subtree(cop2):
                        cop2 = random.randint(1, len(genome2) - 1)

                if replace:
                    offspring1.swap_subtrees(offspring2, cop1, cop2)
                else:
                    subtree1 = offspring1.get_subtree(cop1)
                    subtree2 = offspring2.get_subtree(cop2)
                    if len(genome1) == 1:
                        index1 = random.randint(0, 1)
                    else:
                        index1 = random.randint(1, len(genome1) - 1)
                    if len(genome2) == 1:
                        index2 = random.randint(0, 1)
                    else:
                        index2 = random.randint(1, len(genome2) - 1)
                    offspring1.insert_subtree(subtree2, index1)
                    offspring2.insert_subtree(subtree1, index2)

                attempts += 1
                if offspring1.is_valid() and offspring2.is_valid():
                    found = True
            if not found:
                offspring1.set([])
                offspring2.set([])

        return offspring1.bt, offspring2.bt
    def test_get_subtree(self):
        """ Tests get_subtree function """

        btsr = BehaviorTreeStringRepresentation(
            ['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')'])

        subtree = btsr.get_subtree(1)
        self.assertEqual(subtree, ['a0'])

        btsr.set(
            ['s(', 'a0', 'f(', 'a0', 'a0', ')', 's(', 'a0', 'a0', ')', ')'])
        subtree = btsr.get_subtree(6)
        self.assertEqual(subtree, ['s(', 'a0', 'a0', ')'])

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', ')'])
        subtree = btsr.get_subtree(2)
        self.assertEqual(subtree, ['f(', 'a0', 'a0', ')'])

        subtree = btsr.get_subtree(5)
        self.assertEqual(subtree, [])
    def test_length(self):
        """ Tests bt_length function """

        btsr = BehaviorTreeStringRepresentation([])

        btsr.set(['s(', 'a0', 'a1', ')'])
        self.assertEqual(btsr.length(), 3)

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')'])
        self.assertEqual(btsr.length(), 6)

        btsr.set(['s(', ')'])
        self.assertEqual(btsr.length(), 1)

        btsr.set(['a0'])
        self.assertEqual(btsr.length(), 1)
    def test_delete_node(self):
        """ Tests delete_node function """

        btsr = BehaviorTreeStringRepresentation([])

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')']).delete_node(0)
        self.assertEqual(btsr.bt, [])

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 's(', 'a0', ')',
                  ')']).delete_node(0)
        self.assertEqual(btsr.bt, [])

        btsr.set([
            's(', 'a0', 'f(', 'a0', 's(', 'a0', ')', ')', 's(', 'a0', ')', ')'
        ]).delete_node(0)
        self.assertEqual(btsr.bt, [])

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')']).delete_node(1)
        self.assertEqual(btsr.bt, ['s(', 'f(', 'a0', 'a0', ')', 'a0', ')'])

        btsr.set(['s(', 'a0', 'f(', 'a1', 'a2', ')', 'a3', ')']).delete_node(2)
        self.assertEqual(btsr.bt, ['s(', 'a0', 'a3', ')'])

        btsr.set(['s(', 'a0', 'f(', 'a0', ')', 'a0', ')']).delete_node(3)
        self.assertEqual(btsr.bt, ['s(', 'a0', 'f(', ')', 'a0', ')'])

        btsr.set(['s(', 'a0', ')']).delete_node(2)
        self.assertEqual(btsr.bt, ['s(', 'a0', ')'])
    def test_change_node(self):
        """ Tests change_node function """

        btsr = BehaviorTreeStringRepresentation([])
        random.seed(1337)

        # No new node given, change to random node
        btsr.set(['s(', 'a0', 'a0', ')']).change_node(2)
        self.assertNotEqual(btsr.bt[2], 'a0')

        # Change control node to action node
        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0',
                  ')']).change_node(2, 'a0')
        self.assertEqual(btsr.bt, ['s(', 'a0', 'a0', 'a0', ')'])

        # Change control node to action node - correct up must be removed too
        btsr.set(['s(', 'a0', 'f(', 's(', 'a0', ')', 'a0', ')', 'a0',
                  ')']).change_node(2, 'a0')
        self.assertEqual(btsr.bt, ['s(', 'a0', 'a0', 'a0', ')'])

        btsr.set(['s(', 'a0', 'f(', 's(', 'a0', ')', 'a1', ')', 'a0',
                  ')']).change_node(3, 'a0')
        self.assertEqual(btsr.bt,
                         ['s(', 'a0', 'f(', 'a0', 'a1', ')', 'a0', ')'])

        # Change action node to control node
        btsr.set(['s(', 'a0', 'a0', ')']).change_node(1, 'f(')
        self.assertEqual(btsr.bt, ['s(', 'f(', 'a0', 'a0', ')', 'a0', ')'])

        # Change action node to action node
        btsr.set(['s(', 'a0', 'a0', ')']).change_node(1, 'a1')
        self.assertEqual(btsr.bt, ['s(', 'a1', 'a0', ')'])

        # Change control node to control node
        btsr.set(['s(', 'a0', 'a0', ')']).change_node(0, 'f(')
        self.assertEqual(btsr.bt, ['f(', 'a0', 'a0', ')'])

        # Change up node, not possible
        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0',
                  ')']).change_node(5, 'a0')
        self.assertEqual(btsr.bt,
                         ['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')'])
    def test_find_up_node(self):
        """ Tests find_up_node function """

        btsr = BehaviorTreeStringRepresentation([])

        btsr.set(['s(', 'a0', 'f(', 'a0', ')', 'a0', ')'])
        self.assertEqual(btsr.find_up_node(0), 6)

        btsr.set(['s(', 'a0', 'f(', 'a0', ')', 'a0', ')'])
        self.assertEqual(btsr.find_up_node(2), 4)

        btsr.set(['s(', 'a0', 'f(', 's(', 'a0', ')', 'a0', ')'])
        self.assertEqual(btsr.find_up_node(2), 7)

        btsr.set(['s(', 'a0', 'f(', 'a0', ')', 'a0', ')'])
        with self.assertRaises(Exception):
            _ = btsr.find_up_node(1)

        btsr.set(['s(', 'a0', 'f(', 'a0', ')', 'a0'])
        with self.assertRaises(Exception):
            _ = btsr.find_up_node(0)

        btsr.set(['s(', 's(', 'a0', 'f(', 'a0', ')', 'a0'])
        with self.assertRaises(Exception):
            _ = btsr.find_up_node(1)
    def test_add_node(self):
        """ Tests add_node function """

        btsr = BehaviorTreeStringRepresentation([])
        random.seed(1337)

        btsr.set(['a0']).add_node(0, 's(')
        self.assertEqual(btsr.bt, ['s(', 'a0', ')'])

        btsr.set(['s(', 'a0', 'a0', ')']).add_node(2)
        self.assertEqual(btsr.bt, ['s(', 'a0', 'a3', 'a0', ')'])

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0',
                  ')']).add_node(2, 'a0')
        self.assertEqual(btsr.bt,
                         ['s(', 'a0', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')'])

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0',
                  ')']).add_node(3, 'a0')
        self.assertEqual(btsr.bt,
                         ['s(', 'a0', 'f(', 'a0', 'a0', 'a0', ')', 'a0', ')'])

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0',
                  ')']).add_node(0, 'f(')
        self.assertEqual(
            btsr.bt, ['f(', 's(', 'a0', 'f(', 'a0', 'a0', ')', 'a0', ')', ')'])

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0',
                  ')']).add_node(4, 's(')
        self.assertTrue(btsr.is_valid())

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0',
                  ')']).add_node(2, 'f(')
        self.assertTrue(btsr.is_valid())

        btsr.set(['s(', 'a0', 'f(', 'a0', 'a0', ')', 'a0',
                  ')']).add_node(1, 'f(')
        self.assertTrue(btsr.is_valid())

        btsr.set(['s(', 'a0', 'f(', 'c1', 'a0', ')', ')']).add_node(2, 'f(')
        self.assertTrue(btsr.is_valid())
    def test_is_valid(self):

        btsr = BehaviorTreeStringRepresentation([])
        self.assertFalse(btsr.is_valid())

        # Valid tree
        btsr.set(['s(', 'c0', 'f(', 'c0', 'a0', ')', 'a0', ')'])
        self.assertTrue(btsr.is_valid())

        # Minimal valid tree - just an action node
        btsr.set(['a0'])
        self.assertTrue(btsr.is_valid())

        # Two control nodes at root level - not valid
        btsr.set(
            ['s(', 'c0', 'f(', 'c0', 'a0', ')', 'a0', ')', 's(', 'a0', ')'])
        self.assertFalse(btsr.is_valid())

        # Action node at root level - not valid
        btsr.set(['s(', 'c0', 'f(', 'c0', 'a0', ')', ')', 'a0', ')'])
        self.assertFalse(btsr.is_valid())

        # Too few up nodes - not valid
        btsr.set(['s(', 'c0', 'f(', 'c0', 'a0', ')', 'a0'])
        self.assertFalse(btsr.is_valid())

        # Too few up nodes - not valid
        btsr.set(['s(', 'c0', 'f(', 'c0', 'a0', ')'])
        self.assertFalse(btsr.is_valid())

        # No control nodes, but more than one action - not valid
        btsr.set(['a0', 'a0'])
        self.assertFalse(btsr.is_valid())

        # Starts with an up node - not valid
        btsr.set([')', 'f(', 'c0', 'a0', ')'])
        self.assertFalse(btsr.is_valid())

        # Just a control node - not valid
        btsr.set(['s(', ')'])
        self.assertFalse(btsr.is_valid())

        # Just a control node - not valid
        btsr.set(['s(', 's('])
        self.assertFalse(btsr.is_valid())

        # Up just after control node
        btsr.set(['s(', 'f(', ')', 'a0', ')'])
        self.assertFalse(btsr.is_valid())

        # Unknown characters
        btsr.set(['s(', 'c0', 'x', 'y', 'z', ')'])
        self.assertFalse(btsr.is_valid())