Example #1
0
    def assert_clause(self, *literals):
        """
        Takes a list of TermComparisons representing a disjunction.
        Stores the list as a Clause object.
        """
        #todo: ASSERTION_FULL version
        disjunctions = []
        for l in literals:
            tc = l.canonize()
            i, j = self.term_name(tc.term1).index, self.term_name(tc.term2.term).index
            disjunctions.append((i, tc.comp, tc.term2.coeff, j))
        c = terms.Clause(disjunctions)

        s = str(c)

        c.update(self)
        if c.satisfied:
            return

        if messages.visible(messages.ASSERTION) and c not in self.clauses:
            messages.announce_strong('Asserting clause: {0!s}'.format(s))
        l = len(c)
        if l > 1:
            self.clauses.add(c)
        elif l == 1:
            self.assert_comparison(c.first())
        else:
            messages.announce('Contradiction from clause.', messages.DEBUG)
            self.raise_contradiction(0, terms.EQ, 0, 0)
Example #2
0
    def update_clause(self, *p):
        """
        p is either a singleton (i) or a pair (i, j).
        Updates any clauses that have literals containing either t_i or t_i and t_j.
        """
        for c in self.clauses:
            if len(p) == 1:
                c.update_on_index(p[0], self)
            else:
                c.update_on_indices(p[0], p[1], self)

        self.clauses = set(c for c in self.clauses if not c.satisfied)

        empty, unit = None, []
        for c in self.clauses:
            l = len(c)
            if l == 0:
                empty = c
                break
            elif l == 1:
                unit.append(c)
                #self.clauses.remove(c)

        if empty is not None:
            messages.announce('Contradiction from clause.', messages.DEBUG)
            self.raise_contradiction(100, terms.EQ, 100, 100)
        else:  # do these separately, so that learning from one won't recurse to the others.
            for c in unit:
                self.clauses.remove(c)

            for c in unit:
                tc = c.first()
                self.assert_comparison(tc)
Example #3
0
    def update_clause(self, *p):
        """
        p is either a singleton (i) or a pair (i, j).
        Updates any clauses that have literals containing either t_i or t_i and t_j.
        """
        for c in self.clauses:
            if len(p) == 1:
                c.update_on_index(p[0], self)
            else:
                c.update_on_indices(p[0], p[1], self)

        self.clauses = set(c for c in self.clauses if not c.satisfied)

        empty, unit = None, []
        for c in self.clauses:
            l = len(c)
            if l == 0:
                empty = c
                break
            elif l == 1:
                unit.append(c)
                #self.clauses.remove(c)

        if empty is not None:
            messages.announce('Contradiction from clause.', messages.DEBUG)
            self.raise_contradiction(100, terms.EQ, 100, 100)
        else:  # do these separately, so that learning from one won't recurse to the others.
            for c in unit:
                self.clauses.remove(c)

            for c in unit:
                tc = c.first()
                self.assert_comparison(tc)
Example #4
0
    def assert_clause(self, *literals):
        """
        Takes a list of TermComparisons representing a disjunction.
        Stores the list as a Clause object.
        """
        #todo: ASSERTION_FULL version
        disjunctions = []
        for l in literals:
            tc = l.canonize()
            i, j = self.term_name(tc.term1).index, self.term_name(
                tc.term2.term).index
            disjunctions.append((i, tc.comp, tc.term2.coeff, j))
        c = terms.Clause(disjunctions)

        s = str(c)

        c.update(self)
        if c.satisfied:
            return

        if messages.visible(messages.ASSERTION) and c not in self.clauses:
            messages.announce_strong('Asserting clause: {0!s}'.format(s))
        l = len(c)
        if l > 1:
            self.clauses.add(c)
        elif l == 1:
            self.assert_comparison(c.first())
        else:
            messages.announce('Contradiction from clause.', messages.DEBUG)
            self.raise_contradiction(0, terms.EQ, 0, 0)
Example #5
0
    def update_blackboard(self, B):
        """
        Instantiates all stored axioms with respect to B and asserts new clauses.
        """
        timer.start(timer.FUN)
        messages.announce_module('axiom module')
        n = B.num_terms + len(B.equalities.keys()) + len(B.zero_equalities)
        #if n == self.num_eqs:
        #    messages.announce("No new information for the axiom module to use.", messages.DEBUG)
        #    timer.stop(timer.FUN)
        #    return
        self.num_eqs = n

        for a in self.axioms:
            messages.announce("Instantiating axiom: {}".format(a),
                              messages.DEBUG)
            if a.unifiable:
                clauses = instantiate(a, self.used_envs, B)
                for c in clauses:
                    B.assert_clause(*c)
            else:
                clauses = instantiate_triggerless(a, self.used_envs, B)
                for c in clauses:
                    B.assert_clause(*c)
        timer.stop(timer.FUN)
Example #6
0
 def _assert_comparison(self, c):
     """
     Adds a single comparison to the Solver's blackboard.
     """
     try:
         self.B.assert_comparison(c)
     except terms.Contradiction as e:
         self.contradiction = True
         messages.announce(e.msg, messages.ASSERTION)
Example #7
0
def announce_times():
    for k in [k for k in time_cur if time_cur[k] != 0]:
        e_stop(k)
    messages.announce("Average run times:", messages.DEBUG)
    for i in time_total:
        messages.announce(
            "{0!s} module: {1!s} over {2!s} runs. {3!s} total.".format(
                mod_names[i], str(round(time_total[i] / runs[i], 3)), runs[i],
                round(time_total[i], 3)), messages.DEBUG)
Example #8
0
 def _assert_comparison(self, c):
     """
     Adds a single comparison to the Solver's blackboard.
     """
     try:
         self.B.assert_comparison(c)
     except terms.Contradiction as e:
         self.contradiction = True
         messages.announce(e.msg, messages.ASSERTION)
Example #9
0
def run_modules(B, modules, depth, breadth):
    """
    Given a blackboard B, iteratively runs the modules in modules until either a contradiction is
    found or no new information is learned.
    Returns True if a contradiction is found, False otherwise.
    """
    try:
        split_modules(B, modules, depth, breadth)
        return False
    except terms.Contradiction as e:
        messages.announce(e.msg + '\n', messages.ASSERTION)
        return True
Example #10
0
def saturate_modules(B, modules):
    """Run the modules in succession on B until saturation

    Arguments:
    -- B: a blackboard
    -- modules: a list of modules
    """
    mid = B.identify()
    while len(B.get_new_info(mid)) > 0:
        for m in modules:
            messages.announce(B.info_dump(), messages.DEBUG)
            m.update_blackboard(B)
