Пример #1
0
def problem(args):
    p = GenericProblem(
        args["active_constraints"],
        args["passive_constraints"],
        args["leaf_constraints"],
        args["root_constraints"],
        leaf_allow_all=(args["leaf_constraints"] == []),
        root_allow_all=(args["root_constraints"] == []),
        flags=ProblemFlags(is_tree=args["is_tree"],
                           is_cycle=args["is_cycle"],
                           is_path=args["is_path"]),
    )

    classified_problem = get_classified_problem_obj(p)
    if classified_problem is not None:
        return jsonify({
            "problem": classified_problem.to_problem().dict(),
            "result": classified_problem.to_response().dict(),
        })
    else:
        res = classify(p)
        if not (res.det_lower_bound == CONST and res.det_upper_bound
                == UNSOLVABLE and res.rand_lower_bound == CONST
                and res.rand_upper_bound == UNSOLVABLE):
            store_problem_and_classification(p, res)
        return jsonify({"problem": p.dict(), "result": res.dict()})
Пример #2
0
def validate(p: GenericProblem) -> None:
    if p.flags.is_cycle:
        raise Exception("tlp", "Cannot classify if the graph is a cycle")

    if p.flags.is_directed_or_rooted:
        raise Exception("tlp",
                        "Cannot classify if the tree/path is rooted/directed")

    if not p.flags.is_regular:
        raise Exception("tlp", "Cannot classify if the graph is not regular")

    if not p.root_allow_all or not p.leaf_allow_all:
        raise Exception("tlp",
                        "Leaves and roots must allow all configurations")

    if len(p.get_alphabet()) > 3:
        raise Exception("tlp",
                        "Cannot classify problems with more than 3 labels")

    active_degree = len(p.active_constraints[0]) if len(
        p.active_constraints) else 3
    passive_degree = len(p.passive_constraints[0]) if len(
        p.passive_constraints) else 2

    if not ((active_degree == 2 and passive_degree == 2) or
            (active_degree == 2 and passive_degree == 3) or
            (active_degree == 3 and passive_degree == 2)):
        raise Exception("rooted-tree",
                        "Allowed degrees pairs are (2, 2), (2, 3), (3, 2)")
Пример #3
0
def preprocess_problem(p: GenericProblem) -> List[str]:
    alphabet = p.get_alphabet()
    constraints = [move_root_label_to_center(x) for x in p.active_constraints]

    for i, label in enumerate(alphabet):
        constraints = [x.replace(label, str(i + 1)) for x in constraints]
    return constraints
Пример #4
0
 def test_re2(self):
     REtorProblem2 = GenericProblem(active_constraints=["A AB AB AB"],
                                    passive_constraints=["B AB AB"])
     res = classify(REtorProblem2)
     self.assertEqual(res.det_lower_bound, LOG)
     self.assertEqual(res.det_upper_bound, UNSOLVABLE)
     self.assertEqual(res.rand_upper_bound, UNSOLVABLE)
     self.assertEqual(res.rand_lower_bound, LOGLOG)
Пример #5
0
 def test_brt0(self):
     binary_rooted_tree_problem0 = GenericProblem(
         ["a : a a"], ["a : a"], flags=ProblemFlags(is_tree=True))
     res = classify(binary_rooted_tree_problem0)
     self.assertEqual(res.det_lower_bound, CONST)
     self.assertEqual(res.det_upper_bound, CONST)
     self.assertEqual(res.rand_upper_bound, CONST)
     self.assertEqual(res.rand_lower_bound, CONST)
Пример #6
0
 def test_re3(self):
     # const, 1 round solvable
     REtorProblem3 = GenericProblem(["M U U U", "PM PM PM PM"],
                                    ["M UP UP UP", "U U U U"])
     res = classify(REtorProblem3)
     self.assertEqual(res.det_lower_bound, CONST)
     self.assertEqual(res.det_upper_bound, CONST)
     self.assertEqual(res.rand_upper_bound, CONST)
     self.assertEqual(res.rand_lower_bound, CONST)
Пример #7
0
 def test_re1(self):
     REtorProblem1 = GenericProblem(
         active_constraints=["M U U U", "P P P P"],
         passive_constraints=["M UP UP UP", "U U U U"],
     )
     res = classify(REtorProblem1)
     self.assertEqual(res.det_lower_bound, CONST)
     self.assertEqual(res.det_upper_bound, UNSOLVABLE)
     self.assertEqual(res.rand_upper_bound, UNSOLVABLE)
     self.assertEqual(res.rand_lower_bound, CONST)
