Beispiel #1
0
def remove_unknowns(response: GenericResponse) -> GenericResponse:
    if response.rand_lower_bound == UNKNOWN:
        response.rand_lower_bound = CONST
    if response.det_lower_bound == UNKNOWN:
        response.det_lower_bound = CONST
    if response.rand_upper_bound == UNKNOWN:
        response.rand_upper_bound = UNSOLVABLE
    if response.det_upper_bound == UNKNOWN:
        response.det_upper_bound = UNSOLVABLE
    return response
def classify(p: GenericProblem, context: ClassifyContext) -> GenericResponse:
    if context.tlp_preclassified:
        return GenericResponse(p)

    validate(p)
    result = get_problem(p.active_constraints, p.passive_constraints)

    return GenericResponse(
        p,
        complexity_mapping[
            result.
            upper_bound],  # because deterministic UB is also a randomised UB
        CONST,
        complexity_mapping[result.upper_bound],
        complexity_mapping[result.lower_bound],
    )
 def to_response(self) -> GenericResponse:
     return GenericResponse(
         problem=self.to_problem(),
         rand_upper_bound=self.rand_upper_bound,
         rand_lower_bound=self.rand_lower_bound,
         det_upper_bound=self.det_upper_bound,
         det_lower_bound=self.det_lower_bound,
         solvable_count=self.solvable_count,
         unsolvable_count=self.unsolvable_count,
         papers=self.papers,
     )
def classify(problem: GenericProblem,
             context: ClassifyContext) -> GenericResponse:
    validate(problem)

    data = ("\n".join(
        unparse_configs(problem.active_constraints,
                        problem.flags.is_directed_or_rooted)) + "\n\n" +
            "\n".join(
                unparse_configs(problem.passive_constraints,
                                problem.flags.is_directed_or_rooted)))

    timeout_seconds = 0.1 if context.is_batch else 0.5
    # potentially add here things like labels and iter
    # that depend on whether we're operating in a batch mode

    ctx = mp.get_context("fork")
    q = ctx.Queue()
    process = ctx.Process(target=run_r_e, kwargs={"data": data, "q": q})
    process.start()
    try:
        (lower_bound_raw, upper_bound_raw) = q.get(timeout=timeout_seconds)
    except:
        pass
    process.join(timeout_seconds)
    if process.is_alive():
        process.terminate()
        process.join()

    if lower_bound_raw == "log n":
        lower_bound = LOG
        lower_bound_rand = LOGLOG
    elif lower_bound_raw == "unknown":
        lower_bound = CONST
        lower_bound_rand = CONST
    else:
        lower_bound = CONST
        lower_bound_rand = CONST

    if upper_bound_raw == "unknown":
        upper_bound = UNSOLVABLE
        upper_bound_rand = UNSOLVABLE
    else:
        upper_bound = CONST
        upper_bound_rand = CONST

    return GenericResponse(
        problem,
        upper_bound_rand,
        lower_bound_rand,
        upper_bound,
        lower_bound,
    )
Beispiel #5
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 batch_classify(ps: List[GenericProblem]) -> List[GenericResponse]:
    try:
        for p in ps:
            validate(p)
    except Exception as e:
        print(e)
        raise Exception("Cannot batch classify")

    results = get_problems([(p.active_constraints, p.passive_constraints)
                            for p in ps])
    return [
        GenericResponse(
            ps[i],
            complexity_mapping[
                r.
                upper_bound],  # because deterministic UB is also a randomised UB
            CONST,
            complexity_mapping[r.upper_bound],
            complexity_mapping[r.lower_bound],
        ) for i, r in enumerate(results)
    ]
Beispiel #7
0
def batch_classify(ps: List[GenericProblem]) -> List[GenericResponse]:
    try:
        for p in ps:
            validate(p)
    except Exception as e:
        print(e)
        raise Exception("Cannot batch classify")

    constrs = [preprocess_problem(p) for p in ps]

    results = getProblems(constrs, len(set(flatten(flatten(constrs)))))

    return [
        GenericResponse(
            ps[i],
            complexity_mapping[r["upper-bound"]],
            complexity_mapping[r["lower-bound"]],
            UNSOLVABLE,
            complexity_mapping[r[
                "lower-bound"]],  # because randomised LB is also a deterministic LB
            r["solvable-count"],
            r["unsolvable-count"],
        ) for i, r in enumerate(results)
    ]
