예제 #1
0
    def test_copy(self):
        eprint(">> Continuum.copy(self)")

        for i in range(self.__nb_unit_test):

            # Emptyset
            c_ = Continuum()
            c = c_.copy()

            self.assertTrue(c.is_empty())
            self.assertEqual(c.get_min_value(), None)
            self.assertEqual(c.get_max_value(), None)
            self.assertEqual(c.min_included(), None)
            self.assertEqual(c.max_included(), None)

            # Non empty
            min = random.uniform(self.__min_value, self.__max_value)
            max = random.uniform(min, self.__max_value)
            min_included = random.choice([True, False])
            max_included = random.choice([True, False])

            c_ = Continuum(min, max, min_included, max_included)
            c = c_.copy()

            self.assertFalse(c.is_empty())
            self.assertEqual(c.get_min_value(), min)
            self.assertEqual(c.get_max_value(), max)
            self.assertEqual(c.min_included(), min_included)
            self.assertEqual(c.max_included(), max_included)
예제 #2
0
    def test_constructor_full(self):
        eprint(
            ">> Continuum.__init__(self, min_value=None, max_value=None, min_included=None, max_included=None)"
        )

        for i in range(self.__nb_unit_test):

            # Valid continuum
            #-----------------
            min = random.uniform(self.__min_value, self.__max_value)
            max = random.uniform(min, self.__max_value)
            min_included = random.choice([True, False])
            max_included = random.choice([True, False])

            c = Continuum(min, max, min_included, max_included)

            self.assertFalse(c.is_empty())
            self.assertEqual(c.get_min_value(), min)
            self.assertEqual(c.get_max_value(), max)
            self.assertEqual(c.min_included(), min_included)
            self.assertEqual(c.max_included(), max_included)

            # Implicit emptyset
            #-------------------
            min = random.uniform(self.__min_value, self.__max_value)

            c = Continuum(min, min, False, False)

            self.assertTrue(c.is_empty())
            self.assertEqual(c.get_min_value(), None)
            self.assertEqual(c.get_max_value(), None)
            self.assertEqual(c.min_included(), None)
            self.assertEqual(c.max_included(), None)

            # Invalid Continuum
            #--------------------
            max = random.uniform(self.__min_value, min - 0.001)

            self.assertRaises(ValueError, Continuum, min, max, min_included,
                              max_included)

            # Invalid number of arguments
            #-------------------------------

            self.assertRaises(ValueError, Continuum, min)
            self.assertRaises(ValueError, Continuum, min, max)
            self.assertRaises(ValueError, Continuum, min, max, min_included)
            self.assertRaises(ValueError, Continuum, min, max, min_included,
                              max_included)
예제 #3
0
    def test_to_string(self):
        eprint(">> Continuum.to_string(self)")

        for i in range(self.__nb_unit_test):
            c = Continuum()

            self.assertEqual(c.to_string(), u"\u2205")

            c = Continuum.random(self.__min_value, self.__max_value)

            if c.is_empty():
                self.assertEqual(c.to_string(), u"\u2205")

            out = ""

            if c.min_included():
                out += "["
            else:
                out += "]"

            out += str(c.get_min_value()) + "," + str(c.get_max_value())

            if c.max_included():
                out += "]"
            else:
                out += "["

            self.assertEqual(c.to_string(), out)
            self.assertEqual(c.__str__(), out)
            self.assertEqual(c.__repr__(), out)
예제 #4
0
    def test_constructor_empty(self):
        eprint(">> Continuum.__init__(self)")

        for i in range(self.__nb_unit_test):
            c = Continuum()

            self.assertTrue(c.is_empty())
            self.assertEqual(c.get_min_value(), None)
            self.assertEqual(c.get_max_value(), None)
            self.assertEqual(c.min_included(), None)
            self.assertEqual(c.max_included(), None)
예제 #5
0
    def test_size(self):
        eprint(">> Continuum.size(self)")

        for i in range(self.__nb_unit_test):

            # empty set
            c = Continuum()
            self.assertEqual(c.size(), 0.0)

            # regular
            c = Continuum.random(self.__min_value, self.__max_value)

            if not c.is_empty():
                self.assertEqual(c.size(),
                                 c.get_max_value() - c.get_min_value())
예제 #6
0
    def least_revision(rule, state_1, state_2):
        """
        Compute the least revision of rule w.r.t. the transition (state_1, state_2)

        Agrs:
            rule: ContinuumRule
            state_1: list of float
            state_2: list of float

        Returns: list of ContinuumRule
            The least generalisation of the rule over its conclusion and
            the least specializations of the rule over each condition
        """

        # 0) Check Consistence
        #----------------------

        #Consistent rule
        if not rule.matches(state_1):
            raise ValueError(
                "Attempting to revise a consistent rule, revision would be itself, this call is useless in ACEDIA and must be an error"
            )

        # Consistent rule
        if rule.get_head_value().includes(state_2[rule.get_head_variable()]):
            raise ValueError(
                "Attempting to revise a consistent rule, revision would be itself, this call is useless in ACEDIA and must be an error"
            )

        # 1) Revise conclusion
        #----------------------
        head_var = rule.get_head_variable()
        next_value = state_2[head_var]
        revisions = []

        head_revision = rule.copy()
        head_value = head_revision.get_head_value()

        # Empty set head case
        if head_value.is_empty():
            head_value = Continuum(next_value, next_value, True, True)
        elif next_value <= head_value.get_min_value():
            head_value.set_lower_bound(next_value, True)
        else:
            head_value.set_upper_bound(next_value, True)

        head_revision.set_head_value(head_value)

        revisions.append(head_revision)

        # 2) Revise each condition
        #---------------------------
        for var, val in rule.get_body():
            state_value = state_1[var]

            # min revision
            min_revision = rule.copy()
            new_val = val.copy()
            new_val.set_lower_bound(state_value, False)
            if not new_val.is_empty():
                min_revision.set_condition(var, new_val)
                revisions.append(min_revision)

            # max revision
            max_revision = rule.copy()
            new_val = val.copy()
            new_val.set_upper_bound(state_value, False)
            if not new_val.is_empty():
                max_revision.set_condition(var, new_val)
                revisions.append(max_revision)

        return revisions