Example #11
0
def solve(split_depth, split_breadth, solver_type, *assertions):
    """
    Given TermComparisons assertions, returns True if they are found to be inconsistent,
     false otherwise. Uses geometric methods if available, otherwise FM.
    """
    B = blackboard.Blackboard()
    try:
        B.assume(*assertions)
    except terms.Contradiction as e:
        messages.announce(e.msg + '\n', messages.ASSERTION)
        return True
    return run(B, split_depth, split_breadth, solver_type)
Example #12
0
def saturate_modules(B, modules):
    """Run the modules in succession on B until saturation

    Arguments:
    -- B: a blackboard
    -- modules: a list of modules
    """
    mid = B.identify()
    while len(B.get_new_info(mid)) > 0:
        for m in modules:
            messages.announce(B.info_dump(), messages.DEBUG)
            m.update_blackboard(B)
Example #13
0
def solve(split_depth, split_breadth, solver_type, *assertions):
    """
    Given TermComparisons assertions, returns True if they are found to be inconsistent,
     false otherwise. Uses geometric methods if available, otherwise FM.
    """
    B = blackboard.Blackboard()
    try:
        B.assume(*assertions)
    except terms.Contradiction as e:
        messages.announce(e.msg+'\n', messages.ASSERTION)
        return True
    return run(B, split_depth, split_breadth, solver_type)
Example #14
0
def run_modules(B, modules, depth, breadth):
    """
    Given a blackboard B, iteratively runs the modules in modules until either a contradiction is
    found or no new information is learned.
    Returns True if a contradiction is found, False otherwise.
    """
    try:
        split_modules(B, modules, depth, breadth)
        return False
    except terms.Contradiction as e:
        messages.announce(e.msg+'\n', messages.ASSERTION)
        return True
Example #15
0
 def add(self, *c):
     """
     Adds multiple comparisons to the Solver's blackboard.
     """
     for item in c:
         if isinstance(item, formulas.Forall):
             self.add_axiom(item)
         elif isinstance(item, (terms.Term, terms.STerm)):
             self.add_term(item)
         else:
             try:
                 self.B.add(item)
             except terms.Contradiction as e:
                 self.contradiction = True
                 messages.announce(e.msg, messages.ASSERTION)
Example #16
0
 def add(self, *c):
     """
     Adds multiple comparisons to the Solver's blackboard.
     """
     for item in c:
         if isinstance(item, formulas.Forall):
             self.add_axiom(item)
         elif isinstance(item, (terms.Term, terms.STerm)):
             self.add_term(item)
         else:
             try:
                 self.B.add(item)
             except terms.Contradiction as e:
                 self.contradiction = True
                 messages.announce(e.msg, messages.ASSERTION)
Example #17
0
def instantiate(axiom, used_envs, B):
    """
    Given an Axiom object, finds appropriate instantiations by unifying with B.
    Returns a list of clauses.
    """
    # Get a list of assignments that work for all of axiom's triggers.
    envs = unify(B, axiom.triggers, list(axiom.vars),
                 list(axiom.trig_arg_vars))
    messages.announce(' Environments:', messages.DEBUG)
    for e in envs:
        messages.announce('  ' + str(e), messages.DEBUG)

    # For each assignment, use it to instantiate a Clause from axiom and assert it in B.
    clauses = []
    astr = str(axiom)
    for env in [e for e in envs if (axiom, str(e)) not in used_envs]:
        literals = []
        for l in axiom.literals:
            comp = l.comp
            red = reduce_term(l.term1, env)[0].canonize()
            red_coeff, red_term = red.coeff, red.term
            try:
                lcoeff, lterm = find_problem_term(B, red_term)
                lcoeff *= red_coeff
            except NoTermException:
                lterm = B.term_name(red.term).index
                lcoeff = red.coeff

            red = reduce_term(l.term2.term, env)[0].canonize()
            red_coeff, red_term = red.coeff, red.term
            try:
                rcoeff, rterm = find_problem_term(B, red.term)
                rcoeff *= l.term2.coeff * red_coeff
            except NoTermException:
                #sred = red.canonize()
                rterm = B.term_name(red.term).index
                rcoeff = red.coeff * l.term2.coeff

            literals.append(terms.comp_eval[comp](lcoeff * terms.IVar(lterm),
                                                  rcoeff * terms.IVar(rterm)))
        clauses.append(literals)
        used_envs.add((axiom, str(env)))
    return clauses
Example #18
0
    def prove(self, claim):
        """
        Tries to establish the truth of TermComparison claim from what is already known.
        Returns true if claim follows from the current blackboard, false otherwise.
        Argument:
         -- claim: a TermComparison, ie 3*x > 2*y**2
        """
        if self.contradiction:
            return True

        a = terms.TermComparison(claim.term1, terms.comp_negate(claim.comp), claim.term2)
        try:
            B = run_util.copy_and_add(self.B, a)
        except terms.Contradiction as e:
            messages.announce(e.msg+'\n', messages.ASSERTION)
            self.contradiction = True
            return True
        else:
            return run_util.run_modules(B, self.modules, self.split_depth, self.split_breadth)
Example #19
0
def instantiate(axiom, used_envs, B):
    """
    Given an Axiom object, finds appropriate instantiations by unifying with B.
    Returns a list of clauses.
    """
    # Get a list of assignments that work for all of axiom's triggers.
    envs = unify(B, axiom.triggers, list(axiom.vars), list(axiom.trig_arg_vars))
    messages.announce(' Environments:', messages.DEBUG)
    for e in envs:
        messages.announce('  '+str(e), messages.DEBUG)

    # For each assignment, use it to instantiate a Clause from axiom and assert it in B.
    clauses = []
    astr = str(axiom)
    for env in [e for e in envs if (axiom, str(e)) not in used_envs]:
        literals = []
        for l in axiom.literals:
            comp = l.comp
            red = reduce_term(l.term1, env)[0].canonize()
            red_coeff, red_term = red.coeff, red.term
            try:
                lcoeff, lterm = find_problem_term(B, red_term)
                lcoeff *= red_coeff
            except NoTermException:
                lterm = B.term_name(red.term).index
                lcoeff = red.coeff

            red = reduce_term(l.term2.term, env)[0].canonize()
            red_coeff, red_term = red.coeff, red.term
            try:
                rcoeff, rterm = find_problem_term(B, red.term)
                rcoeff *= l.term2.coeff*red_coeff
            except NoTermException:
                #sred = red.canonize()
                rterm = B.term_name(red.term).index
                rcoeff = red.coeff * l.term2.coeff

            literals.append(
                terms.comp_eval[comp](lcoeff*terms.IVar(lterm), rcoeff*terms.IVar(rterm))
            )
        clauses.append(literals)
        used_envs.add((axiom, str(env)))
    return clauses