Пример #8
0
 def test_tlp1(self):
     # AB, CC
     # BBC, AAA, BBB, AAC, BCC
     # output: log* n
     tlp_problem1 = GenericProblem(
         ["A B", "C C"], ["B B C", "A A A", "B B B", "A A C", "B C C"])
     res = classify(tlp_problem1)
     self.assertEqual(res.det_lower_bound, ITERATED_LOG)
     self.assertEqual(res.det_upper_bound, ITERATED_LOG)
     self.assertEqual(res.rand_upper_bound, ITERATED_LOG)
     self.assertEqual(res.rand_lower_bound, ITERATED_LOG)
Пример #9
0
 def test_tlp4(self):
     # AB, CC
     # BBC, AAA, BBB, AAC, BCC
     # output: log* n
     tlp_problem1 = GenericProblem(
         ["1 2", "3 3"], ["2 2 3", "1 1 1", "2 2 2", "1 1 3", "2 3 3"])
     res = classify(tlp_problem1)
     self.assertEqual(res.det_lower_bound, ITERATED_LOG)
     self.assertEqual(res.det_upper_bound, ITERATED_LOG)
     self.assertEqual(res.rand_upper_bound, ITERATED_LOG)
     self.assertEqual(res.rand_lower_bound, ITERATED_LOG)
Пример #10
0
 def test_tlp3(self):
     # AC AB CC BC
     # BB AC AB BC
     # output: O(1) 1
     tlp_problem3 = GenericProblem(["A C", "A B", "C C", "B C"],
                                   ["B B", "A C", "A B", "B C"])
     res = classify(tlp_problem3)
     self.assertEqual(res.det_lower_bound, CONST)
     self.assertEqual(res.det_upper_bound, CONST)
     self.assertEqual(res.rand_upper_bound, CONST)
     self.assertEqual(res.rand_lower_bound, CONST)
Пример #11
0
 def test_tlp2(self):
     # AA CC BC
     # AAA AAB AAC BCC ACC
     # output: O(1) 0
     tlp_problem2 = GenericProblem(
         ["A A", "C C", "B C"],
         ["A A A", "A A B", "A A C", "B C C", "A C C"])
     res = classify(tlp_problem2)
     self.assertEqual(res.det_lower_bound, CONST)
     self.assertEqual(res.det_upper_bound, CONST)
     self.assertEqual(res.rand_upper_bound, CONST)
     self.assertEqual(res.rand_lower_bound, CONST)
Пример #12
0
 def test_cycle_path4(self):
     # -undir -n "{ 11, 22, 33 }" -e "{ 12, 21, 13, 31, 23, 32 }"
     # cycle path classifier
     cycle_path_problem4 = GenericProblem(
         ["A A", "B B", "C C"],
         ["A B", "B A", "A C", "C A", "B C", "C B"],
         flags=ProblemFlags(is_cycle=True, is_path=False, is_tree=False),
     )
     res = classify(cycle_path_problem4)
     self.assertEqual(res.det_lower_bound, ITERATED_LOG)
     self.assertEqual(res.det_upper_bound, ITERATED_LOG)
     self.assertEqual(res.rand_upper_bound, ITERATED_LOG)
     self.assertEqual(res.rand_lower_bound, ITERATED_LOG)
Пример #13
0
 def test_cycle_path1(self):
     # 3-coloring on a rooted trees (degree not known i.e. not just binary)
     # 12, 13, 23, 21, 31, 32 in automata-theoretic formalism
     # cycle path classifier
     cycle_path_tree_problem1 = GenericProblem(
         ["a : a a a a", "b : b b b b", "c : c c c c"],
         ["a : b", "a : c", "b : c", "b : a", "c : a", "c : b"],
         flags=ProblemFlags(is_tree=True, ),
     )
     res = classify(cycle_path_tree_problem1)
     self.assertEqual(res.det_lower_bound, ITERATED_LOG)
     self.assertEqual(res.det_upper_bound, ITERATED_LOG)
     self.assertEqual(res.rand_upper_bound, ITERATED_LOG)
     self.assertEqual(res.rand_lower_bound, ITERATED_LOG)