예제 #7
0
    def fit_var(variables, domains, transitions, variable):
        """
        Learn minimal rules that realizes the given transitions

        Args:
            variables: list of string
                variables of the system
            domains: list of Continuum
                domains of value of each variable
            transitions: list of (list of float, list of float)
                states transitions of the system
            variable: int
                variable id
        """
        #eprint("\rLearning var="+str(variable+1)+"/"+str(len(variables)), end='')

        # 0) Initialize undominated rule
        #--------------------------------
        body = [(var, domains[var]) for var in range(len(domains))]
        minimal_rules = [ContinuumRule(variable, Continuum(), body)]

        # Revise learned rules against each transition
        for state_1, state_2 in transitions:

            # 1) Extract unconsistents rules
            #--------------------------------
            unconsistents = [
                rule for rule in minimal_rules if rule.matches(state_1)
                and not rule.get_head_value().includes(state_2[variable])
            ]
            minimal_rules = [
                rule for rule in minimal_rules if rule not in unconsistents
            ]

            for unconsistent in unconsistents:

                revisions = ACEDIA.least_revision(unconsistent, state_1,
                                                  state_2)

                for revision in revisions:

                    # Check domination
                    dominated = False

                    for r in minimal_rules:
                        if r.dominates(revision):
                            dominated = True
                            break

                    # Remove dominated rules
                    if not dominated:
                        minimal_rules = [
                            r for r in minimal_rules
                            if not revision.dominates(r)
                        ]
                        minimal_rules.append(revision)

        # 2) remove domains wize conditions
        #-----------------------------------

        output = []

        for r in minimal_rules:
            if r.get_head_value().is_empty():
                continue

            r_ = r.copy()

            for var, val in r.get_body():
                if val == domains[var]:
                    r_.remove_condition(var)

            output.append(r_)

        #DBG
        #eprint("\r",end='')

        return output
예제 #8
0
    def test_set_upper_bound(self):
        eprint(">> Continuum.set_upper_bound(self, value, included)")

        for i in range(self.__nb_unit_test):
            # Empty set
            c = Continuum()

            self.assertRaises(TypeError, c.set_upper_bound, "string", True)
            self.assertRaises(TypeError, c.set_upper_bound, "string", False)
            self.assertRaises(TypeError, c.set_upper_bound, 0.5, 10)

            value = random.uniform(self.__min_value, self.__max_value)

            # extend with exclusion gives empty set, mistake expected from user
            # or both min and max will be changed and constructor must be used
            self.assertRaises(ValueError, c.set_upper_bound, value, False)

            c.set_upper_bound(value, True)

            # Empty set to one value interval
            self.assertEqual(c, Continuum(value, value, True, True))

            # Regular continuum

            # over min value
            c = Continuum.random(self.__min_value, self.__max_value)
            value = random.uniform(self.__min_value, c.get_min_value())
            while value == c.get_min_value():
                value = random.uniform(self.__min_value, c.get_min_value())

            self.assertRaises(ValueError, c.set_upper_bound, value, True)
            self.assertRaises(ValueError, c.set_upper_bound, value, False)

            # on min value
            c = Continuum.random(self.__min_value, self.__max_value)
            c_old = c.copy()
            value = c.get_min_value()
            if not c.max_included() or not c.min_included():
                c.set_upper_bound(value, False)
                self.assertEqual(c,
                                 Continuum())  # continuum reduced to empty set
            else:
                c.set_upper_bound(value, True)
                self.assertEqual(c.get_max_value(), value)
                self.assertEqual(c.max_included(), True)
                self.assertEqual(c.get_max_value(), c.get_min_value())

                self.assertEqual(c.get_min_value(), c_old.get_min_value())
                self.assertEqual(c.min_included(), c_old.min_included())

            # other valid value
            c = Continuum.random(self.__min_value, self.__max_value)
            c_old = c.copy()
            value = random.uniform(c.get_min_value(), self.__max_value)
            while value == c.get_min_value():
                value = random.uniform(c.get_min_value(), self.__max_value)

            c.set_upper_bound(value, True)

            self.assertEqual(c.get_max_value(), value)
            self.assertEqual(c.max_included(), True)

            c = Continuum.random(self.__min_value, self.__max_value)
            c_old = c.copy()
            value = random.uniform(c.get_min_value(), self.__max_value)
            while value == c.get_min_value():
                value = random.uniform(c.get_min_value(), self.__max_value)

            c.set_upper_bound(value, False)

            self.assertEqual(c.get_max_value(), value)
            self.assertEqual(c.max_included(), False)