Example #20
0
    def prove(self, claim):
        """
        Tries to establish the truth of TermComparison claim from what is already known.
        Returns true if claim follows from the current blackboard, false otherwise.
        Argument:
         -- claim: a TermComparison, ie 3*x > 2*y**2
        """
        if self.contradiction:
            return True

        a = terms.TermComparison(claim.term1, terms.comp_negate(claim.comp),
                                 claim.term2)
        try:
            B = run_util.copy_and_add(self.B, a)
        except terms.Contradiction as e:
            messages.announce(e.msg + '\n', messages.ASSERTION)
            self.contradiction = True
            return True
        else:
            return run_util.run_modules(B, self.modules, self.split_depth,
                                        self.split_breadth)
Example #21
0
def saturate_modules2(B, modules):
    """Run the modules in succession on B until saturation.
    Delays the use of the "expensive" abs and exp modules.

    Arguments:
    -- B: a blackboard
    -- modules: a list of modules
    """
    mid = B.identify()
    cntr = 0
    amodules, bmodules = [], []
    for m in modules:
        if isinstance(m, (abs_module.AbsModule, exp_module.ExponentialModule)):
            bmodules.append(m)
        else:
            amodules.append(m)
    while len(B.get_new_info(mid)) > 0 and cntr < 3:
        for m in amodules:
            messages.announce(B.info_dump(), messages.DEBUG)
            m.update_blackboard(B)
    for m in bmodules:
        messages.announce(B.info_dump(), messages.DEBUG)
        m.update_blackboard(B)
    while len(B.get_new_info(mid)) > 0:
        for m in amodules + bmodules:
            messages.announce(B.info_dump(), messages.DEBUG)
            m.update_blackboard(B)
Example #22
0
def saturate_modules2(B, modules):
    """Run the modules in succession on B until saturation.
    Delays the use of the "expensive" abs and exp modules.

    Arguments:
    -- B: a blackboard
    -- modules: a list of modules
    """
    mid = B.identify()
    cntr = 0
    amodules, bmodules = [], []
    for m in modules:
        if isinstance(m, (abs_module.AbsModule, exp_module.ExponentialModule)):
            bmodules.append(m)
        else:
            amodules.append(m)
    while len(B.get_new_info(mid)) > 0 and cntr < 3:
        for m in amodules:
            messages.announce(B.info_dump(), messages.DEBUG)
            m.update_blackboard(B)
    for m in bmodules:
        messages.announce(B.info_dump(), messages.DEBUG)
        m.update_blackboard(B)
    while len(B.get_new_info(mid)) > 0:
        for m in amodules + bmodules:
            messages.announce(B.info_dump(), messages.DEBUG)
            m.update_blackboard(B)
Example #23
0
    def __init__(self, split_depth, split_breadth, assertions, terms, axioms,
                 modules, default_solver):
        """
        Instantiates a Solver object.
        Arguments:
         -- split_depth: How many successive (cumulative) case splits to try.
         -- split_breadth: How many split options to consider.
         -- assertions: a list of TermComparisons to assert to the new Solver. Defaults to empty.
         -- axioms: a list of Axioms to assert to the Solver's axiom module. Defaults to empty.
         -- modules: a list of modules for the solver to use. Defaults to all available modules.
         -- default_solver: 'fm' or 'poly' arithmetic.
        """
        if not isinstance(assertions, list) or not isinstance(axioms, list):
            messages.announce(
                'Error: assertions and axioms must be passed as lists.',
                messages.INFO)
            messages.announce(
                'Usage: Solver([assertions=list()[, axioms=list()[, poly=True]]])',
                messages.INFO)
            raise Exception

        self.B = blackboard.Blackboard()
        self.fm = None
        if len(modules) == 0:
            self.fm = axiom_module.AxiomModule(axioms)
            modules = [
                cc_module.CongClosureModule(),
                exp_module.ExponentialModule(self.fm)
            ]
            modules.extend([
                abs_module.AbsModule(self.fm),
                min_module.MinimumModule(),
                nth_root_module.NthRootModule(self.fm),
                builtins_module.BuiltinsModule(self.fm), self.fm
            ])
            if default_solver == 'poly':
                pa = poly_add_module.PolyAdditionModule()
                pm = poly_mult_module.PolyMultiplicationModule()
            elif default_solver == 'fm':
                pa = fm_add_module.FMAdditionModule()
                pm = fm_mult_module.FMMultiplicationModule()
            else:
                messages.announce(
                    'Unsupported option: {0}'.format(default_solver),
                    messages.INFO)
                raise Exception

            modules.extend([pa, pm])
        else:
            self.fm = next(
                (m
                 for m in modules if isinstance(m, axiom_module.AxiomModule)),
                None)
            self.fm.add_axioms(axioms)

        self.contradiction = False
        self.assume(*assertions)
        self.assume(*terms)
        self.modules = modules
        self.split_depth, self.split_breadth = split_depth, split_breadth
Example #24
0
    def update_blackboard(self, B):
        """
        Instantiates all stored axioms with respect to B and asserts new clauses.
        """
        timer.start(timer.FUN)
        messages.announce_module('axiom module')
        n = B.num_terms + len(B.equalities.keys()) + len(B.zero_equalities)
        #if n == self.num_eqs:
        #    messages.announce("No new information for the axiom module to use.", messages.DEBUG)
        #    timer.stop(timer.FUN)
        #    return
        self.num_eqs = n

        for a in self.axioms:
            messages.announce("Instantiating axiom: {}".format(a), messages.DEBUG)
            if a.unifiable:
                clauses = instantiate(a, self.used_envs, B)
                for c in clauses:
                    B.assert_clause(*c)
            else:
                clauses = instantiate_triggerless(a, self.used_envs, B)
                for c in clauses:
                    B.assert_clause(*c)
        timer.stop(timer.FUN)
