Esempio n. 1
0
    def test_axiom_to_pcnf(self):
        a = Symbol.Predicate('A', ['x'])
        b = Symbol.Predicate('B', ['y'])
        c = Symbol.Predicate('C', ['z'])

        # Simple test of disjunction over conjunction
        axi_one = Axiom.Axiom(Quantifier.Universal(['x', 'y', 'z'], a | b & c))
        axi_one = axi_one.to_pcnf()
        self.assertEqual('∀(z,y,x)[((A(z) | B(y)) & (A(z) | C(x)))]',
                         repr(axi_one))

        # Simple sanity check, it's already FF-PCNF
        axi_two = Axiom.Axiom(
            Quantifier.Universal(['x', 'y', 'z'], (a | b) & c))
        axi_two = axi_two.to_pcnf()
        self.assertEqual('∀(z,y,x)[(C(x) & (A(z) | B(y)))]', repr(axi_two))

        # Sanity check we remove functions
        c = Symbol.Predicate('C', ['z', Symbol.Function('F', ['z'])])
        axi_three = Axiom.Axiom(
            Quantifier.Universal(['x', 'y', 'z'], a | b & c))
        axi_three = axi_three.to_pcnf()
        self.assertEqual(
            '∀(z,y,x,w)[((A(z) | C(x,w)) & (A(z) | F(x,w)) & (A(z) | B(y)))]',
            repr(axi_three))
Esempio n. 2
0
    def test_axiom_connecive_rescoping(self):

        a = Symbol.Predicate('A', ['x'])
        b = Symbol.Predicate('B', ['y'])

        universal = Quantifier.Universal(['x'], a)
        existential = Quantifier.Existential(['y'], b)

        conjunction = universal & existential
        disjunction = universal | existential

        # Ensure we handle single quantifier case
        self.assertEqual(repr((universal & b).rescope()),
                         '∀(x)[(A(x) & B(y))]')
        self.assertEqual(repr((existential & a).rescope()),
                         '∃(y)[(B(y) & A(x))]')
        self.assertEqual(repr((universal | b).rescope()),
                         '∀(x)[(A(x) | B(y))]')
        self.assertEqual(repr((existential | a).rescope()),
                         '∃(y)[(B(y) | A(x))]')

        # Ensure we catch error condition where lookahead is needed
        self.assertRaises(ValueError, (existential | universal).rescope)

        # Ensure that we can promote Universals when a conjunction lives above us
        top = a & disjunction
        self.assertEqual(repr(disjunction.rescope(top)),
                         '∀(x)[∃(y)[(A(x) | B(y))]]')

        # Ensure that we can promote Existentials when a conjunction lives above us
        top = a | conjunction
        self.assertEqual(repr(conjunction.rescope(top)),
                         '∃(y)[∀(x)[(B(y) & A(x))]]')
Esempio n. 3
0
    def test_cnf_negation(self):
        '''
        Ensure we can get into conjunctive normal form
        '''

        alpha = Symbol.Predicate('A', ['x'])
        beta = Symbol.Predicate('B', ['y'])
        delta = Symbol.Predicate('D', ['z'])

        s = ~(Quantifier.Universal(['x', 'y', 'z'], (~(alpha | beta) & delta)))
        self.assertEqual(repr(s.push_complete()),
                         "∃(x,y,z)[(A(x) | B(y) | ~D(z))]")
        s = ~(Quantifier.Universal(['x', 'y', 'z'], ~((alpha | beta) & delta)))
        self.assertEqual(repr(s.push_complete()),
                         "∃(x,y,z)[((A(x) | B(y)) & D(z))]")

        s = ~((~alpha | ~beta) & ~delta)
        self.assertEqual(repr(s.push_complete()), "((A(x) & B(y)) | D(z))")

        ## Test to make sure the recursino into nested stuff actually work
        s = (~~~~~~~~~alpha).push_complete()
        self.assertEqual(repr(s), '~A(x)')

        s = (~~~~~~~~alpha).push_complete()
        self.assertEqual(repr(s), 'A(x)')