예제 #9
0
    def test__eq__(self):
        eprint(">> Continuum.__eq__(self, continuum)")

        for i in range(self.__nb_unit_test):

            # emptyset
            c = Continuum()

            self.assertTrue(Continuum() == Continuum())
            self.assertTrue(c == Continuum())
            self.assertTrue(c == c)

            self.assertFalse(Continuum() != Continuum())
            self.assertFalse(c != Continuum())
            self.assertFalse(c != c)

            c = Continuum.random(self.__min_value, self.__max_value)

            self.assertTrue(c == c)
            self.assertFalse(c != c)
            self.assertEqual(c == Continuum(), c.is_empty())

            c_ = Continuum.random(self.__min_value, self.__max_value)

            if c.is_empty() and c_.is_empty():
                self.assertTrue(c == c_)
                self.assertTrue(c != c_)

            if c.is_empty() != c_.is_empty():
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)

            if c.get_min_value() != c_.get_min_value():
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)

            if c.get_max_value() != c_.get_max_value():
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)

            if c.min_included() != c_.min_included():
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)

            if c.max_included() != c_.max_included():
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)

            # exaustive modifications
            if not c.is_empty():
                c_ = c.copy()
                value = random.uniform(1, 100)
                c_.set_lower_bound(c.get_min_value() - value, True)
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)
                c_.set_lower_bound(c.get_min_value() - value, False)
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)

                c_ = c.copy()
                c_.set_lower_bound(c.get_min_value(), not c.min_included())
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)

                c_ = c.copy()
                value = random.uniform(1, 100)
                c_.set_upper_bound(c.get_min_value() + value, True)
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)
                c_.set_upper_bound(c.get_min_value() + value, False)
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)

                c_ = c.copy()
                c_.set_upper_bound(c.get_max_value(), not c.max_included())
                self.assertFalse(c == c_)
                self.assertTrue(c != c_)

            # different type
            self.assertFalse(c == "test")
            self.assertFalse(c == 0)
            self.assertFalse(c == True)
            self.assertFalse(c == [])
예제 #10
0
    def test_intersects(self):
        eprint(">> Continuum.intersects(self, continuum)")

        for i in range(self.__nb_unit_test):
            c = Continuum.random(self.__min_value, self.__max_value)
            c_ = Continuum()

            # emptyset
            self.assertFalse(c.intersects(c_))
            self.assertFalse(c_.intersects(c))
            self.assertFalse(c_.intersects(c_))

            # stricly before
            c = Continuum.random(self.__min_value, self.__max_value)
            c_ = Continuum.random(c.get_min_value() - 100, c.get_min_value())
            self.assertFalse(c.intersects(c_))
            self.assertFalse(c_.intersects(c))

            # touching on lower bound
            c = Continuum.random(self.__min_value, self.__max_value)
            c_ = Continuum.random(c.get_min_value() - 100, c.get_min_value())
            c_.set_upper_bound(c.get_min_value(), True)

            self.assertEqual(c.intersects(c_), c.min_included())
            self.assertEqual(c_.intersects(c), c.min_included())

            c_.set_upper_bound(c.get_min_value(), False)

            self.assertFalse(c.intersects(c_))
            self.assertFalse(c_.intersects(c))

            # strictly after
            c = Continuum.random(self.__min_value, self.__max_value)
            c_ = Continuum.random(c.get_max_value(), c.get_max_value() + 100)
            self.assertFalse(c.intersects(c_))
            self.assertFalse(c_.intersects(c))

            # touching on lower bound
            c = Continuum.random(self.__min_value, self.__max_value)
            c_ = Continuum.random(c.get_max_value(), c.get_max_value() + 100)
            c_.set_lower_bound(c.get_max_value(), True)

            self.assertEqual(c.intersects(c_), c.max_included())
            self.assertEqual(c_.intersects(c), c.max_included())

            c_.set_lower_bound(c.get_max_value(), False)

            self.assertFalse(c.intersects(c_))
            self.assertFalse(c_.intersects(c))

            # same (not empty)
            c = Continuum.random(self.__min_value, self.__max_value)
            while c.is_empty():
                c = Continuum.random(self.__min_value, self.__max_value)
            self.assertTrue(c.includes(c))

            # smaller
            c_ = Continuum.random(c.get_min_value(), c.get_max_value())
            while c_.get_min_value() == c.get_min_value() and c_.get_max_value(
            ) == c.get_max_value():
                c_ = Continuum.random(c.get_min_value(), c.get_max_value())

            self.assertTrue(c.intersects(c_))
            self.assertTrue(c_.intersects(c))

            # bigger
            c_ = Continuum.random(c.get_min_value() - 100,
                                  c.get_max_value() + 100)
            while c_.get_min_value() >= c.get_min_value() or c_.get_max_value(
            ) <= c.get_max_value():
                c_ = Continuum.random(c.get_min_value() - 100,
                                      c.get_max_value() + 100)

            #eprint(c.to_string())
            #eprint(c_.to_string())
            self.assertTrue(c.intersects(c_))
            self.assertTrue(c_.intersects(c))