Beispiel #8
0
def propagate_bounds(response: GenericResponse) -> GenericResponse:
    # propagate rand upper
    if complexities.index(response.det_upper_bound) < complexities.index(
            response.rand_upper_bound):
        response.rand_upper_bound = response.det_upper_bound
        response.papers.rand_upper_bound_source = response.papers.det_upper_bound_source

    # propagate det lower
    if complexities.index(response.rand_lower_bound) > complexities.index(
            response.det_lower_bound):
        response.det_lower_bound = response.rand_lower_bound
        response.papers.det_lower_bound_source = response.papers.rand_lower_bound_source

    # propagate det upper
    if response.rand_upper_bound != LOGLOG:
        response.det_upper_bound = response.rand_upper_bound
        response.papers.det_upper_bound_source = response.papers.rand_upper_bound_source
    elif complexities.index(LOG) < complexities.index(
            response.det_upper_bound):
        response.det_upper_bound = LOG
        # source of det_upper_bound is still in this case
        # dictated by rand_upper_bound
        response.papers.det_upper_bound_source = response.papers.rand_upper_bound_source

    # propagate rand lower
    if response.det_lower_bound != LOG:
        response.rand_lower_bound = response.det_lower_bound
        response.papers.rand_lower_bound_source = response.papers.det_lower_bound_source
    elif complexities.index(LOGLOG) > complexities.index(
            response.rand_lower_bound):
        response.rand_lower_bound = LOGLOG
        # source of rand_lower_bound_source is still in this case
        # dictated by det_lower_bound_source
        response.papers.rand_lower_bound_source = response.papers.det_lower_bound_source

    return response
Beispiel #9
0
def classify(
        problem: GenericProblem,
        existing_classifications: Dict[Classifier, GenericResponse] = {},
        context: ClassifyContext = ClassifyContext(),
) -> GenericResponse:
    try:
        cp_result = cp_classify(problem, context)
    except Exception:
        cp_result = GenericResponse(problem)

    try:
        rt_result = rt_classify(problem, context)
    except Exception:
        rt_result = GenericResponse(problem)

    try:
        tlp_result = tlp_classify(problem, context)
    except Exception:
        tlp_result = GenericResponse(problem)

    try:
        brt_result = brt_classify(problem, context)
    except Exception:
        brt_result = GenericResponse(problem)

    try:
        re_result = re_classify(problem, context)
    except Exception:
        re_result = GenericResponse(problem)

    responses = {
        Classifier.CP: cp_result,
        Classifier.RT: rt_result,
        Classifier.TLP: tlp_result,
        Classifier.BRT: brt_result,
        Classifier.RE: re_result,
        **existing_classifications,
    }

    check_for_contradictions(responses)

    rub_source, rub = get_upper_bound(responses, "rand_upper_bound")
    rlb_source, rlb = get_lower_bound(responses, "rand_lower_bound")
    dub_source, dub = get_upper_bound(responses, "det_upper_bound")
    dlb_source, dlb = get_lower_bound(responses, "det_lower_bound")

    response = GenericResponse(
        problem,
        rub,
        rlb,
        dub,
        dlb,
        cp_result.solvable_count,
        cp_result.unsolvable_count,
        papers=Sources(
            context.sources[rub_source],
            context.sources[rlb_source],
            context.sources[dub_source],
            context.sources[dlb_source],
        ),
    )

    return postprocess(response)
Beispiel #10
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"],
    )
Beispiel #11
0
def classify(p: GenericProblem, context: ClassifyContext) -> GenericResponse:
    if not p.flags.is_tree:
        raise Exception("rooted-tree",
                        "Cannot classify if the problem is not a tree")

    if not p.flags.is_directed_or_rooted:
        raise Exception("rooted-tree",
                        "Cannot classify if the tree is not rooted")

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

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

    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 active_degree != 3:
        raise Exception("rooted-tree",
                        "Active configurations must be of size 3")

    if passive_degree != 2:
        raise Exception("rooted-tree",
                        "Passive configurations must be of size 2")

    if not each_constr_is_homogeneous(p.passive_constraints):
        raise Exception(
            "rooted-tree",
            "Passive constraints must be simple pairs of the same labels.",
        )

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

    det_upper_bound = UNSOLVABLE
    det_lower_bound = CONST
    rand_upper_bound = UNSOLVABLE
    rand_lower_bound = CONST
    if is_log_solvable(constraints):  # is not empty
        if is_log_star_solvable(constraints):
            if is_constant_solvable(constraints):
                det_upper_bound = CONST
                rand_upper_bound = CONST
            else:
                det_upper_bound = ITERATED_LOG
                det_lower_bound = ITERATED_LOG
                rand_upper_bound = ITERATED_LOG
                rand_lower_bound = ITERATED_LOG
        else:
            det_upper_bound = LOG
            det_lower_bound = LOG
            rand_upper_bound = LOG
            rand_lower_bound = LOG  # because LOGLOG does not exist in the setting
    else:
        det_lower_bound = GLOBAL
        rand_lower_bound = GLOBAL

    return GenericResponse(p, rand_upper_bound, rand_lower_bound,
                           det_upper_bound, det_lower_bound)