Пример #14
0
 def test_brt3(self):
     # "121",
     # "131"
     # "132"
     # decider, tree-classification
     # output: unsolvable
     binary_rooted_tree_problem3 = GenericProblem(
         ["b : a a", "c : a a", "c : a b"],
         ["a : a", "b : b", "c : c"],
         flags=ProblemFlags(is_tree=True),
     )
     res = classify(binary_rooted_tree_problem3)
     self.assertEqual(res.det_lower_bound, UNSOLVABLE)
     self.assertEqual(res.det_upper_bound, UNSOLVABLE)
     self.assertEqual(res.rand_upper_bound, UNSOLVABLE)
     self.assertEqual(res.rand_lower_bound, UNSOLVABLE)
Пример #15
0
 def test_brt2(self):
     # "121",
     # "132",
     # "213"
     # decider, tree-classification
     # output: O(log n)
     binary_rooted_tree_problem2 = GenericProblem(
         ["b : a a", "c : a b", "a : b c"],
         ["a : a", "b : b", "c : c"],
         flags=ProblemFlags(is_tree=True),
     )
     res = classify(binary_rooted_tree_problem2)
     self.assertEqual(res.det_lower_bound, LOG)
     self.assertEqual(res.det_upper_bound, LOG)
     self.assertEqual(res.rand_upper_bound, LOG)
     self.assertEqual(res.rand_lower_bound, LOG)
Пример #16
0
 def test_brt1(self):
     # "111",
     # "121",
     # "131"
     # "132"
     # decider, tree-classification
     # output: O(1)
     binary_rooted_tree_problem1 = GenericProblem(
         ["a : a a", "b : a a", "c : a a", "c : a b"],
         ["a : a", "b : b", "c : c"],
         flags=ProblemFlags(is_tree=True),
     )
     res = classify(binary_rooted_tree_problem1)
     self.assertEqual(res.det_lower_bound, CONST)
     self.assertEqual(res.det_upper_bound, CONST)
     self.assertEqual(res.rand_upper_bound, CONST)
     self.assertEqual(res.rand_lower_bound, CONST)
Пример #17
0
 def test_cycle_path3(self):
     # -dir -n "{00, 1M}" -e "{01, 10, 11, MM}"
     # --start-constr "{ 1 }" --end-constr "{ 0 }"
     # cycle path classifier
     cycle_path_problem3 = GenericProblem(
         ["A : A", "B : M"],  # node constraints
         ["A : B", "B : A", "B : B", "M : M"],  # edge constraints
         leaf_constraints=["B"],
         leaf_allow_all=False,  # leaf constraint = end-constr
         root_constraints=["B"],
         root_allow_all=False,  # root constraint = start-constr
         flags=ProblemFlags(
             is_cycle=False,
             is_path=True,
             is_tree=False,
         ),
     )
     res = classify(cycle_path_problem3)
     self.assertEqual(res.det_lower_bound, CONST)
     self.assertEqual(res.det_upper_bound, CONST)
     self.assertEqual(res.rand_upper_bound, CONST)
     self.assertEqual(res.rand_lower_bound, CONST)
Пример #18
0
def classify(p: GenericProblem, context: ClassifyContext) -> GenericResponse:
    if context.brt_preclassified:
        return GenericResponse(p)

    validate(p)
    alphabet = p.get_alphabet()
    constraints = [move_root_label_to_center(x) for x in p.active_constraints]

    for i, label in enumerate(alphabet):
        constraints = [x.replace(label, str(i + 1)) for x in constraints]

    result = getProblem(constraints)

    return GenericResponse(
        p,
        complexity_mapping[result["upper-bound"]],
        complexity_mapping[result["lower-bound"]],
        UNSOLVABLE,
        complexity_mapping[result[
            "lower-bound"]],  # because randomised LB is also a deterministic LB
        result["solvable-count"],
        result["unsolvable-count"],
    )
 def to_problem(self) -> GenericProblem:
     p = GenericProblem(["A A"], ["A A"])
     p.id = self.id
     p.active_constraints = self.active_constraints
     p.passive_constraints = self.passive_constraints
     p.leaf_constraints = self.leaf_constraints
     p.root_constraints = self.root_constraints
     alphabet = p.get_alphabet()
     p.leaf_allow_all = (set(flatten(p.leaf_constraints)) -
                         {" "}) == set(alphabet)
     p.root_allow_all = (set(flatten(p.root_constraints)) -
                         {" "}) == set(alphabet)
     p.flags = ProblemFlags(
         is_tree=self.is_tree,
         is_cycle=self.is_cycle,
         is_path=self.is_path,
         is_directed_or_rooted=self.is_directed_or_rooted,
         is_regular=self.is_regular,
     )
     return p