예제 #11
0
    def test_includes(self):
        eprint(">> Continuum.includes(self, element)")

        for i in range(self.__nb_unit_test):

            # bad argument type
            c = Continuum.random(self.__min_value, self.__max_value)

            self.assertRaises(TypeError, c.includes, "test")

            # float argument
            #----------------

            # empty set includes nothing
            c = Continuum()
            value = random.uniform(self.__min_value, self.__max_value)
            self.assertFalse(c.includes(value))

            c = Continuum.random(self.__min_value, self.__max_value)

            # Before min
            value = c.get_min_value()
            while value == c.get_min_value():
                value = random.uniform(c.get_min_value() - 100.0,
                                       c.get_min_value())

            self.assertFalse(c.includes(value))

            # on min bound
            self.assertEqual(c.includes(c.get_min_value()), c.min_included())

            # Inside
            value = c.get_min_value()
            while value == c.get_min_value() or value == c.get_max_value():
                value = random.uniform(c.get_min_value(), c.get_max_value())

            self.assertTrue(c.includes(value))

            # on max bound
            self.assertEqual(c.includes(c.get_max_value()), c.max_included())

            # after max bound
            value = c.get_max_value()
            while value == c.get_max_value():
                value = random.uniform(c.get_max_value(),
                                       c.get_max_value() + 100.0)

            self.assertFalse(c.includes(value))

            # int argument
            #--------------

            # empty set includes nothing
            c = Continuum()
            value = random.randint(int(self.__min_value),
                                   int(self.__max_value))
            self.assertFalse(c.includes(value))

            c = Continuum.random(self.__min_value, self.__max_value)

            while int(c.get_max_value()) - int(c.get_min_value()) <= 1:
                min = random.uniform(self.__min_value, self.__max_value)
                max = random.uniform(min, self.__max_value)

                c = Continuum.random(min, max)

            #eprint(c.to_string())

            # Before min
            value = random.randint(int(c.get_min_value() - 100),
                                   int(c.get_min_value()) - 1)

            self.assertFalse(c.includes(value))

            # on min bound
            self.assertEqual(c.includes(c.get_min_value()), c.min_included())

            # Inside
            value = random.randint(
                int(c.get_min_value()) + 1,
                int(c.get_max_value()) - 1)

            #eprint(value)

            self.assertTrue(c.includes(value))

            # on max bound
            self.assertEqual(c.includes(c.get_max_value()), c.max_included())

            # after max bound
            value = random.randint(
                int(c.get_max_value()) + 1, int(c.get_max_value() + 100))

            self.assertFalse(c.includes(value))

            # continuum argument
            #--------------------

            # 0) c is empty set
            c = Continuum()
            c_ = Continuum()
            self.assertTrue(c.includes(c_))  # empty set VS empty set

            c_ = Continuum.random(self.__min_value, self.__max_value)
            while c_.is_empty():
                c_ = Continuum.random(self.__min_value, self.__max_value)
            self.assertFalse(c.includes(c_))  # empty set VS non empty

            # 1) c is non empty
            c = Continuum.random(self.__min_value, self.__max_value)

            self.assertTrue(c.includes(Continuum()))  # non empty VS empty set
            self.assertTrue(c.includes(c))  # includes itself

            # 1.1) Lower bound over
            c_ = Continuum.random(c.get_min_value(), self.__max_value)
            while c_.is_empty():
                c_ = Continuum.random(c.get_min_value(), self.__max_value)

            value = c.get_min_value()
            while value == c.get_min_value():
                value = random.uniform(c.get_min_value() - 100,
                                       c.get_min_value())

            c_.set_lower_bound(value, random.choice([True, False]))
            self.assertFalse(c.includes(c_))

            # 1.2) on min bound
            c_ = Continuum.random(c.get_min_value(), self.__max_value)
            while c_.is_empty():
                c_ = Continuum.random(c.get_min_value(), self.__max_value)
            c_.set_lower_bound(c.get_min_value(), random.choice([True, False]))

            if not c.min_included() and c_.min_included():  # one value over
                self.assertFalse(c.includes(c_))

            # 1.3) upper bound over
            c_ = Continuum.random(self.__min_value, c.get_max_value())
            while c_.is_empty():
                c_ = Continuum.random(self.__min_value, c.get_max_value())

            value = c.get_max_value()
            while value == c.get_max_value():
                value = random.uniform(c.get_max_value(),
                                       c.get_max_value() + 100)

            c_.set_upper_bound(value, random.choice([True, False]))

            self.assertFalse(c.includes(c_))

            # 1.4) on upper bound
            c_ = Continuum.random(self.__min_value, c.get_max_value())
            while c_.is_empty():
                c_ = Continuum.random(self.__min_value, c.get_max_value())
            c_.set_upper_bound(c.get_max_value(), random.choice([True, False]))

            if not c.max_included() and c_.max_included():  # one value over
                self.assertFalse(c.includes(c_))

            # 1.5) inside
            min = c.get_min_value()
            while min == c.get_min_value():
                min = random.uniform(c.get_min_value(), c.get_max_value())
            max = c.get_max_value()
            while max == c.get_max_value():
                max = random.uniform(min, c.get_max_value())
            c_ = Continuum(min, max, random.choice([True, False]),
                           random.choice([True, False]))

            self.assertTrue(c.includes(c_))
            self.assertFalse(c_.includes(c))