Esempio n. 4
0
    def test_cnf_quantifier_simplfy(self):

        alpha = Symbol.Predicate('A', ['x'])

        uni_one = Quantifier.Universal(['x'], alpha)
        mixer = uni_one | alpha
        uni_two = Quantifier.Universal(['y'], mixer)

        self.assertEqual(repr(uni_two), "∀(y)[(∀(x)[A(x)] | A(x))]")
        self.assertEqual(repr(uni_two.simplify()), "∀(y,x)[(A(x) | A(x))]")
Esempio n. 5
0
    def test_axiom_function_replacement(self):
        f = Symbol.Function('f', ['x'])
        t = Symbol.Function('t', ['y'])
        a = Symbol.Predicate('A', [f])
        b = Symbol.Predicate('B', [f, t])

        axi = Axiom.Axiom(Quantifier.Universal(['x'], a | a & a))
        self.assertEqual(repr(axi), '∀(x)[(A(f(x)) | (A(f(x)) & A(f(x))))]')

        axi = Axiom.Axiom(Quantifier.Universal(['x', 'y'], b))
        self.assertEqual(
            repr(axi.substitute_functions()),
            '∀(x,y)[∀(t1)[(∀(f1)[(B(f1,t1) & f(x,f1))] & t(y,t1))]]')
Esempio n. 6
0
    def substitute_function(self):
        '''
        Find a function that's nested and replace it by adding a new variable and term
        '''

        # TODO This a dirty hack because cyclic imports are painful
        import macleod.logical.Quantifier as Quantifier

        if not self.has_functions():
            return self
        
        for idx, var in enumerate(self.variables):

            if isinstance(var, Function):

                function = var
                pos = idx

        # TODO Get a global variable singleton
        n_var = function.name.lower()[0] + '1'
        f_vars = copy.deepcopy(function.variables)
        f_vars.append(n_var)
        n_pred = Predicate(function.name, f_vars)
        e_vars = copy.deepcopy(self.variables)
        e_vars[pos] = n_var
        e_pred = Predicate(self.name, e_vars)

        return Quantifier.Universal([n_var], [e_pred & n_pred]), None
Esempio n. 7
0
    def test_axiom_variable_standardize(self):

        a = Symbol.Predicate('A', ['x'])
        b = Symbol.Predicate('B', ['y', 'x'])
        c = Symbol.Predicate('C',
                             ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])

        axi = Axiom.Axiom(Quantifier.Universal(['x'], a | a & a))
        self.assertEqual(repr(axi.standardize_variables()),
                         '∀(z)[(A(z) | (A(z) & A(z)))]')

        axi = Axiom.Axiom(Quantifier.Universal(['x', 'y'], b))
        self.assertEqual(repr(axi.standardize_variables()), '∀(z,y)[B(y,z)]')

        axi = Axiom.Axiom(
            Quantifier.Existential(
                ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], c))
        self.assertEqual(repr(axi.standardize_variables()),
                         '∃(z,y,x,w,v,u,t,s,r)[C(z,y,x,w,v,u,t,s,r)]')
Esempio n. 8
0
    def test_quantifiers(self):

        alpha = Symbol.Predicate('A', ['x'])
        beta = Symbol.Predicate('B', ['y'])
        delta = Symbol.Predicate('D', ['z'])

        uni = Quantifier.Universal(['x', 'y', 'z'], alpha | beta | delta)
        exi = Quantifier.Existential(['x', 'y', 'z'], alpha & beta & delta)

        self.assertEqual(repr(uni), "∀(x,y,z)[(A(x) | B(y) | D(z))]")
        self.assertEqual(repr(exi), "∃(x,y,z)[(A(x) & B(y) & D(z))]")

        self.assertEqual(repr(~uni), "~∀(x,y,z)[(A(x) | B(y) | D(z))]")
        self.assertEqual(repr(~exi), "~∃(x,y,z)[(A(x) & B(y) & D(z))]")

        self.assertEqual(repr((~uni).push()),
                         "∃(x,y,z)[~(A(x) | B(y) | D(z))]")
        self.assertEqual(repr((~exi).push()),
                         "∀(x,y,z)[~(A(x) & B(y) & D(z))]")