Пример #20
0
def store_problem_and_get_with_id(p: GenericProblem) -> GenericProblem:
    with get_db_cursor(commit=True) as cur:
        problem_data = (
            p.get_active_degree(),
            p.get_passive_degree(),
            len(p.get_alphabet()),
            each_constr_is_homogeneous(p.active_constraints),
            each_constr_is_homogeneous(p.passive_constraints),
            list(p.active_constraints),
            list(p.passive_constraints),
            list(p.leaf_constraints),
            list(p.root_constraints),
            p.flags.is_tree,
            p.flags.is_cycle,
            p.flags.is_path,
            p.flags.is_directed_or_rooted,
            p.flags.is_regular,
        )
        cur.execute(
            """
            INSERT INTO problems (
            active_degree,
            passive_degree,
            label_count,
            actives_all_same,
            passives_all_same,

            active_constraints,
            passive_constraints,
            root_constraints,
            leaf_constraints,
            is_tree,
            is_cycle,
            is_path,
            is_directed_or_rooted,
            is_regular
            ) VALUES (
                %s, %s, %s, %s, %s,
                %s, %s, %s, %s, %s,
                %s, %s, %s, %s
            ) ON CONFLICT DO NOTHING RETURNING id;""",
            problem_data,
        )

        res = cur.fetchone()
        if res is None:
            cur.execute(
                """
                SELECT id FROM problems
                WHERE
                    active_degree = %s AND
                    passive_degree = %s AND
                    label_count = %s AND
                    actives_all_same = %s AND
                    passives_all_same = %s AND

                    active_constraints = %s AND
                    passive_constraints = %s AND
                    root_constraints = %s AND
                    leaf_constraints = %s AND
                    is_tree = %s AND
                    is_cycle = %s AND
                    is_path = %s AND
                    is_directed_or_rooted = %s AND
                    is_regular = %s;
            """,
                problem_data,
            )
            res = cur.fetchone()

        p.id = res["id"]

    return p
Пример #21
0
def classify(p: GenericProblem, context: ClassifyContext) -> GenericResponse:
    active_degree = len(p.active_constraints[0]) if len(
        p.active_constraints) else 2
    passive_degree = len(p.passive_constraints[0]) if len(
        p.passive_constraints) else 2
    leaf_degree = len(p.leaf_constraints[0]) if len(p.leaf_constraints) else 1

    if leaf_degree != 1:
        raise Exception("cyclepath",
                        "Leaf constraints must always be of degree 1")

    if passive_degree != 2:
        raise Exception("cyclepath",
                        "Passive constraints must always be of degree 2")

    if p.flags.is_tree:
        if not each_constr_is_homogeneous(p.active_constraints):
            raise Exception(
                "cyclepath",
                "On trees, node constraints must be the same for all incident edges.",
            )
        if not p.flags.is_directed_or_rooted:
            raise Exception(
                "cyclepath",
                "In the context of trees, only rooted ones can be classified.",
            )
    elif active_degree != 2:
        raise Exception(
            "cyclepath",
            "In a path or cycle, active constraints must always be of degree 2",
        )

    problem_type = (Type.TREE if p.flags.is_tree else (
        Type.DIRECTED if p.flags.is_directed_or_rooted else Type.UNDIRECTED))

    if not p.flags.is_directed_or_rooted:
        p.passive_constraints = p.passive_constraints + tuple(
            [cs[::-1] for cs in p.passive_constraints])
        p.active_constraints = p.active_constraints + tuple(
            [cs[::-1] for cs in p.active_constraints])

    edge_constraints = set(p.passive_constraints)
    node_constraints = {} if problem_type == Type.TREE else set(
        p.active_constraints)
    start_constraints = {} if p.root_allow_all else set(p.root_constraints)
    end_constraints = {} if p.leaf_allow_all else set(p.leaf_constraints)

    cp_problem = CyclePathProblem(
        node_constraints,
        edge_constraints,
        start_constraints,
        end_constraints,
        problem_type,
    )

    result = cpClassify(cp_problem)

    complexity_mapping = {
        CP_CONST: CONST,
        CP_GLOBAL: GLOBAL,
        CP_ITERATED_LOG: ITERATED_LOG,
        CP_UNSOLVABLE: UNSOLVABLE,
    }
    normalised_complexity = complexity_mapping[result["complexity"]]

    return GenericResponse(
        p,
        normalised_complexity,
        normalised_complexity,
        normalised_complexity,
        normalised_complexity,
        result["solvable"],
        result["unsolvable"],
    )