예제 #12
0
from utils import eprint
from continuum import Continuum
from continuumLogicProgram import ContinuumLogicProgram
from acedia import ACEDIA

# 1: Main
#------------
if __name__ == '__main__':

    # 0) Example from text file representing a logic program
    #--------------------------------------------------------
    eprint("Example using random logic program:")
    eprint("----------------------------------------------")

    variables = ["a", "b", "c"]
    domains = [ Continuum(0.0,1.0,True,True) for v in variables ]
    rule_min_size = 0
    rule_max_size = 3
    epsilon = 0.5
    random.seed(9999)

    benchmark = ContinuumLogicProgram.random(variables, domains, rule_min_size, rule_max_size, epsilon, delay=1)

    eprint("Original logic program: \n", benchmark.logic_form())

    eprint("Generating transitions...")

    input = benchmark.generate_all_transitions(epsilon)

    eprint("ACEDIA input: \n", input)
예제 #13
0
    def test_fit(self):
        eprint(">> ACEDIA.fit(variables, values, transitions)")

        for i in range(self.__nb_unit_test):

            eprint("\rTest ", i + 1, "/", self.__nb_unit_test, end='')

            # Generate transitions
            epsilon = random.choice([0.1, 0.25, 0.3, 0.5])
            variables, domains = self.random_system()
            p = ContinuumLogicProgram.random(variables, domains, 1,
                                             len(variables), epsilon)

            #eprint("Progam: ", p)

            # Valid and realistic epsilon
            #epsilon = round(random.uniform(0.1,1.0), 2)
            #while epsilon == 1.0:
            #    epsilon = round(random.uniform(0.1,1.0), 2)

            t = p.generate_all_transitions(epsilon)

            #sys.exit()

            #eprint("Transitions: ")
            #for s1, s2 in t:
            #    eprint(s1, s2)
            #eprint("Transitions: ", t)

            p_ = ACEDIA.fit(p.get_variables(), p.get_domains(), t)
            rules = p_.get_rules()

            #eprint("learned: ", p_)

            # All transitions are realized
            #------------------------------

            for head_var in range(len(p.get_variables())):
                for s1, s2 in t:
                    for idx, val in enumerate(s2):
                        realized = 0
                        for r in rules:
                            if r.get_head_variable(
                            ) == idx and r.get_head_value().includes(
                                    val) and r.matches(s1):
                                realized += 1
                                break
                        if realized <= 0:
                            eprint("head_var: ", head_var)
                            eprint("s1: ", s1)
                            eprint("s2: ", s2)
                            eprint("learned: ", p_)
                        self.assertTrue(
                            realized >= 1)  # One rule realize the example

            # All rules are minimals
            #------------------------
            for r in rules:

                #eprint("r: ", r)

                # Try reducing head min
                #-----------------------
                r_ = r.copy()
                h = r_.get_head_value()
                if h.get_min_value() + epsilon <= h.get_max_value():
                    r_.set_head_value(
                        Continuum(h.get_min_value() + epsilon,
                                  h.get_max_value(), h.min_included(),
                                  h.max_included()))

                    #eprint("spec: ", r_)

                    conflict = False
                    for s1, s2 in t:
                        if not r_.get_head_value().includes(
                                s2[r_.get_head_variable()]) and r_.matches(
                                    s1):  # Cover a negative example
                            conflict = True
                            #eprint("conflict")
                            break

                    if not conflict:
                        eprint("Non minimal rule: ", r)
                        eprint("head can be specialized into: ",
                               r_.get_head_variable(), "=",
                               r_.get_head_value())

                    self.assertTrue(conflict)

                # Try reducing head max
                #-----------------------
                r_ = r.copy()
                h = r_.get_head_value()
                if h.get_max_value() - epsilon >= h.get_min_value():
                    r_.set_head_value(
                        Continuum(h.get_min_value(),
                                  h.get_max_value() - epsilon,
                                  h.min_included(), h.max_included()))

                    #eprint("spec: ", r_)

                    conflict = False
                    for s1, s2 in t:
                        if not r_.get_head_value().includes(
                                s2[r_.get_head_variable()]) and r_.matches(
                                    s1):  # Cover a negative example
                            conflict = True
                            #eprint("conflict")
                            break

                    if not conflict:
                        eprint("Non minimal rule: ", r)
                        eprint("head can be generalized to: ",
                               r_.get_head_variable(), "=",
                               r_.get_head_value())

                    self.assertTrue(conflict)

                # Try extending condition
                #-------------------------
                for (var, val) in r.get_body():

                    # Try extend min
                    r_ = r.copy()
                    if val.get_min_value(
                    ) - epsilon >= domains[var].get_min_value():
                        val_ = val.copy()
                        if not val_.min_included():
                            val_.set_lower_bound(val_.get_min_value(), True)
                        else:
                            val_.set_lower_bound(
                                val_.get_min_value() - epsilon, False)
                        r_.set_condition(var, val_)

                        #eprint("gen: ", r_)

                        conflict = False
                        for s1, s2 in t:
                            if not r_.get_head_value().includes(
                                    s2[r_.get_head_variable()]) and r_.matches(
                                        s1):  # Cover a negative example
                                conflict = True
                                #eprint("conflict")
                                break

                        if not conflict:
                            eprint("Non minimal rule: ", r)
                            eprint("condition can be generalized: ", var, "=",
                                   val_)

                        self.assertTrue(conflict)

                    # Try extend max
                    r_ = r.copy()
                    if val.get_max_value(
                    ) + epsilon <= domains[var].get_max_value():
                        val_ = val.copy()
                        if not val_.max_included():
                            val_.set_upper_bound(val_.get_max_value(), True)
                        else:
                            val_.set_upper_bound(
                                val_.get_max_value() + epsilon, False)
                        r_.set_condition(var, val_)

                        #eprint("gen: ", r_)

                        conflict = False
                        for s1, s2 in t:
                            if not r_.get_head_value().includes(
                                    s2[r_.get_head_variable()]) and r_.matches(
                                        s1):  # Cover a negative example
                                conflict = True
                                #eprint("conflict")
                                break

                        if not conflict:
                            eprint("Non minimal rule: ", r)
                            eprint("condition can be generalized: ", var, "=",
                                   val_)

                        self.assertTrue(conflict)
        eprint()
