def random_system(self): # generates variables/domains nb_variables = random.randint(1, self.__max_variables) variables = ["x"+str(var) for var in range(nb_variables)] domains = [ Continuum.random(self.__min_value, self.__max_value, self.__min_domain_size) for var in variables ] return variables, domains
def random_rule(self, variables, domains): var = random.randint(0,len(variables)-1) var_domain = domains[var] val = Continuum.random(var_domain.get_min_value(), var_domain.get_max_value(), self.__min_continuum_size) min_size = random.randint(0, len(variables)) max_size = random.randint(min_size, len(variables)) return ContinuumRule.random(var, val, variables, domains, min_size, max_size)
def test_static_random(self): eprint(">> Continuum.random(min_value, max_value)") for i in range(self.__nb_unit_test): # Valid values min = random.uniform(self.__min_value, self.__max_value) max = random.uniform(min, self.__max_value) c = Continuum.random(min, max) self.assertTrue(c.get_min_value() >= min and c.get_min_value() <= max) self.assertTrue(isinstance(c.min_included(), bool)) self.assertFalse(c.is_empty()) # with min size min_size = 0 while min_size == 0: min_size = random.uniform(-100, 0) self.assertRaises(ValueError, Continuum.random, min, max, min_size) min_size = random.uniform(0, self.__max_value) if min_size >= (max - min): self.assertRaises(ValueError, Continuum.random, min, max, min_size) c = Continuum.random(min, max) self.assertTrue(c.get_min_value() >= min and c.get_min_value() <= max) self.assertTrue(isinstance(c.min_included(), bool)) self.assertFalse(c.is_empty()) # Invalid values min = random.uniform(self.__min_value, self.__max_value) max = random.uniform(self.__min_value, min - 0.001) self.assertRaises(ValueError, Continuum.random, min, max)
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)
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)
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
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())
def test_precision(self): print(">> ContinuumLogicProgram.precision(expected, predicted)") self.assertEqual(ContinuumLogicProgram.precision([],[]), 1.0) # Equal programs for i in range(self.__nb_unit_test): variables, domains = self.random_system() nb_states = random.randint(1,100) expected = [] predicted = [] for j in range(nb_states): s1 = [ random.uniform(d.get_min_value(),d.get_max_value()) for d in domains ] s2 = [ random.uniform(d.get_min_value(),d.get_max_value()) for d in domains ] s2_ = [ Continuum.random(d.get_min_value(), d.get_max_value()) for d in domains ] expected.append( (s1,s2) ) predicted.append( (s1,s2_) ) precision = ContinuumLogicProgram.precision(expected, predicted) error = 0 for j in range(len(expected)): s1, s2 = expected[j] s1_, s2_ = predicted[j] for k in range(len(s2)): if not s2_[k].includes(s2[k]): error += 1 total = nb_states * len(variables) self.assertEqual( precision, 1.0 - (error / total) ) #eprint("precision: ", precision) # error of size state_id = random.randint(0, len(expected)-1) modif = random.randint(1,len(expected[state_id])) expected[state_id] = ( expected[state_id][0][:-modif], expected[state_id][1] ) self.assertRaises(ValueError, ContinuumLogicProgram.precision, expected, predicted)
def test___init__(self): print(">> ContinuumLogicProgram.__init__(self, variables, domains, rules)") for i in range(self.__nb_unit_test): variables, domains = self.random_system() rules = [] for j in range(random.randint(0,self.__nb_rules)): r = self.random_rule(variables, domains) rules.append(r) p = ContinuumLogicProgram(variables, domains, rules) self.assertEqual(p.get_variables(), variables) self.assertEqual(p.get_domains(), domains) self.assertEqual(p.get_rules(), rules) modif = random.randint(1,len(variables)) self.assertRaises(ValueError, ContinuumLogicProgram, variables, domains[:-modif], rules) for var in range(0, modif): domains.append(Continuum.random(self.__min_value, self.__max_value, self.__min_domain_size)) self.assertRaises(ValueError, ContinuumLogicProgram, variables, domains, rules)
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)
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)
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)
from idc import * from idautils import * sys.path.append( os.path.join( os.path.dirname(os.path.realpath(__file__)), '..', ) ) from continuum import Continuum from continuum.project import Project # Connect to server instance. proj = Project() cont = Continuum() proj.open(Project.find_project_dir(GetIdbDir()), skip_analysis=True) cont.open_project(proj) # Wait for auto-analysis to complete. SetShortPrm(INF_AF2, GetShortPrm(INF_AF2) | AF2_DODATA) print("Analyzing input file ...") cont.client.send_analysis_state('auto-analysis') Wait() # Index types. print("Indexing types ...") cont.client.send_analysis_state('indexing-types') proj.index.index_types_for_this_idb() # Index symbols.
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 == [])
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))
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
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)
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()
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)
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))
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))
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
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)