Example #25
0
def set_solver_type(s):
    """
    Sets the solver to a given method, s, in solver_options.
    """
    if s in solver_options:
        messages.announce('Setting solver type: {0!s}'.format(s), messages.INFO)
        global default_solver
        default_solver = s
    else:
        messages.announce('Error:{0!s} is not in the list of possible arithmetic solvers'.format(s),
                          messages.INFO)
        messages.announce('solver options = {0!s}'.format(solver_options), messages.INFO)
Example #26
0
    def __init__(self, split_depth, split_breadth, assertions, terms, axioms, modules,
                 default_solver):
        """
        Instantiates a Solver object.
        Arguments:
         -- split_depth: How many successive (cumulative) case splits to try.
         -- split_breadth: How many split options to consider.
         -- assertions: a list of TermComparisons to assert to the new Solver. Defaults to empty.
         -- axioms: a list of Axioms to assert to the Solver's axiom module. Defaults to empty.
         -- modules: a list of modules for the solver to use. Defaults to all available modules.
         -- default_solver: 'fm' or 'poly' arithmetic.
        """
        if not isinstance(assertions, list) or not isinstance(axioms, list):
            messages.announce(
                'Error: assertions and axioms must be passed as lists.',
                messages.INFO)
            messages.announce(
                'Usage: Solver([assertions=list()[, axioms=list()[, poly=True]]])',
                messages.INFO)
            raise Exception

        self.B = blackboard.Blackboard()
        self.fm = None
        if len(modules) == 0:
            self.fm = axiom_module.AxiomModule(axioms)
            modules = [cc_module.CongClosureModule(), exp_module.ExponentialModule(self.fm)]
            modules.extend([abs_module.AbsModule(self.fm), min_module.MinimumModule(),
                            nth_root_module.NthRootModule(self.fm),
                            builtins_module.BuiltinsModule(self.fm), self.fm])
            if default_solver == 'poly':
                pa = poly_add_module.PolyAdditionModule()
                pm = poly_mult_module.PolyMultiplicationModule()
            elif default_solver == 'fm':
                pa = fm_add_module.FMAdditionModule()
                pm = fm_mult_module.FMMultiplicationModule()
            else:
                messages.announce(
                    'Unsupported option: {0}'.format(default_solver),
                    messages.INFO)
                raise Exception

            modules.extend([pa, pm])
        else:
            self.fm = next((m for m in modules if isinstance(m, axiom_module.AxiomModule)), None)
            self.fm.add_axioms(axioms)

        self.contradiction = False
        self.assume(*assertions)
        self.assume(*terms)
        self.modules = modules
        self.split_depth, self.split_breadth = split_depth, split_breadth
Example #27
0
def set_solver_type(s):
    """
    Sets the solver to a given method, s, in solver_options.
    """
    if s in solver_options:
        messages.announce('Setting solver type: {0!s}'.format(s),
                          messages.INFO)
        global default_solver
        default_solver = s
    else:
        messages.announce(
            'Error:{0!s} is not in the list of possible arithmetic solvers'.
            format(s), messages.INFO)
        messages.announce('solver options = {0!s}'.format(solver_options),
                          messages.INFO)
Example #28
0
def find_problem_term(B, term1):
    """
    term is a Term such that all variable occurrences are IVars.
    returns (c, i) such that term = c*ti, or raises NoTermException.

    if term1 is a FuncTerm, recursively find problem terms matching each of the arguments, then
    search for a problem term with the same function name whose arguments are equal to the arguments
    of term1.

    if term1 is an additive or multiplicative term, recursively finds problem terms matching each
    of the arguments, and performs FM elimination on equalities to see if their sum/product is equal
    to a problem term.
    """
    messages.announce('    finding problem term:' + str(term1), messages.DEBUG)
    sterm = term1.canonize()
    term, coeff = sterm.term, sterm.coeff
    if isinstance(term, terms.IVar):
        return coeff, term.index

    b, ind = B.has_name(term)
    if b:
        return coeff, ind

    if isinstance(term, terms.FuncTerm):
        nargs = [find_problem_term(B, p.term) for p in term.args]
        for i in range(len(nargs)):
            nargs[i] = (term.args[i].coeff * nargs[i][0], nargs[i][1])

        for i in range(B.num_terms):
            t = B.term_defs[i]
            if (isinstance(t, terms.FuncTerm) and t.func_name == term.func_name
                    and len(t.args) == len(nargs)):
                match = True
                for k in range(len(t.args)):
                    targ, uarg = (t.args[k].coeff,
                                  t.args[k].term.index), nargs[k]
                    p = tuple(sorted((targ[1], uarg[1])))
                    if targ == uarg:
                        continue
                    elif targ[1] == uarg[1]:
                        if targ[1] in B.zero_equalities:
                            continue
                    elif p in B.equalities:
                        c = B.equalities[p]
                        if targ[1] < uarg[1]:
                            c = fractions.Fraction(1, c)
                        if uarg[0] * c == targ[0]:
                            continue
                    match = False
                    break

                if match:
                    return coeff, i
        raise NoTermException

    elif isinstance(term, terms.AddTerm):
        return add_gauss_eq_elim(coeff, term, B)

    elif isinstance(term, terms.MulTerm):
        return mul_gauss_eq_elim(coeff, term, B)

    raise NoTermException
Example #29
0
def find_problem_term(B, term1):
    """
    term is a Term such that all variable occurrences are IVars.
    returns (c, i) such that term = c*ti, or raises NoTermException.

    if term1 is a FuncTerm, recursively find problem terms matching each of the arguments, then
    search for a problem term with the same function name whose arguments are equal to the arguments
    of term1.

    if term1 is an additive or multiplicative term, recursively finds problem terms matching each
    of the arguments, and performs FM elimination on equalities to see if their sum/product is equal
    to a problem term.
    """
    messages.announce('    finding problem term:' + str(term1), messages.DEBUG)
    sterm = term1.canonize()
    term, coeff = sterm.term, sterm.coeff
    if isinstance(term, terms.IVar):
        return coeff, term.index

    b, ind = B.has_name(term)
    if b:
        return coeff, ind

    if isinstance(term, terms.FuncTerm):
        nargs = [find_problem_term(B, p.term) for p in term.args]
        for i in range(len(nargs)):
            nargs[i] = (term.args[i].coeff*nargs[i][0], nargs[i][1])

        for i in range(B.num_terms):
            t = B.term_defs[i]
            if (isinstance(t, terms.FuncTerm) and t.func_name == term.func_name
               and len(t.args) == len(nargs)):
                match = True
                for k in range(len(t.args)):
                    targ, uarg = (t.args[k].coeff, t.args[k].term.index), nargs[k]
                    p = tuple(sorted((targ[1], uarg[1])))
                    if targ == uarg:
                        continue
                    elif targ[1] == uarg[1]:
                        if targ[1] in B.zero_equalities:
                            continue
                    elif p in B.equalities:
                        c = B.equalities[p]
                        if targ[1] < uarg[1]:
                            c = fractions.Fraction(1, c)
                        if uarg[0]*c == targ[0]:
                            continue
                    match = False
                    break

                if match:
                    return coeff, i
        raise NoTermException

    elif isinstance(term, terms.AddTerm):
        return add_gauss_eq_elim(coeff, term, B)

    elif isinstance(term, terms.MulTerm):
        return mul_gauss_eq_elim(coeff, term, B)

    raise NoTermException