예제 #14
0
    def test_least_revision(self):
        eprint(">> ACEDIA.least_revision(rule, state_1, state_2)")

        for i in range(self.__nb_unit_test):
            variables, domains = self.random_system()

            state_1 = self.random_state(variables, domains)
            state_2 = self.random_state(variables, domains)

            # not matching
            #--------------
            rule = self.random_rule(variables, domains)
            while rule.matches(state_1):
                rule = self.random_rule(variables, domains)

            self.assertRaises(ValueError, ACEDIA.least_revision, rule, state_1,
                              state_2)

            # matching
            #--------------

            rule = self.random_rule(variables, domains)
            while not rule.matches(state_1):
                rule = self.random_rule(variables, domains)

            head_var = rule.get_head_variable()
            target_val = state_2[rule.get_head_variable()]

            # Consistent
            head_value = Continuum()
            while not head_value.includes(target_val):
                head_value = Continuum.random(
                    domains[head_var].get_min_value(),
                    domains[head_var].get_max_value())
            rule.set_head_value(head_value)
            self.assertRaises(ValueError, ACEDIA.least_revision, rule, state_1,
                              state_2)

            # Empty set head
            rule.set_head_value(Continuum())

            LR = ACEDIA.least_revision(rule, state_1, state_2)
            lg = rule.copy()
            lg.set_head_value(Continuum(target_val, target_val, True, True))
            self.assertTrue(lg in LR)

            nb_valid_revision = 1

            for var, val in rule.get_body():
                state_value = state_1[var]

                # min rev
                ls = rule.copy()
                new_val = val.copy()
                new_val.set_lower_bound(state_value, False)
                if not new_val.is_empty():
                    ls.set_condition(var, new_val)
                    self.assertTrue(ls in LR)
                    nb_valid_revision += 1

                # max rev
                ls = rule.copy()
                new_val = val.copy()
                new_val.set_upper_bound(state_value, False)
                if not new_val.is_empty():
                    ls.set_condition(var, new_val)
                    self.assertTrue(ls in LR)
                    nb_valid_revision += 1

            self.assertEqual(len(LR), nb_valid_revision)

            #eprint(nb_valid_revision)

            # usual head
            head_value = Continuum.random(domains[head_var].get_min_value(),
                                          domains[head_var].get_max_value())
            while head_value.includes(target_val):
                head_value = Continuum.random(
                    domains[head_var].get_min_value(),
                    domains[head_var].get_max_value())
            rule.set_head_value(head_value)

            LR = ACEDIA.least_revision(rule, state_1, state_2)

            lg = rule.copy()
            head_value = lg.get_head_value()
            if target_val <= head_value.get_min_value():
                head_value.set_lower_bound(target_val, True)
            else:
                head_value.set_upper_bound(target_val, True)
            lg.set_head_value(head_value)
            self.assertTrue(lg in LR)

            nb_valid_revision = 1

            for var, val in rule.get_body():
                state_value = state_1[var]

                # min rev
                ls = rule.copy()
                new_val = val.copy()
                new_val.set_lower_bound(state_value, False)
                if not new_val.is_empty():
                    ls.set_condition(var, new_val)
                    self.assertTrue(ls in LR)
                    nb_valid_revision += 1

                # max rev
                ls = rule.copy()
                new_val = val.copy()
                new_val.set_upper_bound(state_value, False)
                if not new_val.is_empty():
                    ls.set_condition(var, new_val)
                    self.assertTrue(ls in LR)
                    nb_valid_revision += 1

            self.assertEqual(len(LR), nb_valid_revision)
