def p_predicate_def(p): '''predicate_def : LPAREN NAME typed_variables_lst RPAREN | LPAREN NAME RPAREN''' if len(p) == 4: p[0] = Predicate(p[2]) elif len(p) == 5: p[0] = Predicate(p[2], p[3])
def _predicate_to_fluent(self, predicate, assignment, fluent_dict={}): """ Inputs: predicate The predicate to be converted assignment a dictionary mapping each possible variable name to an object Returns: A fluent that has the particular valuation for the variables as given in input. The old predicate is *untouched* """ if predicate is None: return None fluent_args = [] for var_name, var_type in predicate.args: if var_name in assignment: fluent_args.append((assignment[var_name], var_type)) elif not var_name.startswith("?"): # will assume these are already ground fluent_args.append((var_name, var_type)) else: raise KeyError("Unknown variable %s in predicate %s" % (var_name, str(predicate))) fluent = Predicate(predicate.name, args=None, ground_args=fluent_args) fluent.always_known = predicate.always_known if hash (fluent) in fluent_dict: return fluent_dict[hash (fluent)] else: return fluent
class Rule(): def __init__(self, ruleString): # The string we parse the rule from. self.ruleString = ruleString # The predicate that is true if the rule's conjugate clauses are true. self.consequent = None # List of conjugated predicates that must be true for the rule's implication to hold. self.conjugates = [] # Fix attributes self.parseInput() self.name = self.consequent.name # Construct the rule from the given ruleString def parseInput(self) : # First, fix the consequent. It is the last element of the input string split by the implies character " => " (spaces intended). consequentString = self.ruleString.split(" => ")[-1] self.consequent = Predicate(consequentString) # Now parse the conjugates conjugateString = self.ruleString.split(" => ")[0] conjugateList = conjugateString.split(" ^ ") for conj in conjugateList : conjPred = Predicate(conj) self.conjugates.append(conjPred) # Does a variable binding for the consequent and predicates def bind(self, val, var) : self.consequent.bindVar(val, var) for conj in self.conjugates : conj.bindVar(val, var)
def readInput(self): try: # Break up by line lines = self.inputFile.read().split('\n') for line in lines: line = line.strip('\r\n') # Get number of queries to make to the KB self.numQueries = int(lines[0]) # Read each query and store it as a predicate in self.queryList for i in range(1, self.numQueries + 1): newQuery = Predicate(lines[i]) self.queryList.append(newQuery) # Read in number of statements for the KB. self.numStatements = int(lines[self.numQueries + 1]) for j in range(self.numQueries + 2, self.numQueries + 2 + self.numStatements): statement = lines[j] # Check if statement is a rule or a fact if "=>" in statement: newRule = Rule(statement) self.kb.addRule(newRule) else: newFact = Predicate(statement) self.kb.addFact(newFact) except Exception as e: print "\nError reading input : ", e
class Rule(): def __init__(self, ruleString): # The string we parse the rule from. self.ruleString = ruleString # The predicate that is true if the rule's conjugate clauses are true. self.consequent = None # List of conjugated predicates that must be true for the rule's implication to hold. self.conjugates = [] # Fix attributes self.parseInput() self.name = self.consequent.name # Construct the rule from the given ruleString def parseInput(self): # First, fix the consequent. It is the last element of the input string split by the implies character " => " (spaces intended). consequentString = self.ruleString.split(" => ")[-1] self.consequent = Predicate(consequentString) # Now parse the conjugates conjugateString = self.ruleString.split(" => ")[0] conjugateList = conjugateString.split(" ^ ") for conj in conjugateList: conjPred = Predicate(conj) self.conjugates.append(conjPred) # Does a variable binding for the consequent and predicates def bind(self, val, var): self.consequent.bindVar(val, var) for conj in self.conjugates: conj.bindVar(val, var)
def p_ground_predicate(p): '''ground_predicate : LPAREN NAME constants_lst RPAREN | LPAREN NAME RPAREN''' if len(p) == 4: p[0] = Predicate(p[2]) elif len(p) == 5: p[0] = Predicate(p[2], p[3])
def whichBranch(self, branch, cond_expr): """ To be called from the process being executed, this function acts as instrumentation. branch can be either True or False, according to the branch taken after the last conditional jump. """ if not (isinstance(cond_expr,SymbolicType)): return # add both possible predicate outcomes to constraint (tree) p = Predicate(cond_expr, branch) p.negate() cneg = self.current_constraint.findChild(p) p.negate() c = self.current_constraint.findChild(p) if c is None: c = self.current_constraint.addChild(p) # Important: we are adding the new constraint # to the queue of the engine for later processing log.debug("New constraint: %s" % c) self.engine.addConstraint(c) if cneg is not None: # We've already processed both cneg.processed = True c.processed = True log.debug("Processed constraint: %s" % c) self.current_constraint = c
def test_repr(self): pred = Predicate('abc') self.assertEqual(repr(pred), "Predicate('abc')") pred = ~Predicate('abc') self.assertEqual(repr(pred), "~Predicate('abc')") pred = Predicate('abc', name='custom_name') self.assertEqual(repr(pred), "Predicate('abc', name='custom_name')")
def p_predicate(p): '''predicate : LPAREN NAME variables_lst RPAREN | LPAREN EQUALS VARIABLE VARIABLE RPAREN | LPAREN NAME RPAREN''' if len(p) == 4: p[0] = Predicate(p[2]) elif len(p) == 5: p[0] = Predicate(p[2], p[3]) elif len(p) == 6: p[0] = Predicate('=', [p[3], p[4]])
def add_to_domain(domain): ############################################ # Let's now create TYPES AND PREDICATES ############################################ domain.add_type('boxes') domain.add_pred('open', [('?x', 'boxes'), ('?z', 'block')]) domain.del_pred('handempty', 0) # print(repr(domain.operators[3])) ############################################ # Let's now create an OPERATOR ############################################ # print(domain.operators[3].precond) params = [Term.variable('?x', type='blocks'), Term.variable('?y', type='blocks')] precond=[] precond.append(Literal(Predicate('=', [Term.variable('?x'), Term.variable('?y')]), False)) precond.append(Literal(Predicate('on', [Term.variable('?x'), Term.variable('?y')]), True)) precond.append(Literal(Predicate('clear', [Term.variable('?x')]), True)) precond.append(Literal(Predicate('handempty', []), True)) # print(domain.operators[3].effects) effect=[] effect.append((1.0, Literal(Predicate('holding', [Term.variable('?x')]), True))) effect.append((1.0, Literal(Predicate('clear', [Term.variable('?y')]), True))) effect.append((1.0, Literal(Predicate('clear', [Term.variable('?x')]), False))) effect.append((1.0, Literal(Predicate('handempty', []), False))) effect.append((1.0, Literal(Predicate('on', [Term.variable('?x'), Term.variable('?y')]), False))) # print(repr(effect)) domain.add_action('pick-up-b', params, precond, effect)
def compile(problem, T, M, init_TL): """Returns new GroundProblem instance.""" # verify inputs assert isinstance (problem, GroundProblem), \ "The problem must be ground" assert isinstance(T, list) and \ all([isinstance(t, Literal) for t in T]), \ "Tags must be a list of Literals" assert isinstance(M, list) and \ all([isinstance(m, tuple) for m in M]),\ "Merges must be a list of tuples" assert isinstance(init_TL, list) and \ all([isinstance(e, tuple) for e in init_TL]),\ "Initial tag literals must be a list of tuples" fluents = [] fluent_dict = {} conversion_dict = {} for fluent in problem.fluents: l_name = "K%s" % fluent.name kl = Predicate(l_name, None, fluent.ground_args) fluents.append(kl) fluent_dict[hash(kl)] = kl conversion_dict[hash(fluent)] = kl l_not_name = "K_not_%s" % fluent.name k_notl = Predicate(l_not_name, None, fluent.ground_args) fluents.append(k_notl) fluent_dict[hash(k_notl)] = k_notl for tag in T: l_name = "K_%s_|_%s" % (fluent.name, tag.name) kl = Predicate(l_name, None, fluent.ground_args) fluents.append(kl) fluent_dict[hash(kl)] = kl l_not_name = "K_not_%s_|_%s" % (fluent.name, tag.name) k_notl = Predicate(l_not_name, None, fluent.ground_args) fluents.append(k_notl) fluent_dict[hash(k_notl)] = k_notl print "* New fluents *" for fluent in fluents: print fluent #TODO new initial state print "* New goal state *" goal_fluents = [] for arg in problem.goal.args: p = Primitive(conversion_dict[hash(arg.predicate)]) goal_fluents.append(p) print p
def parseInput(self): # First, fix the consequent. It is the last element of the input string split by the implies character " => " (spaces intended). consequentString = self.ruleString.split(" => ")[-1] self.consequent = Predicate(consequentString) # Now parse the conjugates conjugateString = self.ruleString.split(" => ")[0] conjugateList = conjugateString.split(" ^ ") for conj in conjugateList: conjPred = Predicate(conj) self.conjugates.append(conjPred)
def __init__(self, domain_file, problem_file, no_ground=False): """Create a new instance of GroundProblem. Inputs: domain_file: The location of the PDDL domain on disk problem_file: The location of the PDDL problem on disk no_ground: Whether to ground the PDDL or not Set to True if PDDL already grounded """ super(GroundProblem, self).__init__(domain_file, problem_file) if no_ground: print "no ground" # create fluents self.fluents = set([]) fluent_dict = {} for p in self.predicates: f = Predicate(p.name, None, p.args) fluent_dict[hash(f)] = f self.fluents.add(f) # create operators by changing all the formulas self.operators = set([]) for a in self.actions: # parameters stay the same param = a.parameters if a.precondition is None: precond = None else: a.precondition.to_ground(fluent_dict) precond = a.precondition if a.effect is None: effect = None else: a.effect.to_ground(fluent_dict) effect = a.effect if a.observe is None: observe = None else: p = Predicate(a.observe.name, None, a.observe.args) observe = fluent_dict[hash(p)] op = Operator(a.name, param, precond, observe, effect) self.operators.add(op) self.init.to_ground(fluent_dict) else: print "ground" self._ground()
def test_predicate_from_predicate(self): pred1 = Predicate('abc') pred2 = Predicate(pred1) self.assertIsNot(pred1, pred2, msg='should be different object') self.assertIs(pred1.obj, pred2.obj, msg='should keep original reference') self.assertEqual(pred1.matcher, pred2.matcher) self.assertEqual(pred1._inverted, pred2._inverted) from_inverted = Predicate(~Predicate('abc')) self.assertTrue(from_inverted._inverted)
def test_optional_name(self): pred1 = Predicate('abc') # <- No name arg provided. self.assertFalse(hasattr(pred1, '__name__')) pred2 = Predicate(pred1) # <- No name arg inherited from pred1. self.assertFalse(hasattr(pred1, '__name__')) pred3 = Predicate('abc', name='pred3_name') # <- Provides name. self.assertEqual(pred3.__name__, 'pred3_name') pred4 = Predicate(pred3) # <- Inherits name from pred3. self.assertEqual(pred4.__name__, 'pred3_name') pred5 = Predicate(pred3, name='pred5_name') # <- Overrides pred3 name. self.assertEqual(pred5.__name__, 'pred5_name')
def read_imp_arg_dataset(input_xml): xml_parser = etree.XMLParser(target=ImplicitArgumentTarget()) print '\nReading implicit argument dataset from: ' + input_xml + '\n' etree.parse(input_xml, xml_parser) annotations = [] for annotation in xml_parser.target.annotations: pred_node = Node.parse(annotation['node']) predicate = Predicate(pred_node) predicate.add_args_from_ia(annotation['arguments']) annotations.append(predicate) annotations.sort(key=lambda p: p.node.file_id) return annotations
def _predicate(self): # accept_negation=True sentence = self.sentence var = sentence[self.index] self.index+=1 assert sentence[self.index].upper() == Parser.IS, "expected 'is' word" self.index+=1 negate = sentence[self.index].upper() == Parser.NOT #f not accept_negation and negate: # raise Exception("predicate can't negate") if negate: self.index+=1 adj = sentence[self.index] self.index+=1 if var not in self.scope or adj not in self.scope: raise Exception('predicate sentence not well formed') var, adj = self.scope[var], self.scope[adj] if not isinstance(var, Variable): raise Exception('{0} must be a Variable'.format(var)) if not isinstance(adj, Adjective): raise Exception('{0} must be an Adjective'.format(adj)) predicate = Predicate(var, adj) return Not(predicate, self.cnorm) if negate else predicate
def build_predicates(self): assert len(self.all_instances) > 0 assert self.treebank_reader is not None assert self.nombank_reader is not None assert self.predicate_mapping is not None assert self.corenlp_reader is not None if len(self.all_predicates) > 0: log.warning('Overriding existing predicates') self.all_predicates = [] log.info('Building predicates') for instance in self.all_instances: predicate = Predicate.build(instance) predicate.set_pred(self.predicate_mapping[str( predicate.pred_pointer)]) self.all_predicates.append(predicate) log.info('Checking explicit arguments with Nombank instances') for predicate in self.all_predicates: nombank_instance = self.nombank_reader.search_by_pointer( predicate.pred_pointer) predicate.check_exp_args(nombank_instance, add_missing_args=False, remove_conflict_imp_args=False, verbose=False) log.info('Parsing all implicit and explicit arguments') for predicate in self.all_predicates: predicate.parse_args( self.treebank_reader, self.corenlp_reader, include_non_head_entity=self.include_non_head_entity) log.info('Done')
def _predicate(antecedent, index, scope, accept_negation=True): """ Gets a predicate (variable is adjective) :param antecedent: if-part or then-part of a string-rule :param index: index of string to parse :param scope: scope dictionary :param accept_negation: True if we allow variable is NOT adjective """ initial_pos = index var = antecedent[index] index += 1 assert antecedent[index] == IS, "expected 'is' word" index += 1 negate = antecedent[index] == NOT if not accept_negation and negate: raise Exception("predicate can't negate") if negate: index += 1 adj = antecedent[index] index += 1 var, adj = scope.get(var), scope.get(adj) if not (var and adj): raise Exception('predicate sentence not well formed') predicate = Predicate(var, adj) return predicate, index - initial_pos
def __init__(self, p, h): self.problem = p self.initial = p.init # self.actions = p.actions self.goal = p.goal # self.type_to_obj = p.type_to_obj # self.objects = p.obj_to_type self.fluents = p.fluents self.operators = p.operators self.precs = {} self.effects = {} self.observes = {} self.adds_fluent = {}#use self.dels_fluent = {}#use self.horizon = h self.j = 1 self.logic = Logic() self.jk = [] self.fluent_lits = [] self.op_lits = [] self.djk_lits = [] self.all_literals = [] self.initial_lits = None self.subproblems = [] self.init_known = None self.lit_dict = {} self.lit_lookup = {} self.dg_atom = Predicate('DG', None, []) self.fluents.add(self.dg_atom) self.end_atom = Operator('End', [], self.goal, None, And([Primitive(self.dg_atom)])) self.operators.add(self.end_atom)
def visit_Function(self, function, data=TreeData()): predicate = Predicate(function['name'], len(function['arguments'])) if data.head: self.head_predicates.add(predicate) else: self.body_predicates.add(predicate) return super(ASTPredicateMapper, self).visit_children(function, data)
def test_find_max_eases(): cov_table = CoverageTable( SourceCode( "# find_max import sys x = int(sys.argv[1]) y = int(sys.argv[2]) z = int(sys.argv[3]) if x > y: if x > z: print(" "x) else: print(z) else: if y < z: print(z) else: print(y)")) P = Predicate(2, 9, "if y > z", True, False) assert cov_table.calculate_ease(P) == 1 assert cov_table.calculate_improved_ease(P) == 1
def from_tokens(cls, pred_token, neg, subj_token, obj_token, pobj_token_list): pred = Predicate.from_token(pred_token, neg=neg) subj = Argument.from_token(subj_token) \ if subj_token is not None else None obj = Argument.from_token(obj_token) if obj_token is not None else None pobj_list = [(prep, Argument.from_token(pobj)) for prep, pobj in pobj_token_list] return cls(pred, subj, obj, pobj_list)
def to_predicate(self, node, f='predicate', map=None): """ Create a predicate out of this PDDL_Tree node. For now, will assume this makes sense. """ if 'AK{}' == node.name: assert 1 == len( node.children), "Error: AK{} had more than one child" pred = self.to_predicate(node.children[0], f, map) pred.always_known = True return pred args = PDDL_Utils.read_type(node) # change the type if there is only 1 type if len(self.types) == 1: t_args = args t = list(self.types)[0] args = [] for arg in t_args: if arg[1] != t: args.append((arg[0], t)) else: args.append(arg) # here is where the map comes in... if map is None: if 'predicate' == f: return Predicate(node.name, args) elif 'fluent' == f: return Predicate(node.name, args=None, ground_args=args) else: new_args = [] for v, t in args: if v in map: new_args.append((v, map[v])) else: new_args.append((v, t)) if 'predicate' == f: return Predicate(node.name, new_args) elif 'fluent' == f: return Predicate(node.name, args=None, ground_args=new_args)
def identify_output_forms_aggregate_form2_input(self): """ Identify whether rule is candidate for rewriting from the aggregate form 2 into any other form. Forms non-aggregate and inequality must satisfy the additional condition that the counting predicate does not depend on the head predicates Returns list of IDs of valid output forms. TODO: Handle when |Y|>0 TODO: Verification of rewriting for all sets of rewritable aggregate literals within a rule, and recording of this verification """ aggregate_data = self.aggregate_counter.rewritable_aggregate_data[ constants.AGGR_FORM2] if len(aggregate_data) == 0: return [] # no valid forms # TODO: Verification and recording of EACH possible aggregate literal aggregate_data_tuple = aggregate_data[0] counting_variable = aggregate_data_tuple[0] counting_function = aggregate_data_tuple[1] guard_value = aggregate_data_tuple[2] aggregate_literal = aggregate_data_tuple[3] self.ag_counting_function = counting_function self.ag_guard_value = guard_value if guard_value < 2: # aggregate guard less than 2 return [] # no valid forms check_rule = ASTCopier().deep_copy(self.rule) # TODO: Fix this check. Not working in tests/testInequalityAggregateInput.lp if self.counting_vars_used_elsewhere(check_rule, [aggregate_literal], [str(counting_variable)]): return [] # record counting literal and variable information for performing rewriting later # TODO: New way of recording counting literals and variables self.counting_literals = [aggregate_literal] self.counting_variables = [str(counting_variable)] counting_predicate = Predicate(counting_function['name'], len(counting_function['arguments'])) if self.circular_dependencies(counting_predicate): valid_forms = [constants.AGGR_FORM3] else: valid_forms = [ constants.NON_AGGR_FORM, constants.AGGR_FORM1, constants.AGGR_FORM3 ] return valid_forms
def parseInput(self) : # First, fix the consequent. It is the last element of the input string split by the implies character " => " (spaces intended). consequentString = self.ruleString.split(" => ")[-1] self.consequent = Predicate(consequentString) # Now parse the conjugates conjugateString = self.ruleString.split(" => ")[0] conjugateList = conjugateString.split(" ^ ") for conj in conjugateList : conjPred = Predicate(conj) self.conjugates.append(conjPred)
def test_triangle_eases(): cov_table = CoverageTable( SourceCode( "# tri import sys i = int(sys.argv[1]) j = int(sys.argv[2]) k = int(sys.argv[3]) if i <= 0 or j <= 0 or k <= 0: " "print(4) exit() tri = 0 if i == j: tri += 1 if i == k: tri += 2 if j == k: tri += 3 if tri == 0: if i + j < k or " "j + k < i or k + i < j: tri = 4 else: tri = 1 print(tri) exit() if tri > 3: tri = 3 elif tri == 1 and i + j > k: " "tri = 2 elif tri == 2 and i + k > j: tri = 2 elif tri == 3 and j + k > i: tri = 2 else: tri = 4 print(tri) exit(" ")")) P = Predicate(8, 30, "if tri == 1 and i + j > k", True, False) assert cov_table.calculate_ease(P) == 3 assert cov_table.calculate_improved_ease(P) == 6
def isSubsumed(self, my_state, old_state, old_constraint): if not set(my_state) == set(old_state): return my_concretes = { k: v for k, v in my_state.iteritems() if not isinstance(v, SymbolicType) } old_concretes = { k: v for k, v in old_state.iteritems() if not isinstance(v, SymbolicType) } # all purely concrete variables must be equal for var in my_concretes.viewkeys() & old_concretes.viewkeys(): if my_concretes[var] != old_concretes[var]: return # assert that the states must be equal my_constraint = self.current_constraint state_vars = set() for var in set(my_state): # use a variable name that is illegal in python state_var = var + "$" state_sym_var = SymbolicInteger(state_var, 32) state_vars.add(state_var) my_p = Predicate(state_sym_var == my_state[var], True) my_constraint = Constraint(my_constraint, my_p) old_p = Predicate(state_sym_var == old_state[var], True) old_constraint = Constraint(old_constraint, old_p) (_, my_asserts, _) = my_constraint.buildZ3Asserts() (_, old_asserts, old_sym_vars) = old_constraint.buildZ3Asserts() old_inputs = [ v[1] for k, v in old_sym_vars.iteritems() if not k in state_vars ] subsumed = Implies(And(my_asserts), Exists(old_inputs, And(old_asserts))) return z3_wrap.findCounterexample([], subsumed, []) == None
def __init__(self, s ): head, body = s.split(":-") self.head_pred = Predicate(head) self.body_preds = [] j = 0 while True: #i = body.find(')', j) i = body.find(',',j) if '(' in body[j:i]: i = body.find(')',j) + 1 t = Predicate(body[j:i]) self.body_preds.append( t ) j = body.find(',', i) if j == -1: break else: j += 1
def get_projection_predicate(self, counting_function, counting_var, arity): """ Creates a predicate for a new function with a name following the pattern: COUNTINGFUNCTIONNAME_proj_COUNTINGVAR# where # is initially empty. If a collision occurs with other function names in the current operating file, then # is 1. If there is still a collision, # is incremented until there is none Returns the new projection predicate """ new_predicate = Predicate( counting_function['name'] + '_project_' + str(counting_var), arity) iteration = 1 while new_predicate in self.base_transformer.in_predicates or \ new_predicate in self.base_transformer.new_predicates: new_predicate.name = new_predicate.name + str(iteration) iteration += 1 self.base_transformer.new_predicates.add(new_predicate) return new_predicate
def whichBranch(self, branch, cond_expr): """ To be called from the process being executed, this function acts as instrumentation. branch can be either True or False, according to the branch taken after the last conditional jump. """ if not (isinstance(cond_expr, SymbolicType)): return # add both possible predicate outcomes to constraint (tree) p = Predicate(cond_expr, branch) p.negate() cneg = self.current_constraint.findChild(p) p.negate() c = self.current_constraint.findChild(p) if c is None: c = self.current_constraint.addChild(p) # Important: we are adding the new constraint # to the queue of the engine for later processing log.debug("New constraint: %s" % c) self.engine.addConstraint(c) if cneg is not None: # We've already processed both cneg.processed = True c.processed = True log.debug("Processed constraint: %s" % c) self.current_constraint = c
def whichBranch(self, branch, cond_expr): """ To be called from the process being executed, this function acts as instrumentation. branch can be either True or False, according to the branch taken after the last conditional jump. """ if not (isinstance(cond_expr,SymbolicType)): return if self.engine.cutting: stats.pushProfile("subsumption checking") # Important: this call may jump out of this function (and the # whole execution) by throwing an EndExecutionThrowable self.tryCut() stats.popProfile() # add both possible predicate outcomes to constraint (tree) p = Predicate(cond_expr, branch) p.negate() cneg = self.current_constraint.findChild(p) p.negate() c = self.current_constraint.findChild(p) if c is None: c = self.current_constraint.addChild(p) # Important: we are adding the new constraint # to the queue of the engine for later processing log.debug("New constraint: %s" % c) self.engine.addConstraint(c) if cneg is not None: # We've already processed both cneg.processed = True c.processed = True log.debug("Processed constraint: %s" % c) self.current_constraint = c if not self.engine.selected or self.engine.selected is cneg: self.target_reached = True
def add_pred(self, name, args): args2 = [] for a in args: if type(a) is tuple: # name of variable with type arg = Term(name=a[0], type=a[1]) elif type(a) is str: # a constant value arg = Term(value=a[0]) else: print( 'ERROR: something went wrong, incorrect argument for predicate {}' .format(name)) args2.append(arg) self._predicates.append(Predicate(name, args2))
def test_general(): cov_table = CoverageTable( SourceCode( "# tri import sys i = int(sys.argv[1]) j = int(sys.argv[2]) k = int(sys.argv[3]) if i <= 0 or j <= 0 or k <= 0: " "print(4) exit() tri = 0 if i == j: tri += 1 if i == k: tri += 2 if j == k: tri += 3 if tri == 0: if i + j < k or " "j + k < i or k + i < j: tri = 4 else: tri = 1 print(tri) exit() if tri > 3: tri = 3 elif tri == 1 and i + j > k: " "tri = 2 elif tri == 2 and i + k > j: tri = 2 elif tri == 3 and j + k > i: tri = 2 else: tri = 4 print(tri) exit(" ")")) P = Predicate(1, 8, "if i <= 0 or j <= 0 or k <= 0", True, True) assert cov_table.get_target_branch().program_line == 20 c = cov_table.pdg.predicate_to_constraint(P, 1) values = [9, 8, 2, 0] assert c.to_fitness(values) == 4.0