Example #30
0
def unify(B, termlist, uvars, arg_uvars, envs=list()):
    """
    Takes Terms s1...sn involving uvars u1...um
    arg_uvars is a subset of uvars: those that occur alone as function arguments in s1...sn.
    Optional envs is a list of maps from UVar indices to (const, IVar index) pairs.
    Returns a list of assignments under which each si is equal to a problem term in B.
    """

    def occurs_as_arg(term, varkey):
        """
        Returns true if term is a FuncTerm and var occurs alone as an argument.
        """
        if not isinstance(term, terms.FuncTerm):
            return False
        return any(a.term.key == varkey for a in term.args)

    messages.announce(' Unifying :' + str(termlist) + str(arg_uvars) + str(envs),
                      messages.DEBUG)

    if len(uvars) == 0:
        return envs

    if len(arg_uvars) == 0:
        #todo: we should find a way to handle the case where no variables occur alone in func terms.

        return envs
        # The code below is a tentative generalization.
        n_envs = []
        for e in envs:
            #print e
            for pr in itertools.product(range(B.num_terms), repeat=len(uvars)):
                e2 = copy.copy(e)
                for uv in range(len(uvars)):
                    e2[uvars[uv]] = (1, pr[uv])
                n_envs.append(e2)
        #print 'n_nens:', n_envs
        return n_envs

    v = arg_uvars[0]
    vkey = terms.UVar(v).key
    try:
        t = next(term for term in termlist if occurs_as_arg(term, vkey))
    except StopIteration:
        raise Exception('arg_uvars not set up right.'+str(termlist)+str(uvars)+str(arg_uvars))
    ind = next(j for j in range(len(t.args)) if t.args[j].term.key == vkey)
    c = t.args[ind].coeff

    # we have: t = f(..., c*u_v, ...)
    prob_f_terms = [i for i in range(B.num_terms) if
                    (isinstance(B.term_defs[i], terms.FuncTerm)
                     and B.term_defs[i].func_name == t.func_name
                     and len(B.term_defs[i].args) == len(t.args))]

    messages.announce('   probfterms:' + str(prob_f_terms), messages.DEBUG)

    s = [(fractions.Fraction(B.term_defs[i].args[ind].coeff, c),
          B.term_defs[i].args[ind].term.index) for i in prob_f_terms]
    # s is a list of pairs (coeff, j) such that c*coeff*tj occurs as an argument to f in a pr. term

    nenvs = []
    for (coeff, j) in s:
        #new_terms = [p.substitute({vkey: coeff*terms.IVar(j)}) for p in termlist]
        new_terms = [substitute(p, v, coeff, j) for p in termlist]
        closed_terms, open_terms = list(), list()

        for (a, b) in new_terms:
            if b:
                closed_terms.append(a)
            else:
                open_terms.append(a)

        try:
            messages.announce('   closed terms:' + str(closed_terms), messages.DEBUG)
            prob_terms = [find_problem_term(B, ct.term) for ct in closed_terms]
        except NoTermException:

            continue

        # TODO: prob_terms isn't actually used in what follows. Could it be?

        # At this point, every closed term matches something in the problem.
        cenvs = copy.deepcopy(envs) if envs else [{}]
        for c in cenvs:
            c[v] = (coeff, j)
            maps = unify(B, [o.term for o in open_terms],
                         [v0 for v0 in uvars if v0 != v], arg_uvars[1:], cenvs)
            nenvs.extend(maps)

    return nenvs
Example #31
0
    def update_blackboard(self, B):
        """
        Saturates a Blackboard B with multiplicative inferences.
        """
        timer.start(timer.PMUL)
        messages.announce_module('polyhedron multiplicative module')
        mul_util.derive_info_from_definitions(B)

        mul_util.preprocess_cancellations(B)

        m_comparisons = mul_util.get_multiplicative_information(B)
        # Each ti in m_comparisons really represents |t_i|.

        p = add_of_mul_comps(m_comparisons, B.num_terms)
        a_comparisons, prime_of_index, num_terms = p
        a_comparisons = [terms.comp_eval[c[1]](c[0], 0) for c in a_comparisons]

        h_matrix = lrs_util.create_h_format_matrix(a_comparisons, num_terms)
        messages.announce('Halfplane matrix:', messages.DEBUG)
        messages.announce(h_matrix, messages.DEBUG)
        v_matrix, v_lin_set = lrs_util.get_vertices(h_matrix)
        messages.announce('Vertex matrix:', messages.DEBUG)
        for l in v_matrix:
            messages.announce(str(l), messages.DEBUG)
        messages.announce('Linear set:', messages.DEBUG)
        messages.announce(str(v_lin_set), messages.DEBUG)

        new_comparisons = get_mul_comparisons(v_matrix, v_lin_set, B.num_terms,
                                              prime_of_index)

        for m1, m2, coeff, comp in new_comparisons:
            c = mul_util.process_mul_comp(m1, m2, coeff, comp, B)
            if c is not None:
                B.assert_comparison(c)
        timer.stop(timer.PMUL)
Example #32
0
 def add_clause(self, c):
     try:
         self.B.assert_clause(*c)
     except terms.Contradiction as e:
         self.contradiction = True
         messages.announce(e.msg, messages.ASSERTION)