예제 #15
0
class ContinuumRule:
    """
    Define a continuum logic rule, conclusion and conditions are pairs (variable, continuum)
        - one conclusion
        - one conjonction of conditions
            - atmost one condition per variable, i.e. atmost one continuum is specified for a variable
        - a rule holds when all conditions continuum includes the values of the system state, i.e. the rule matches the state
    """
    """ Conclusion variable id: int """
    __head_variable = 0
    """ Conclusion value: Continuum """
    __head_value = Continuum()
    """ Conditions values: list of (int,Continuum) """
    __body = []

    #--------------
    # Constructors
    #--------------

    def __init__(self, head_variable, head_value, body=None):
        """
        Constructor of a continuum logic rule

        Args:
            head_variable: int
                id of the head variable
            head_value: Continuum
                values of the head variable
            body: list of tuple (int,Continuum)
                list of conditions as pairs of variable id, continuum of values
        """
        self.__head_variable = head_variable
        self.__head_value = head_value.copy()
        self.__body = []

        if body is not None:
            for var, val in body:
                self.set_condition(var, val)

    def copy(self):
        """
        copy method

        Returns:
            Rule
                A copy of the rule
        """
        return ContinuumRule(self.__head_variable, self.__head_value,
                             self.__body)

    @staticmethod
    def random(head_variable, head_value, variables, domains, min_body_size,
               max_body_size):
        """
        Generates a valid continuum rule of given size randomly.

        Args:
            head_variable: int
                id of the head variable
            head_value: Continuum
                range of values of the head variable
            variables: list of String
                labels of the variable of a dynamic system
            domains: list of pairs of (int, Continuum)
                domains of values of each variable
            min_body_size: int
                minimal number of conditions to appear in the generated rule
            max_body_size: int
                maximal number of conditions to appear in the generated rule

        Returns: ContinuumRule
            A random valid continuum rule
        """

        if min_body_size > max_body_size:
            raise ValueError(
                "min_body_size must be inferior or equal to max_body_size")

        if min_body_size > len(variables):
            raise ValueError(
                "min_body_size can't exceed the number of variables")

        if max_body_size > len(variables):
            raise ValueError(
                "max_body_size can't exceed the number of variables")

        size = random.randint(min_body_size, max_body_size)

        locked = []

        r = ContinuumRule(head_variable, head_value)

        while r.size() < size:
            var = random.randint(0, len(variables) - 1)
            val = Continuum.random(domains[var].get_min_value(),
                                   domains[var].get_max_value())

            if var not in locked:
                r.set_condition(var, val)
                locked.append(var)

        return r

#--------------
# Observers
#--------------

    def size(self):
        """
        Gives the number of conditions in the rule

        Returns:
            int
                the number of conditions in the rule body
        """
        return len(self.__body)

    def get_condition(self, variable):
        """
        Accessor to the condition value over the given variable

        Args:
            variable: int
                a variable id

        Returns:
            Continuum
                The value of the condition over the variable if it exists
                None if no condition exists on the given variable
        """
        for (var, val) in self.__body:
            if (var == variable):
                return val
        return None

    def has_condition(self, variable):
        """
        Observer to condition existence over the given variable

        Args:
            variable: int
                a variable id

        Returns:
            Bool
                True if a condition exists over the given variable
                False otherwize
        """
        return self.get_condition(variable) is not None

#--------------
# Operators
#--------------

    def __eq__(self, rule):
        """
        Compare equallity with other rule

        Args:
            rule: ContinuumRule

        Returns:
            Boolean
                True if the other rule is equal
                False otherwize
        """
        if isinstance(rule, ContinuumRule):
            # Different head
            if (self.get_head_variable() != rule.get_head_variable()) or (
                    self.get_head_value() != rule.get_head_value()):
                return False

            # Different size
            if len(self.get_body()) != len(rule.get_body()):
                return False

            # Check conditions
            for c in self.get_body():
                if c not in rule.get_body():
                    return False

            # Same head, same number of conditions and all conditions appear in the other rule
            return True

        return False

    def __str__(self):
        return self.to_string()

    def __repr__(self):
        return self.to_string()

#--------------
# Methods
#--------------

    def to_string(self):
        """
        Convert the object to a readable string

        Returns:
            String
                a readable representation of the object
        """
        out = str(self.__head_variable) + "=" + self.__head_value.to_string()

        out += " :- "
        for var, val in self.__body:
            out += str(var) + "=" + val.to_string() + ", "
        if len(self.__body) > 0:
            out = out[:-2]
        out += "."
        return out

    def logic_form(self, variables):
        """
        Convert the rule to a logic programming string format,
        using given variables labels

        Args:
            variables: list of string
                labels of the variables

        Returns:
            String
                a readable logic programmong representation of the rule
        """
        var_label = variables[self.__head_variable % len(variables)]
        out = str(var_label) + "(" + self.__head_value.to_string() + ",T) :- "

        for var, val in self.__body:
            var_label = variables[var % len(variables)]
            delay = int(var / len(variables)) + 1
            out += str(var_label) + "(" + val.to_string() + ",T-" + str(
                delay) + "), "
        if len(self.__body) > 0:
            out = out[:-2]
        out += "."
        return out

    def matches(self, state):
        """
        Check if the conditions of the rules holds in the given state

        Args:
            state: list of float
                a state of the system

        Returns:
            Boolean
                True if all conditions holds in the given state
                False otherwize
        """
        for (var, val) in self.__body:
            # delayed condition
            if (var >= len(state)):
                return False

            if (not val.includes(state[var])):
                return False
        return True

    def dominates(self, rule):
        """
        Check if the rule is more general and more precise:
            - conclusion is smaller (included in the other)
            - conditions are all bigger (they includes the others)

        Args:
            rule: ContinuumRule

        Returns:
            Boolean
                True if the rule dominates the other one
                False otherwize
        """

        # Different variable
        if self.get_head_variable() != rule.get_head_variable():
            return False

        # Conclusion more specific
        if not rule.get_head_value().includes(self.get_head_value()):
            return False

        # Conditions more general
        for var, val in self.__body:
            if rule.get_condition(var) is None:
                return False

            if not val.includes(rule.get_condition(var)):
                return False

        # Dominates
        return True

    def remove_condition(self, variable):
        """
        Remove a condition from the body of the rule

        Args:
            variable: int
                id of a variable
        """
        index = 0
        for (var, val) in self.__body:
            if (var == variable):
                self.__body.pop(index)
                return
            index += 1