Esempio n. 9
0
    def test_axiom_quantifier_coalesence(self):

        a = Symbol.Predicate('A', ['x'])
        b = Symbol.Predicate('B', ['y'])

        universal = Quantifier.Universal(['x'], a)
        universal_two = Quantifier.Universal(['y'], b)
        existential = Quantifier.Existential(['y'], b)
        existential_two = Quantifier.Existential(['x'], a)

        # Coalescence over conjunction should merge Universals
        conjunction = universal & universal_two & existential & existential_two
        self.assertEqual(repr(conjunction.coalesce()),
                         '(∃(y)[B(y)] & ∃(x)[A(x)] & ∀(x)[(B(x) & A(x))])')

        # Coalescence over disjunction should merge Existentials
        disjunction = universal | universal_two | existential | existential_two
        self.assertEqual(repr(disjunction.coalesce()),
                         '(∀(x)[A(x)] | ∀(y)[B(y)] | ∃(y)[(A(y) | B(y))])')
Esempio n. 10
0
    def push(self):
        '''
        Push negation inwards and apply to all children
        '''

        # Can be a conjunction or disjunction
        # Can be a single predicate
        # Can be a quantifier

        if isinstance(self.term(), Connective.Conjunction):

            ret = Connective.Disjunction(
                [Negation(x) for x in self.term().get_term()])

        elif isinstance(self.term(), Connective.Disjunction):

            ret = Connective.Conjunction(
                [Negation(x) for x in self.term().get_term()])

        elif isinstance(self.term(), Symbol.Predicate):

            ret = self

        elif isinstance(self.term(), Quantifier.Existential):

            ret = Quantifier.Universal(self.term().variables,
                                       Negation(self.term().get_term()))

        elif isinstance(self.term(), Quantifier.Universal):

            ret = Quantifier.Existential(self.term().variables,
                                         Negation(self.term().get_term()))

        elif isinstance(self.term(), Negation):

            ret = self.term().term()

        else:

            raise ValueError("Negation onto unknown type!", self.term)

        return copy.deepcopy(ret)
Esempio n. 11
0
    def coalesce(self):
        '''
        Coalesce or merge any like quantifiers held as terms of this
        connective. Disjunctions will coalesce existentials and will merge
        universals.
        '''

        obj = copy.deepcopy(self)

        existentials = [
            x for x in obj.terms if isinstance(x, Quantifier.Existential)
        ]
        universals = [
            x for x in obj.terms if isinstance(x, Quantifier.Universal)
        ]

        if len(existentials) != 0:

            LOGGER.debug("Coalescing existentials")
            new_existential = functools.reduce(lambda x, y: x.coalesce(y),
                                               existentials)

            if len(existentials) == len(obj.terms):
                return new_existential

            else:
                for term in existentials:
                    obj.remove_term(term)

                obj.set_term(new_existential)
                return obj

        elif len(universals) != 0 and len(existentials) == 0:

            LOGGER.debug("Merging nested Universals")
            variables = []
            terms = []
            for quant in universals:
                variables += quant.variables
                terms.append(quant.terms[0])

            for term in obj.terms:
                LOGGER.debug("Adding term: " + repr(term))
                if term not in universals:
                    terms.append(term)

            terms = [type(self)(terms)]
            return Quantifier.Universal(variables, terms)

        else:

            return obj