Example #33
0
def split_modules(B, modules, depth, breadth, saturate=True):
    """
    B is a blackboard.
    modules is a list of modules.
    depth restricts how many subsequent splits will be performed: ie, if depth=2, will assume x>0
     and y>0, but won't assume z>0 on top of that.
    breadth restricts how many splits will be considered at each depth. ie, if depth=1, breadth=3,
     will try the three most promising splits separately. If depth=2, breadth=3, will try the three
     most promising splits determined after each of the three most promising preliminary splits.
    """
    if saturate:
        saturate_modules(B, modules)
    if depth <= 0:
        return B
    else:
        backup_bbds = {}
        backup_modules = {}
        if breadth <= 0:
            candidates = get_splits(B, modules)
        else:
            candidates = get_splits(B, modules)[:breadth]
        for i in range(len(candidates)):
            can = candidates[i]
            ti, tj = terms.IVar(can[0]), can[3] * terms.IVar(can[1])
            comp = can[2]

            backup_bbds[i, comp] = copy.deepcopy(B)
            backup_modules[i, comp] = copy.deepcopy(modules)
            gtsplit = False
            try:
                newcomp = terms.comp_eval[comp](ti, tj)
                messages.announce(
                    "Case split: assuming {0} at depth {1}".format(
                        newcomp, depth), messages.ASSERTION)
                backup_bbds[i, comp].assert_comparison(newcomp)
                gtsplit = run_modules(backup_bbds[i, comp],
                                      backup_modules[i, comp], 0, 0)
            except terms.Contradiction:
                gtsplit = True

            if gtsplit:
                #print 'DETERMINED {0} <= {1}'.format(ti, tj)
                messages.announce(
                    "Split led to contradiction at depth {0}. Learned:".format(
                        depth), messages.ASSERTION)
                B.assert_comparison(terms.comp_eval[terms.comp_negate(comp)](
                    ti, tj))
                return split_modules(B, modules, depth, breadth)

        # at this point, none of the depth-1 splits have returned any useful information.
        for (i, c) in backup_bbds.keys():
            messages.announce(
                "Working under depth {4} assumption: t{0} {1} {2} t{3}".format(
                    candidates[i][0], terms.comp_str[candidates[i][2]],
                    candidates[i][3], candidates[i][1], depth),
                messages.ASSERTION)
            try:
                split_modules(backup_bbds[i, c],
                              backup_modules[i, c],
                              depth - 1,
                              breadth,
                              saturate=False)
            except terms.Contradiction:
                messages.announce(
                    "Split led to contradiction at depth {0}. Learned:".format(
                        depth), messages.ASSERTION)

                can = candidates[i]
                ti, tj = terms.IVar(can[0]), can[3] * terms.IVar(can[1])
                comp = can[2]
                B.assert_comparison(terms.comp_eval[terms.comp_negate(comp)](
                    ti, tj))
                return split_modules(B, modules, depth, breadth)

            messages.announce(
                "Ending depth {4} assumption: t{0} {1} {2} t{3}".format(
                    candidates[i][0], terms.comp_str[candidates[i][2]],
                    candidates[i][3], candidates[i][1], depth),
                messages.ASSERTION)
Example #34
0
 def add_clause(self, c):
     try:
         self.B.assert_clause(*c)
     except terms.Contradiction as e:
         self.contradiction = True
         messages.announce(e.msg, messages.ASSERTION)
Example #35
0
def show_configuration():
    """
    Prints information about the present components at verbosity level INFO.
    """
    messages.announce('', messages.INFO)
    messages.announce('Welcome to the Polya inequality prover.', messages.INFO)
    messages.announce('Looking for components...', messages.INFO)
    if lrs.lrs_path is None:
        messages.announce('lrs not found.', messages.INFO)
    else:
        messages.announce('lrs found (path: {0!s}).'.format(lrs.lrs_path), messages.INFO)
    if lrs.redund_path is None:
        messages.announce('redund not found.', messages.INFO)
    else:
        messages.announce('redund found (path: {0!s}).'.format(lrs.redund_path), messages.INFO)
    if have_cdd:
        messages.announce('cdd found.', messages.INFO)
    else:
        messages.announce('cdd not found.', messages.INFO)
    messages.announce('', messages.INFO)
Example #36
0
def unify(B, termlist, uvars, arg_uvars, envs=list()):
    """
    Takes Terms s1...sn involving uvars u1...um
    arg_uvars is a subset of uvars: those that occur alone as function arguments in s1...sn.
    Optional envs is a list of maps from UVar indices to (const, IVar index) pairs.
    Returns a list of assignments under which each si is equal to a problem term in B.
    """
    def occurs_as_arg(term, varkey):
        """
        Returns true if term is a FuncTerm and var occurs alone as an argument.
        """
        if not isinstance(term, terms.FuncTerm):
            return False
        return any(a.term.key == varkey for a in term.args)

    messages.announce(
        ' Unifying :' + str(termlist) + str(arg_uvars) + str(envs),
        messages.DEBUG)

    if len(uvars) == 0:
        return envs

    if len(arg_uvars) == 0:
        #todo: we should find a way to handle the case where no variables occur alone in func terms.

        return envs
        # The code below is a tentative generalization.
        n_envs = []
        for e in envs:
            #print e
            for pr in itertools.product(range(B.num_terms), repeat=len(uvars)):
                e2 = copy.copy(e)
                for uv in range(len(uvars)):
                    e2[uvars[uv]] = (1, pr[uv])
                n_envs.append(e2)
        #print 'n_nens:', n_envs
        return n_envs

    v = arg_uvars[0]
    vkey = terms.UVar(v).key
    try:
        t = next(term for term in termlist if occurs_as_arg(term, vkey))
    except StopIteration:
        raise Exception('arg_uvars not set up right.' + str(termlist) +
                        str(uvars) + str(arg_uvars))
    ind = next(j for j in range(len(t.args)) if t.args[j].term.key == vkey)
    c = t.args[ind].coeff

    # we have: t = f(..., c*u_v, ...)
    prob_f_terms = [
        i for i in range(B.num_terms)
        if (isinstance(B.term_defs[i], terms.FuncTerm)
            and B.term_defs[i].func_name == t.func_name
            and len(B.term_defs[i].args) == len(t.args))
    ]

    messages.announce('   probfterms:' + str(prob_f_terms), messages.DEBUG)

    s = [(fractions.Fraction(B.term_defs[i].args[ind].coeff,
                             c), B.term_defs[i].args[ind].term.index)
         for i in prob_f_terms]
    # s is a list of pairs (coeff, j) such that c*coeff*tj occurs as an argument to f in a pr. term

    nenvs = []
    for (coeff, j) in s:
        #new_terms = [p.substitute({vkey: coeff*terms.IVar(j)}) for p in termlist]
        new_terms = [substitute(p, v, coeff, j) for p in termlist]
        closed_terms, open_terms = list(), list()

        for (a, b) in new_terms:
            if b:
                closed_terms.append(a)
            else:
                open_terms.append(a)

        try:
            messages.announce('   closed terms:' + str(closed_terms),
                              messages.DEBUG)
            prob_terms = [find_problem_term(B, ct.term) for ct in closed_terms]
        except NoTermException:

            continue

        # TODO: prob_terms isn't actually used in what follows. Could it be?

        # At this point, every closed term matches something in the problem.
        cenvs = copy.deepcopy(envs) if envs else [{}]
        for c in cenvs:
            c[v] = (coeff, j)
            maps = unify(B, [o.term for o in open_terms],
                         [v0 for v0 in uvars if v0 != v], arg_uvars[1:], cenvs)
            nenvs.extend(maps)

    return nenvs