#--------------
# Accessors
#--------------

    def get_head_variable(self):
        """
        Accessor to __head_variable

        Returns:
            int
                the conclusion variable id
        """
        return self.__head_variable

    def get_head_value(self):
        """
        Accessor to __head_value

        Returns:
            Continuum
                the value range of the conclusion
        """
        return self.__head_value

    def get_body(self):
        """
        Accessor to __body

        Returns:
            list of pair (int, Continuum)
                list of conditions of the rule
        """
        return self.__body

#--------------
# Mutatators
#--------------

    def set_head_variable(self, variable):
        """
        Head variable mutator method

        Args:
            variable: int
                id of the new head variable
        """
        self.__head_variable = variable

    def set_head_value(self, value):
        """
        Head value mutator method

        Args:
            value: Continuum
                continuum of the new head value
        """
        self.__head_value = value.copy()

    def set_condition(self, variable, value):
        """
        Condition mutator method

        Args:
            variable: int
                id of the variable
            value: Continuum
                new value of the condition over the given variable
        """
        for i, (var, val) in enumerate(self.__body):
            # new condition variable
            if var > variable:
                self.__body.insert(i, (variable, value))
                return

            # condition found
            if var == variable:
                self.__body[i] = (variable, value)
                return

        # new condition on variable id bigger than biggest knowned
        self.__body.append((variable, value))
예제 #16
0
    def random(variables, domains, rule_min_size, rule_max_size, epsilon, delay=1):
        """
        Generate a epsilon-complete ContinuumLogicProgram with a random dynamics.
        For each variable of the system, each possible epsilon state of the system is matched by at least one rule.

        Args:
            variables: list of String
                variables of the represented system
            domains: list of Continuum
                domain of values that each variable can take
            rule_min_size: int
                minimal number of conditions in each rule
            rule_max_size: int
                maximal number of conditions in each rule
            epsilon: float in ]0,1]
                precision of the completness of the program
            delay: int
                maximal delay of the conditions of each rule

        Returns:
            ContinuumLogicProgram
                an epsilon-complete CLP with a random dynamics
        """

        #eprint("Start random CLP generation: var ", len(variables), " delay: ", delay)
        extended_variables = variables.copy()
        extended_domains = domains.copy()

        # Delayed logic program: extend local herbrand base
        if delay > 1:
            for d in range(1,delay):
                extended_variables += [var+"_"+str(d) for var in variables]
                extended_domains += domains

        rules = []
        states = ContinuumLogicProgram.states(extended_domains, epsilon) # aggregated reversed time serie of size delay

        for s in states:
            #eprint(s)
            for var in range(len(variables)):
                matching = False
                for r in rules: # check if matched
                    if r.get_head_variable() == var and r.matches(s):
                        matching = True
                        break

                if not matching: # need new rule
                    val = Continuum()
                    while val.is_empty():
                        # Enumerate each possible value
                        min = domains[var].get_min_value()
                        max = domains[var].get_max_value()
                        step = epsilon * (max - min)
                        values = [min+(step*i) for i in range( int(1.0 / epsilon) )]
                        if values[-1] != max:
                            values.append(max)

                        min = random.choice(values)
                        max = random.choice(values)
                        while min > max:
                            min = random.choice(values)
                            max = random.choice(values)

                        val = Continuum(min, max, random.choice([True,False]), random.choice([True,False]))

                    body_size = random.randint(rule_min_size, rule_max_size)

                    new_rule = ContinuumRule(var, val, [])

                    # Prevent cross-match
                    # not necessarry, since next(state) assume determinism

                    # Complete the rule body if needed
                    while (new_rule.size() < body_size): # create body
                        cond_var = random.randint(0, len(s)-1)
                        if new_rule.has_condition(cond_var):
                            continue

                        # Enumerate each possible value
                        min = extended_domains[cond_var].get_min_value()
                        max = extended_domains[cond_var].get_max_value()
                        step = epsilon * (max - min)
                        values = [min+(step*i) for i in range( int(1.0 / epsilon) )]
                        if values[-1] != max:
                            values.append(max)

                        cond_val = Continuum()
                        while not cond_val.includes(s[cond_var]):
                            min = random.choice(values)
                            max = random.choice(values)
                            while min > max:
                                min = random.choice(values)
                                max = random.choice(values)
                            cond_val = Continuum(min, max, random.choice([True,False]), random.choice([True,False]))

                        new_rule.set_condition(cond_var, cond_val)

                    rules.append(new_rule)

        return ContinuumLogicProgram(variables, domains, rules)