def test_root(self):
        domain = ['a', 'b', 'c']
        x1 = Variable('x1', domain)
        x2 = Variable('x2', domain)
        x3 = Variable('x3', domain)
        variables = [x1, x2, x3]

        r1 = NAryFunctionRelation(lambda x, y: x + y, [x1, x2], name='r1')
        r2 = NAryFunctionRelation(lambda x, y: x - y, [x2, x3], name='r2')
        relations = [r1, r2]

        tree_root = _generate_dfs_tree(variables, relations, x1)
        self.assertEqual(tree_root.variable, x1)

        tree_root = _generate_dfs_tree(variables, relations)
        self.assertIn(tree_root.variable, variables)
    def test_2nodes_tree(self):
        domain = ['a', 'b', 'c']
        x1 = Variable('x1', domain)
        x2 = Variable('x2', domain)
        variables = [x1, x2]

        r1 = NAryFunctionRelation(lambda x, y: x + y, [x1, x2], name='r1')
        relations = [r1]

        root = _generate_dfs_tree(variables, relations, root=x1)

        self.assertEqual(root.variable, x1)
        self.assertEqual(root.parent, None)
        self.assertEqual(len(root.children), 1)
        self.assertEqual(len(root.relations), 1)
        node = root.children[0]
        self.assertEqual(node.variable, x2)
        self.assertEqual(root.pseudo_children, [])
        self.assertEqual(root.pseudo_parents, [])

        self.assertEqual(node.parent, root)
        self.assertEqual(node.children, [])
        self.assertEqual(node.pseudo_children, [])
        self.assertEqual(node.pseudo_parents, [])
        self.assertEqual(node.relations, [r1])

        check_tree(root)
    def test_4nodes(self):
        # Graph with 4 nodes, one cycle
        #
        #       x1---X3
        #        \  /
        #         x2---x4

        domain = ['a', 'b', 'c']
        x1 = Variable('x1', domain)
        x2 = Variable('x2', domain)
        x3 = Variable('x3', domain)
        x4 = Variable('x4', domain)
        variables = [x1, x2, x3, x4]

        def binary_func(x, y):
            return x + y

        r1 = NAryFunctionRelation(binary_func, [x1, x2], name='r1')
        r2 = NAryFunctionRelation(binary_func, [x1, x3], name='r2')
        r3 = NAryFunctionRelation(binary_func, [x2, x3], name='r3')
        r4 = NAryFunctionRelation(binary_func, [x2, x4], name='r4')
        relations = [r1, r2, r3, r4]

        root = _generate_dfs_tree(variables, relations, root=x1)
        _filter_relation_to_lowest_node(root)

        check_tree(root)

        self.assertEqual(root.variable, x1)
        self.assertEqual(root.parent, None)
        self.assertEqual(len(root.children), 1)
        self.assertEqual(len(root.relations), 0)
    def test_3nodes_tree_cycle_3ary_rel_bottom(self):
        # A graph with 3 variables and a single 3-ary relation.

        domain = ['a', 'b', 'c']
        x1 = Variable('x1', domain)
        x2 = Variable('x2', domain)
        x3 = Variable('x3', domain)
        variables = [x1, x2, x3]
        r1 = NAryFunctionRelation(lambda x, y, z: x + y + z, [x1, x2, x3],
                                  name='r1')
        relations = [r1]

        root = _generate_dfs_tree(variables, relations, root=x1)
        _filter_relation_to_lowest_node(root)

        self.assertEqual(root.variable, x1)
        self.assertEqual(root.parent, None)
        self.assertEqual(len(root.children), 1)
        self.assertEqual(len(root.relations), 0)
        c1 = root.children[0]
        self.assertIn(c1.variable, [x2, x3])
        self.assertEqual(len(root.pseudo_children), 1)
        self.assertEqual(root.pseudo_parents, [])

        self.assertEqual(c1.parent, root)
        self.assertEqual(len(c1.children), 1)
        c2 = c1.children[0]
        self.assertEqual(c2.children, [])
        self.assertEqual(c2.pseudo_children, [])
        self.assertEqual(c2.pseudo_parents, [root])

        self.assertEqual(len(c1.relations) + len(c2.relations), 1)

        check_tree(root)
    def test_3nodes_tree_cycle(self):
        domain = ['a', 'b', 'c']
        x1 = Variable('x1', domain)
        x2 = Variable('x2', domain)
        x3 = Variable('x3', domain)
        variables = [x1, x2, x3]

        r1 = NAryFunctionRelation(lambda x, y: x + y, [x1, x2], name='r1')
        r2 = NAryFunctionRelation(lambda x, y: x + y, [x1, x3], name='r2')
        r3 = NAryFunctionRelation(lambda x, y: x + y, [x2, x3], name='r3')
        relations = [r1, r2, r3]

        dcop = DCOP('test', 'min')
        dcop.add_constraint(r1)
        dcop.add_constraint(r2)
        dcop.add_constraint(r3)

        cg = build_computation_graph(dcop)
        self.assertEqual(len(cg.nodes), len(variables))

        self.assertEqual(len(cg.roots), 1)
        # All variables have the same number of neighbors, they could all be
        #  root
        self.assertIn(cg.roots[0].variable, [x1, x2, x3])
        self.assertEqual(cg.roots[0].parent, None)

        root = _generate_dfs_tree(variables, relations, root=x1)
        self.assertEqual(root.variable, x1)
        self.assertEqual(root.parent, None)
    def test_3nodes_tree_cycle(self):
        domain = ['a', 'b', 'c']
        x1 = Variable('x1', domain)
        x2 = Variable('x2', domain)
        x3 = Variable('x3', domain)
        variables = [x1, x2, x3]

        r1 = NAryFunctionRelation(lambda x, y: x + y, [x1, x2], name='r1')
        r2 = NAryFunctionRelation(lambda x, y: x + y, [x1, x3], name='r2')
        r3 = NAryFunctionRelation(lambda x, y: x + y, [x2, x3], name='r3')
        relations = [r1, r2, r3]

        root = _generate_dfs_tree(variables, relations, root=x1)

        self.assertEqual(root.variable, x1)
        self.assertEqual(root.parent, None)
        self.assertEqual(len(root.children), 1)
        c1 = root.children[0]
        self.assertIn(c1.variable, [x2, x3])
        self.assertEqual(len(root.pseudo_children), 1)
        self.assertEqual(root.pseudo_parents, [])

        self.assertEqual(c1.parent, root)
        self.assertEqual(len(c1.children), 1)
        c2 = c1.children[0]
        self.assertEqual(c2.children, [])
        self.assertEqual(c2.pseudo_children, [])
        self.assertEqual(c2.pseudo_parents, [root])

        check_tree(root)
    def test_visit_tree(self):
        domain = ['a', 'b', 'c']
        x1 = Variable('x1', domain)
        x2 = Variable('x2', domain)
        x3 = Variable('x3', domain)
        x4 = Variable('x4', domain)
        variables = [x1, x2, x3, x4]

        binary_func = lambda x, y: x + y
        r1 = NAryFunctionRelation(binary_func, [x1, x2], name='r1')
        r2 = NAryFunctionRelation(binary_func, [x1, x3], name='r2')
        r3 = NAryFunctionRelation(binary_func, [x2, x3], name='r3')
        r4 = NAryFunctionRelation(binary_func, [x2, x4], name='r4')
        relations = [r1, r2, r3, r4]

        root = _generate_dfs_tree(variables, relations, root=x1)

        for node in _visit_tree(root):
            self.assertIn(node.variable, variables)
            variables.remove(node.variable)

        self.assertEqual(len(variables), 0)