Example #37
0
def stop(module):
    t = e_stop(module)
    messages.announce("Module run time: " + str(round(t, 3)), messages.DEBUG)
Example #38
0
def split_modules(B, modules, depth, breadth, saturate=True):
    """
    B is a blackboard.
    modules is a list of modules.
    depth restricts how many subsequent splits will be performed: ie, if depth=2, will assume x>0
     and y>0, but won't assume z>0 on top of that.
    breadth restricts how many splits will be considered at each depth. ie, if depth=1, breadth=3,
     will try the three most promising splits separately. If depth=2, breadth=3, will try the three
     most promising splits determined after each of the three most promising preliminary splits.
    """
    if saturate:
        saturate_modules(B, modules)
    if depth <= 0:
        return B
    else:
        backup_bbds = {}
        backup_modules = {}
        if breadth <= 0:
            candidates = get_splits(B, modules)
        else:
            candidates = get_splits(B, modules)[:breadth]
        for i in range(len(candidates)):
            can = candidates[i]
            ti, tj = terms.IVar(can[0]), can[3]*terms.IVar(can[1])
            comp = can[2]

            backup_bbds[i, comp] = copy.deepcopy(B)
            backup_modules[i, comp] = copy.deepcopy(modules)
            gtsplit = False
            try:
                newcomp = terms.comp_eval[comp](ti, tj)
                messages.announce("Case split: assuming {0} at depth {1}".format(newcomp, depth),
                                  messages.ASSERTION)
                backup_bbds[i, comp].assert_comparison(newcomp)
                gtsplit = run_modules(backup_bbds[i, comp], backup_modules[i, comp], 0, 0)
            except terms.Contradiction:
                gtsplit = True

            if gtsplit:
                #print 'DETERMINED {0} <= {1}'.format(ti, tj)
                messages.announce("Split led to contradiction at depth {0}. Learned:".format(depth),
                                  messages.ASSERTION)
                B.assert_comparison(terms.comp_eval[terms.comp_negate(comp)](ti, tj))
                return split_modules(B, modules, depth, breadth)

        # at this point, none of the depth-1 splits have returned any useful information.
        for (i, c) in backup_bbds.keys():
            messages.announce("Working under depth {4} assumption: t{0} {1} {2} t{3}".format(
                candidates[i][0], terms.comp_str[candidates[i][2]],
                candidates[i][3], candidates[i][1], depth), messages.ASSERTION)
            try:
                split_modules(backup_bbds[i, c], backup_modules[i, c], depth-1, breadth, saturate=False)
            except terms.Contradiction:
                messages.announce("Split led to contradiction at depth {0}. Learned:".format(depth),
                                  messages.ASSERTION)

                can = candidates[i]
                ti, tj = terms.IVar(can[0]), can[3]*terms.IVar(can[1])
                comp = can[2]
                B.assert_comparison(terms.comp_eval[terms.comp_negate(comp)](ti, tj))
                return split_modules(B, modules, depth, breadth)

            messages.announce("Ending depth {4} assumption: t{0} {1} {2} t{3}".format(
                candidates[i][0], terms.comp_str[candidates[i][2]],
                candidates[i][3], candidates[i][1], depth), messages.ASSERTION)
Example #39
0
    def update_blackboard(self, B):
        """
        Saturates a Blackboard B with additive inferences.
        """
        timer.start(timer.PADD)
        messages.announce_module('polyhedron additive module')

    #    learn_additive_sign_info(blackboard)

        comparisons = get_additive_information(B)

        h_matrix = lrs_util.create_h_format_matrix(comparisons, B.num_terms)
        messages.announce('Halfplane matrix:', messages.DEBUG)
        messages.announce(h_matrix, messages.DEBUG)
        v_matrix, v_lin_set = lrs_util.get_vertices(h_matrix)
        messages.announce('Vertex matrix:', messages.DEBUG)
        #messages.announce(str(v_matrix), messages.DEBUG)
        for l in v_matrix:
            messages.announce(str(l), messages.DEBUG)
        messages.announce('Linear set:', messages.DEBUG)
        messages.announce(str(v_lin_set), messages.DEBUG)

        new_comparisons = get_2d_comparisons(v_matrix, v_lin_set)

        for c in new_comparisons:
            B.assert_comparison(c)

        timer.stop(timer.PADD)