Esempio n. 12
0
    def test_onf_detection(self):

        alpha = Symbol.Predicate('A', ['x'])
        beta = Symbol.Predicate('B', ['y'])
        delta = Symbol.Predicate('D', ['z'])

        uni = Quantifier.Universal(['x', 'y', 'z'], alpha | beta | delta)
        exi = Quantifier.Existential(['x', 'y', 'z'], alpha & beta | delta)

        self.assertEqual(alpha.is_onf(), True)
        self.assertEqual((alpha | beta).is_onf(), True)
        self.assertEqual((alpha & beta).is_onf(), True)
        self.assertEqual((alpha | (beta & delta)).is_onf(), False)
        self.assertEqual((alpha & (beta | delta)).is_onf(), True)
        self.assertEqual((~(alpha | beta)).is_onf(), False)
        self.assertEqual((~(alpha & beta)).is_onf(), False)

        self.assertEqual(uni.is_onf(), True)
        self.assertEqual(exi.is_onf(), False)

        # Note that is_onf() is not a recursive call, it's a top level feature
        # If will actually if you need an ONF axiom then create a Logical.Axiom and to_onf()
        self.assertEqual((alpha & (alpha | (beta & delta)) & delta).is_onf(),
                         True)
Esempio n. 13
0
    def test_cnf_quantifier_scoping(self):

        alpha = Symbol.Predicate('A', ['x'])
        beta = Symbol.Predicate('B', ['y'])
        delta = Symbol.Predicate('D', ['z'])

        uni_one = Quantifier.Universal(['x', 'y', 'z'], alpha | beta | delta)
        exi_one = Quantifier.Existential(['x', 'y', 'z'], alpha & beta | delta)
        term = exi_one | beta
        term_two = exi_one | beta | uni_one

        self.assertEqual(
            repr(Quantifier.Universal(['x', 'y', 'z'], uni_one).simplify()),
            "∀(x,y,z)[(A(x) | B(y) | D(z))]")
        self.assertEqual(
            repr(Quantifier.Universal(['x', 'y', 'z'], term_two).simplify()),
            "∀(x,y,z)[(∃(x,y,z)[((A(x) & B(y)) | D(z))] | B(y) | (A(x) | B(y) | D(z)))]"
        )
        self.assertEqual(
            repr(
                Quantifier.Universal(['x', 'y', 'z'],
                                     term_two).simplify().rescope()),
            "∀(x,y,z)[∃(x,y,z)[(B(y) | (A(x) | B(y) | D(z)) | ((A(x) & B(y)) | D(z)))]]"
        )
Esempio n. 14
0
    def coalesce(self):
        '''
        Coalesce or merge any like quantifiers held as terms of this
        connective. Conjunctions will coalesce universals and will merge
        existentials.

        precondition: Must not have both universals and existentials
        '''

        obj = copy.deepcopy(self)

        LOGGER.debug("Attempting to coalesce: " + repr(obj))

        universals = [
            x for x in obj.terms if isinstance(x, Quantifier.Universal)
        ]
        existentials = [
            x for x in obj.terms if isinstance(x, Quantifier.Existential)
        ]

        if len(universals) != 0:

            LOGGER.debug("Coalescing Universals")
            new_universal = functools.reduce(lambda x, y: x.coalesce(y),
                                             universals)
            LOGGER.debug("Coalesced Universal: " + repr(new_universal))

            if len(universals) == len(obj.terms):

                LOGGER.debug("Returning plain: " + repr(new_universal))

                return new_universal

            else:

                for term in universals:
                    obj.remove_term(term)

                obj.set_term(new_universal)

                LOGGER.debug("Returning added: " + repr(obj))
                return obj

        elif len(existentials) != 0 and len(universals) == 0:

            LOGGER.debug("Merging nested existentials")

            variables = []
            terms = []
            for quant in existentials:
                variables += quant.variables
                terms.append(quant.terms[0])

            for term in obj.terms:
                if term not in existentials:
                    terms.append(term)

            terms = [type(self)(terms)]
            return Quantifier.Existential(variables, terms)

        else:

            return obj
Esempio n. 15
0
def p_universal(p):
    """
    universal : LPAREN FORALL LPAREN nonlogicals RPAREN axiom RPAREN
    """

    p[0] = Quantifier.Universal(p[4], p[6])
Esempio n. 16
0
def p_existential(p):
    """
    existential : LPAREN EXISTS LPAREN nonlogicals RPAREN axiom RPAREN
    """

    p[0] = Quantifier.Existential(p[4], p[6])