Example #40
0
def get_2d_comparisons(vertices, lin_set):
    """
    Takes a matrix of vertices. Each row is of the form
     [0, delta, c_0, ..., c_n]

    lin_set tracks the linear set for lrs.
    Returns all possible TermComparisons from the given vertices.
    """

    def adjust_strength(strong, comp):
        if strong:
            if comp == terms.GE:
                return terms.GT
            elif comp == terms.LE:
                return terms.LT
        else:
            if comp == terms.GT:
                return terms.GE
            elif comp == terms.LT:
                return terms.LE
        return comp

    if all(v[1] == 0 for v in vertices):  # We have a degenerate system.
        return [terms.IVar(0) == 0]

    learned_comparisons = []

    # Look for comparisons between t_i and t_j by checking each vertex.
    for (i, j) in itertools.combinations(range(len(vertices[0])-2), 2):
        #messages.announce(
            #'Looking for comparisons between {0} and {1}'.format(i, j), messages.DEBUG)

        i_j_vertices = set()
        weak = False
        for v in vertices:
            if v[i+2] != 0 or v[j+2] != 0:
                i_j_vertices.add((v[i+2], v[j+2], v[1]))
            elif v[1] != 0:
                #(c,0,0) is a vertex, so (c-epsilon,0,0) is reachable.
                weak = True

        for k in lin_set:
            v = vertices[k]
            if v[i+2] != 0 or v[j+2] != 0:
                i_j_vertices.add((-v[i+2], -v[j+2], v[1]))

        if (i, j) == (2, 4): messages.announce('vertices:'+str(i_j_vertices), messages.DEBUG)

        if len(i_j_vertices) == 0:
            learned_comparisons.extend([terms.IVar(i) == 0, terms.IVar(j) == 0])
            continue

        # Find the extremal vertices.
        try:
            bound1, bound2 = get_boundary_vertices(i_j_vertices)
            #messages.announce('boundary vertices:'+str(bound1)+', '+str(bound2), messages.DEBUG)
        except VertexSetException:  # Nothing we can learn for this i, j pair.
            continue

        # Now, all vertices lie in the same halfplane between bound1 and bound2.
        strong1, strong2 = (not weak) and (bound1[2] == 0), (not weak) and (bound2[2] == 0)
        l_b1, l_b2 = geo.line_of_point(bound1), geo.line_of_point(bound2)

        if l_b1 == l_b2:
            if bound1[0]*bound2[0] >= 0 and bound1[1]*bound2[1] >= 0:
                # the rays are collinear. Learn equality.
                learned_comparisons.append(bound1[1] * terms.IVar(i) == bound1[0] * terms.IVar(j))
                if strong1 or strong2:
                    learned_comparisons.append(
                        bound1[1] * terms.IVar(i) < bound1[0] * terms.IVar(j)
                    )

            else:
                #the rays are opposite. Figure out the comparison direction another way.
                try:
                    pt = next(v for v in i_j_vertices if not l_b1.get_direction(v) == terms.EQ)
                    dir1 = adjust_strength(strong1 and strong2, l_b1.get_direction(pt))
                    learned_comparisons.append(
                        terms.comp_eval[dir1](bound1[1] * terms.IVar(i), bound1[0] * terms.IVar(j))
                    )
                except StopIteration:
                    # There is no direction information to be found: all vertices are collinear.
                    #continue
                    learned_comparisons.append(bound1[1]*terms.IVar(i) == bound1[0]*terms.IVar(j))
                #print '*** l_b1 = ', l_b1, pt, terms.comp_str[l_b1.get_direction(pt)]

        else:
            # Otherwise, the points do not lie on the same line through the origin.
            dir1 = adjust_strength(strong1, l_b1.get_direction(bound2))
            dir2 = adjust_strength(strong2, l_b2.get_direction(bound1))
            learned_comparisons.append(
                terms.comp_eval[dir1](bound1[1] * terms.IVar(i), bound1[0] * terms.IVar(j))
            )
            learned_comparisons.append(
                terms.comp_eval[dir2](bound2[1] * terms.IVar(i), bound2[0] * terms.IVar(j))
            )
        #messages.announce('Learned:'+str(learned_comparisons), messages.DEBUG)
    return learned_comparisons
Example #41
0
    def update_blackboard(self, B):
        """
        Saturates a Blackboard B with additive inferences.
        """
        timer.start(timer.PADD)
        messages.announce_module('polyhedron additive module')

    #    learn_additive_sign_info(blackboard)

        comparisons = get_additive_information(B)

        h_matrix = lrs_util.create_h_format_matrix(comparisons, B.num_terms)
        messages.announce('Halfplane matrix:', messages.DEBUG)
        messages.announce(h_matrix, messages.DEBUG)
        v_matrix, v_lin_set = lrs_util.get_vertices(h_matrix)
        messages.announce('Vertex matrix:', messages.DEBUG)
        #messages.announce(str(v_matrix), messages.DEBUG)
        for l in v_matrix:
            messages.announce(str(l), messages.DEBUG)
        messages.announce('Linear set:', messages.DEBUG)
        messages.announce(str(v_lin_set), messages.DEBUG)

        new_comparisons = get_2d_comparisons(v_matrix, v_lin_set)

        for c in new_comparisons:
            B.assert_comparison(c)

        timer.stop(timer.PADD)
Example #42
0
    def update_blackboard(self, B):
        """
        Saturates a Blackboard B with multiplicative inferences.
        """
        timer.start(timer.PMUL)
        messages.announce_module('polyhedron multiplicative module')
        mul_util.derive_info_from_definitions(B)

        mul_util.preprocess_cancellations(B)

        m_comparisons = mul_util.get_multiplicative_information(B)
        # Each ti in m_comparisons really represents |t_i|.

        p = add_of_mul_comps(m_comparisons, B.num_terms)
        a_comparisons, prime_of_index, num_terms = p
        a_comparisons = [terms.comp_eval[c[1]](c[0], 0) for c in a_comparisons]

        h_matrix = lrs_util.create_h_format_matrix(a_comparisons, num_terms)
        messages.announce('Halfplane matrix:', messages.DEBUG)
        messages.announce(h_matrix, messages.DEBUG)
        v_matrix, v_lin_set = lrs_util.get_vertices(h_matrix)
        messages.announce('Vertex matrix:', messages.DEBUG)
        for l in v_matrix:
            messages.announce(str(l), messages.DEBUG)
        messages.announce('Linear set:', messages.DEBUG)
        messages.announce(str(v_lin_set), messages.DEBUG)

        new_comparisons = get_mul_comparisons(v_matrix, v_lin_set,
                                              B.num_terms, prime_of_index)


        for m1, m2, coeff, comp in new_comparisons:
            c = mul_util.process_mul_comp(m1, m2, coeff, comp, B)
            if c is not None:
                B.assert_comparison(c)
        timer.stop(timer.PMUL)
Example #43
0
def show_configuration():
    """
    Prints information about the present components at verbosity level INFO.
    """
    messages.announce('', messages.INFO)
    messages.announce('Welcome to the Polya inequality prover.', messages.INFO)
    messages.announce('Looking for components...', messages.INFO)
    if lrs.lrs_path is None:
        messages.announce('lrs not found.', messages.INFO)
    else:
        messages.announce('lrs found (path: {0!s}).'.format(lrs.lrs_path),
                          messages.INFO)
    if lrs.redund_path is None:
        messages.announce('redund not found.', messages.INFO)
    else:
        messages.announce(
            'redund found (path: {0!s}).'.format(lrs.redund_path),
            messages.INFO)
    if have_cdd:
        messages.announce('cdd found.', messages.INFO)
    else:
        messages.announce('cdd not found.', messages.INFO)
    messages.announce('', messages.INFO)