Пример #1
0
def process():
    varA = Symbol("A")
    varB = Symbol("B")
    f = And(varA, Not(varB))
    print(f)
    print(is_sat(f))

    hello = [Symbol(s, INT) for s in "hello"]
    world = [Symbol(s, INT) for s in "world"]

    letters = set(hello + world)

    domains = And(And(LE(Int(1), l),
                      GE(Int(10), l)) for l in letters)
    print(domains,'domain')
    sum_hello = Plus(hello)
    sum_world = Plus(world)

    problem = And(Equals(sum_hello, sum_world),
                  Equals(sum_hello, Int(36)))

    formula = And(domains, problem)

    print("Serialization of the formula:")
    print(formula)
    print(formula.serialize())
    print(is_sat(formula))
    print(get_model(formula))
Пример #2
0
    def _get_param_assignments(self, model, time, parameters, monotonic=True):
        p_ass = []

        fwd = False

        for p in parameters:
            p_time = model[TS.get_ptimed(p, 0)]
            if p.symbol_type() == BOOL:
                if monotonic:
                    if p_time == TRUE():
                        p_ass.append(p)
                else:
                    p_ass.append(p if p_time == TRUE() else Not(p))
            else:
                p_ass.append(EqualsOrIff(p, p_time))

        p_ass = And(p_ass)
        self.region = simplify(Or(self.region, p_ass))

        if self.models is None:
            self.models = []
        self.models.append((model, time))

        Logger.msg("+", 0, not (Logger.level(1)))
        self.cs_count += 1
        Logger.log(
            "Found assignment \"%s\"" % (p_ass.serialize(threshold=100)), 1)

        return (p_ass, False)
Пример #3
0
    def _get_param_assignments(self, model, time, parameters, monotonic=True):
        p_ass = []

        fwd = False

        for p in parameters:
            # search the trace for any enabled faults
            ever_true = False
            for t in range(time + 1):
                p_time = model[TS.get_ptimed(p, 0)]
                if p.symbol_type() == BOOL:
                    if p_time == TRUE():
                        ever_true = True
                        break

            if ever_true:
                p_ass.append(p)
            elif not monotonic:
                p_ass.append(EqualsOrIff(p, FALSE()))

        p_ass = And(p_ass)
        self.region = simplify(Or(self.region, p_ass))

        if self.models is None:
            self.models = []
        self.models.append((model, time))

        Logger.msg("+", 0, not (Logger.level(1)))
        self.cs_count += 1
        Logger.log(
            "Found assignment \"%s\"" % (p_ass.serialize(threshold=100)), 1)

        return (p_ass, False)
Пример #4
0
    def test_threshold_printing(self):
        x = Symbol("x")
        f = And(x,x)
        for _ in xrange(10):
            f = And(f,f)

        short_f_str = str(f)
        long_f_str = f.serialize()
        self.assertTrue(len(short_f_str) < len(long_f_str))
Пример #5
0
    def test_threshold_printing(self):
        x = Symbol("x")
        f = And(x, x)
        for _ in range(10):
            f = And(f, f)

        short_f_str = str(f)
        long_f_str = f.serialize()
        self.assertTrue(len(short_f_str) < len(long_f_str))
Пример #6
0
class TransitionSystem:
    """ Symbolic transition system.
    All the objects are from PySMT (e.g. Symbols, formulas...)

    The TS is a tuple < state_var, init, trans >

    """
    def __init__(self, env=None, helper=None):
        if env is None:
            self.env = get_env()
            self.helper = Helper(self.env)
        else:
            self.env = env
            self.helper = helper
            assert (self.helper.env == env)

        # internal representation of the transition system
        self.state_vars = set()
        self.var_types = {}
        self.init = TRUE_PYSMT()
        self.trans = TRUE_PYSMT()
        self.final = FALSE_PYSMT()

    def add_var(self, var):
        self.state_vars.add(var)

    def product(self, other_ts):
        """ Computes the synchronous product of self with other_ts,
        storing the product in self.

        Given TS1 = <V1, I1, T1> and TS2 = <V2, I2, T2>
        the product is the transition system
        TSP = <V1 union V2, I1 and I2, T1 and T2>

        (V are the state variables, I is the initial condition, T the transition relation)
        """

        self.state_vars.update(other_ts.state_vars)
        self.init = And(self.init, other_ts.init)
        self.trans = And(self.trans, other_ts.trans)

    def __repr__(self):
        """ Not efficient, need to use a buffer..."""

        res = "State vars: "
        for v in self.state_vars:
            res += ", %s" % v
        res += "\nINIT: "
        res += str(self.init.serialize())
        res += "\nTRANS: "
        res += str(self.trans.simplify().serialize())

        return res
Пример #7
0
def generate_flipped_path(ppc):
    """
    This function will check if a selected path is feasible
           ppc : partial path conditoin at chosen control loc
           chosen_control_loc: branch location selected for flip
           returns satisfiability of the negated path
    """
    parser = SmtLibParser()
    script = parser.get_script(cStringIO(ppc))
    formula = script.get_last_formula()
    prefix = formula.arg(0)
    constraint = formula.arg(1)
    new_path = And(prefix, Not(constraint))

    assert str(new_path.serialize()) != str(formula.serialize())
    return new_path
Пример #8
0
def select_new_input(patch_list=None):
    """
    This function will select a new path for the next concolic execution and generate the inputs that satisfies the path
           log_path : log file for the previous concolic execution that captures PPC
           project_path: project path is the root directory of the program to filter PPC from libraries
    """
    logger.info("generating new input for new path")
    global list_path_explored, list_path_inprogress, count_discovered

    # input_file_byte_list = list()
    # input_file_stat_byte_list = list()

    generated_path_list = values.LIST_GENERATED_PATH
    var_expr_map = reader.collect_symbolic_expression(values.FILE_EXPR_LOG)

    # generated_path_list = generate_new_symbolic_paths(constraint_list)
    # list_path_explored = list(set(list_path_explored + current_path_list))
    selected_patch = None
    patch_constraint = TRUE
    new_path_count = 0

    for (control_loc, generated_path,
         ppc_len), arg_list, poc_path, bin_path in generated_path_list:
        path_str = str(generated_path.serialize())
        if path_str not in (list_path_detected + list_path_explored):
            reach_patch_loc = 100 - path_str.count("angelic!")
            reach_obs_loc = 100 - path_str.count("obs!")
            ppc_len = 10000 - ppc_len
            list_path_inprogress.append(
                (control_loc, generated_path, ppc_len, reach_patch_loc,
                 reach_obs_loc, arg_list, poc_path, bin_path))
            list_path_detected.append(str(generated_path.serialize()))
            new_path_count = new_path_count + 1

    count_discovered = count_discovered + new_path_count
    emitter.highlight("\tidentified " + str(new_path_count) + " new path(s)")
    emitter.highlight("\ttotal discovered: " + str(count_discovered) +
                      " path(s)")
    emitter.highlight("\ttotal remaining: " + str(len(list_path_inprogress)) +
                      " path(s)")
    emitter.highlight("\ttotal infeasible: " + str(len(list_path_infeasible)) +
                      " path(s)")
    if not list_path_inprogress:
        emitter.note("\t\tCount paths explored: " +
                     str(len(list_path_explored)))
        emitter.note("\t\tCount paths remaining: " +
                     str(len(list_path_inprogress)))
        return None, None, patch_list, None, None, None
    values.LIST_GENERATED_PATH = []
    patch_constraint = None
    selected_new_path = ""
    selected_control_loc = ""
    if patch_list:
        while not patch_constraint:
            emitter.normal("\tfinding a feasible path for current patch set")
            if not list_path_inprogress:
                emitter.note("\t\tCount paths explored: " +
                             str(len(list_path_explored)))
                emitter.note("\t\tCount paths remaining: " +
                             str(len(list_path_inprogress)))
                return None, None, patch_list, None, None, None
            selected_new_path, selected_control_loc, argument_list, poc_path, bin_path = select_new_path_condition(
            )
            patch_constraint = select_patch_constraint_for_input(
                patch_list, selected_new_path)
            if patch_constraint:
                list_path_explored.append(str(selected_new_path.serialize()))
                if is_sat(And(selected_new_path, patch_constraint)):
                    selected_new_path = And(selected_new_path,
                                            patch_constraint)
                else:
                    emitter.warning("\t[warning] no model generated")
            else:
                list_path_infeasible.append(str(selected_new_path.serialize()))
    else:
        selected_new_path, selected_control_loc, argument_list, poc_path, bin_path = select_new_path_condition(
        )
        list_path_explored.append(str(selected_new_path.serialize()))
    emitter.highlight("\tSelected control location: " + selected_control_loc)
    emitter.highlight("\tSelected path: " + str(selected_new_path))
    emitter.highlight("\tSelected binary: " + str(bin_path))
    emitter.highlight("\tSelected arguments for mutation: " +
                      str(argument_list))
    if poc_path:
        emitter.highlight("\tSelected seed file: " + str(poc_path))
    input_arg_list, input_var_list = generator.generate_new_input(
        selected_new_path, argument_list, poc_path)
    if input_arg_list is None and input_var_list is None:
        return None, None, patch_list, argument_list, poc_path, bin_path
    return input_arg_list, input_var_list, patch_list, argument_list, poc_path, bin_path
Пример #9
0
def findNashEquilibria(intents, queries, tuples, matches, strict, minReward, minRewardValue):
	userStrategy = dict()
	dbmsStrategy = dict()
	nashUserStrategy = dict()
	nashdbmsStrategy = dict()
	rewardMatrix = constructRewardMatrix(intents, tuples, matches)
	letters = set()
	nashRestrictions = list()

	#User Strategy matrix, each cell holds a variable for the SMT
	for intent in intents:
		if intent not in userStrategy:
			userStrategy[intent] = dict()
		for query in queries:
			userStrategy[intent][query] = Symbol('User['+intent + '][' + query + ']', REAL)
			letters.add(userStrategy[intent][query])
			
	#DBMS Strategy matrix, each cell holds a variable for the SMT
	for query in queries:
		if query not in dbmsStrategy:
			dbmsStrategy[query] = dict()
		for tup in tuples:
			dbmsStrategy[query][tup] = Symbol('DBMS['+query + '][' + tup + ']', REAL)
			letters.add(dbmsStrategy[query][tup])
	
	#We create a strategy for each move that can be made from the current position
	#This means that only a single row changes, the rest of the rows are the same as the strategies above
	#There also needs to be a strategy for each cell and a restriction only on the cell that this strategy belongs to
	for intent in intents:
		nashUserStrategy[intent] = dict()
		for query in queries:
			nashUserStrategy[intent][query] = copy.deepcopy(userStrategy)
			for query2 in copy.deepcopy(queries):
				nashUserStrategy[intent][query][intent][query2] = Symbol('Nash'+str(len(nashUserStrategy))+str(len(nashUserStrategy[intent]))+'User['+intent + '][' + query2 + ']', REAL)
				letters.add(nashUserStrategy[intent][query][intent][query2])
				if query == query2:
					nashRestrictions.append(NotEquals(nashUserStrategy[intent][query][intent][query2], userStrategy[intent][query2]))

	#Same here except for DBMS
	for query in queries:
		nashdbmsStrategy[query] = dict()
		for tup in tuples:
			nashdbmsStrategy[query][tup] = copy.deepcopy(dbmsStrategy)
			for tup2 in tuples:
				nashdbmsStrategy[query][tup][query][tup2] = Symbol('Nash'+str(len(nashdbmsStrategy))+str(len(nashdbmsStrategy[query]))+'DBMS['+query + '][' + tup2 + ']', REAL)
				letters.add(nashdbmsStrategy[query][tup][query][tup2])
				if tup == tup2:
					nashRestrictions.append(NotEquals(nashdbmsStrategy[query][tup][query][tup2], dbmsStrategy[query][tup2]))

	#Tells the range of values, for now set to Pure strategy so [0,1]
	domains = And([Or(Equals(l, Real(0)), Equals(l, Real(1))) for l in letters])
	if DEBUG:
		print('\nDomain Serialization: ')	
		print(domains)

	#Adds restriction that no value from the nashStrategies can be the same as the corresponding cell they are testing. This ensures a 'move'
	nashProblem = And(nashRestrictions)
	if DEBUG:
		print('\nNash Domain Serialization: ')
		print(nashProblem)

	#This is doing all the row stochastic stuff
	allEquals = []
	#Adds each row of the user strategy
	stochasticMatrixUser = list()
	stochasticMatrixNashUser = list()
	for intent in intents:
		stochasticMatrixUser.append(Plus(userStrategy[intent].values()))
		for query in queries:
			allEquals.append(Equals(Plus(nashUserStrategy[intent][query][intent].values()), Real(1)))
			
	#Adds each row of the DBMS strategy
	stochasticMatrixdbms = list()
	stochasticMatrixNashdbms = list()
	for query in queries:
		stochasticMatrixdbms.append(Plus(dbmsStrategy[query].values()))
		for tup in tuples:
			allEquals.append(Equals(Plus(nashdbmsStrategy[query][tup][query].values()), Real(1)))
	
	#Checks the rows to make sure that the strategies are row stochastic
	stochUserEquals = [Equals(x, Real(1)) for x in stochasticMatrixUser]
	stochdbmsEquals = [Equals(x, Real(1)) for x in stochasticMatrixdbms]
	allEquals += stochUserEquals + stochdbmsEquals

	#Stochastic problem
	stochasticProblem = And(set(allEquals))
	if DEBUG:
		print('\nStochastic Serialization: ')
		print(stochasticProblem.serialize())
	
	
	
	#Uses Formula 1 from my paper to calculate the payoff, assuming uniform prior.
	reward = list()
	for intent in intents:
		for query in queries:
			for tup in tuples:
				reward.append(Times(Real(1/len(intents)), userStrategy[intent][query], dbmsStrategy[query][tup], rewardMatrix[intent][tup]))

	#Reward problem, requires a minimum reward. May not always be possible to achieve this reward
	rewardProblem = GE(Plus(reward), Real(minRewardValue))
	if DEBUG:
		print('\nReward Serialization: ')	
		print(rewardProblem)

	nashRewardUser = dict()
	nashRewardDbms = dict()

	#Again using Formula 1, but now we are creating one for each move to make sure that it is less than (Strict Nash) or less than or equal (Nash)
	for strat in nashUserStrategy:
		if strat not in nashRewardUser:
			nashRewardUser[strat] = dict()
		for strat2 in nashUserStrategy[strat]:
			if strat2 not in nashRewardUser[strat]:
				nashRewardUser[strat][strat2] = list()
			for intent in intents:
				for query in queries:
					for tup in tuples:
						nashRewardUser[strat][strat2].append(Times(Real(1/len(intents)), nashUserStrategy[strat][strat2][intent][query], dbmsStrategy[query][tup], rewardMatrix[intent][tup]))

	#Same, but for DBMS side. Just separated them to make it cleaner
	for strat in nashdbmsStrategy:
		if strat not in nashRewardDbms:
			nashRewardDbms[strat] = dict()
		for strat2 in nashdbmsStrategy[strat]:
			if strat2 not in nashRewardDbms[strat]:
				nashRewardDbms[strat][strat2] = list()
			for intent in intents:
				for query in queries:
					for tup in tuples:
						nashRewardDbms[strat][strat2].append(Times(Real(1/len(intents)), userStrategy[intent][query], nashdbmsStrategy[strat][strat2][query][tup], rewardMatrix[intent][tup]))

	if DEBUG:
		print('\nReward Serialization Nash: ')
	
	#Check user nash
	#This is where we actually perform the checking to see if it is less than or equal (or prep to be added to the solver)
	userNash = list()
	for intent in intents:
		for query in queries:
			if strict:
				userNash.append(Implies(NotEquals(nashUserStrategy[intent][query][intent][query], userStrategy[intent][query]), LT(Plus(nashRewardUser[intent][query]), Plus(reward))))
			else:
				userNash.append(Implies(NotEquals(nashUserStrategy[intent][query][intent][query], userStrategy[intent][query]), LE(Plus(nashRewardUser[intent][query]), Plus(reward))))
						
	userNashProblem = And(userNash)

	if DEBUG:
		print(userNashProblem.serialize())

	#Check dbms nash
	dbmsNash = list()
	for query in queries:
		for tup in tuples:
			if strict:
				dbmsNash.append(Implies(NotEquals(dbmsStrategy[query][tup], nashdbmsStrategy[query][tup][query][tup]), LE(Plus(nashRewardDbms[query][tup]), Plus(reward))))
			else:
				dbmsNash.append(Implies(NotEquals(dbmsStrategy[query][tup], nashdbmsStrategy[query][tup][query][tup]), LE(Plus(nashRewardDbms[query][tup]), Plus(reward))))

	dbmsNashProblem = And(dbmsNash)

	if DEBUG:
		print(dbmsNashProblem.serialize())

	#Add each component to the solver and test as we go
	#PySMT has another method where you just AND everything together, but they suggest
	#this method as it looks cleaner and you can see which one fails, if any
	with Solver(name="z3") as solver:
		solver.add_assertion(domains)
		if not solver.solve():
			print('No solultion available (domains)')
			return
		print('Can satisfy domains')

		solver.add_assertion(nashProblem)
		if not solver.solve():
			print('No solultion available (nash restrictions)')
			return
		print('Can satisfy nash domains')
		
		solver.add_assertion(stochasticProblem)
		if not solver.solve():
			print('No sulution available (stochastic)')
			return
		print('Can satisfy stochastic')
		
		if minReward:
			solver.add_assertion(rewardProblem)
			if not solver.solve():
				print('No solution available')
				return
			print('Can satisfy minimum reward')
		
		solver.add_assertion(userNashProblem)
		if not solver.solve():
			print('No solution available (user nash)')
			return

		print('Can satisfy user nash')

		solver.add_assertion(dbmsNashProblem)
		if not solver.solve():
			print('No solution available (dbms nash)')
			return
		print('Can satisfy dbms nash')

		#Print out the final assignments if it made it this far, as a solution exists
		for intent in intents:
			for query in queries:
				print("%s = %s" % (userStrategy[intent][query], solver.get_value(userStrategy[intent][query])))

		for query in queries:
			for tup in tuples:
				print("%s = %s" % (dbmsStrategy[query][tup], solver.get_value(dbmsStrategy[query][tup])))
Пример #10
0
def iterate_to_find_satisfiable_solution(features, feature_implimentation_time,
                                         dependencies, sequential, developers,
                                         feature_developer, parallel_tasks,
                                         end_time):

    feature_time_map = {}
    i = 1
    for fe in features:
        feature_time_map[fe] = {
            'EndTime': Symbol('E' + str(i), INT),
            'StartTime': Symbol('S' + str(i), INT),
            'Duration': Int(feature_implimentation_time[i - 1])
        }
        i += 1

    b_greater = And(
        And(GE(feature_time_map[fe]['EndTime'], Int(0)),
            GE(feature_time_map[fe]['StartTime'], Int(0))) for fe in features)

    b_impli_time = And(
        Equals(
            Minus(feature_time_map[l]['EndTime'], feature_time_map[l]
                  ['StartTime']), feature_time_map[l]['Duration'])
        for l in features)

    b_dependencies = And(
        GE(feature_time_map[depe[1]]['StartTime'], feature_time_map[depe[0]]
           ['EndTime']) for depe in dependencies)

    b_sequential = And(
        Or(
            GE(feature_time_map[seq[1]]['StartTime'], feature_time_map[seq[0]]
               ['EndTime']),
            GE(feature_time_map[seq[0]]['StartTime'], feature_time_map[seq[1]]
               ['EndTime'])) for seq in sequential)

    developer_feature_imp = {}
    for fet_dev in feature_developer:
        developer_feature_imp.setdefault(fet_dev[1], []).append(fet_dev[0])

    and_relation = []
    for val in developer_feature_imp.values():
        if len(val) > 1:
            for comb in combinations(val, 2):
                and_relation.append(
                    Or(
                        GE(feature_time_map[comb[1]]['StartTime'],
                           feature_time_map[comb[0]]['EndTime']),
                        GE(feature_time_map[comb[0]]['StartTime'],
                           feature_time_map[comb[1]]['EndTime'])))
    b_dev_pararale = And(and_relation)
    and_parallel = []
    for val in parallel_tasks:
        and_parallel.append(
            And(
                LE(feature_time_map[val[0]]['StartTime'],
                   feature_time_map[val[1]]['StartTime']),
                GE(feature_time_map[val[0]]['EndTime'],
                   feature_time_map[val[1]]['StartTime'])))

    b_parallel = And(and_parallel)

    print('++++++++++++++Conditions++++++++++++++++')
    print('Start and End times should be grater than zero : ', b_greater)
    print('Difference between end and start times : ', b_impli_time)
    print('Some features should be implimented first : ', b_dependencies)
    print('Some features can not be executed parallelly : ', b_sequential)
    print('Some features need specific developers : ', b_dev_pararale)
    print('Some features need to be started before ending some features : ',
          b_parallel)

    print('++++++++++++++Release Dates++++++++++++++++')
    end_time = 1
    max_end_time = sum(feature_implimentation_time)
    sloved = False
    for end in tqdm(range(max_end_time),
                    'running binary search to find shortest release date'):

        b_end_time = And(
            LE(fe['EndTime'], Int(end_time))
            for fe in feature_time_map.values())
        formula = And(b_greater, b_impli_time, b_dependencies, b_sequential,
                      b_dev_pararale, b_end_time, b_parallel)

        if is_sat(formula):
            print('\n' + 'You have to spend at least', end_time,
                  'days to finish your next release')
            print('Therefore, the closest release date is :',
                  (datetime.today() +
                   timedelta(end_time)).strftime('%d/%m/%Y'))
            for key, val in feature_time_map.items():
                print(
                    'Feature', key, ', Start Date :',
                    (datetime.today() + timedelta(
                        get_model(formula)[val['StartTime']].constant_value())
                     ).strftime('%d/%m/%Y'), '-> End Date : ',
                    (datetime.today() + timedelta(
                        get_model(formula)[val['EndTime']].constant_value())
                     ).strftime('%d/%m/%Y'))
            sloved = True
            break
        end_time += 1
    if sloved == False:
        print("This problem is not solvable")

    # print(b_devlopers)
    # print(is_sat(b_devlopers))

    return len(formula.serialize()), 'S' if is_sat(formula) else 'U'
Пример #11
0
class System():
    def __init__(self):
        self.reset()

    def reset(self):
        self._init = set()
        self._axiom = set()
        self._prop = set()
        self._vars = set()
        self._axiomvars = set()
        self._states = set()
        self._nexstates = set()
        self._globals = set()
        self._le = set()
        self._others = set()
        self._pre2nex = dict()
        self._nex2pre = dict()
        self._trel = None
        self._actions = list()
        self._action_en2idx = dict()
        self._predicates = dict()
        self._helpers = dict()
        self._infers = dict()
        self._definitions = dict()
        self._definitionMap = dict()

    def copy(self, rhs):
        self._init = rhs._init
        self._axiom = rhs._axiom
        self._prop = rhs._prop
        self._vars = rhs._vars
        self._axiomvars = rhs._axiomvars
        self._states = rhs._states
        self._nexstates = rhs._nexstates
        self._globals = rhs._globals
        self._le = rhs._le
        self._others = rhs._others
        self._pre2nex = rhs._pre2nex
        self._nex2pre = rhs._nex2pre
        self._trel = rhs._trel
        self._actions = rhs._actions
        self._action_en2idx = rhs._action_en2idx
        self._predicates = rhs._predicates
        self._helpers = rhs._helpers
        self._infers = rhs._infers
        self._definitions = rhs._definitions
        self._definitionMap = rhs._definitionMap

    def add_helper(self, formula, name):
        self._helpers[formula] = "user_" + name

    def add_pred(self, formula, name):
        args = []
        types = []
        if formula.is_quantifier():
            for a in formula.quantifier_vars():
                args.append(a)
                types.append(a.symbol_type())
            formula = formula.arg(0)
        ft = FunctionType(BOOL, tuple(types))
        f = Symbol(name, ft)
        lhs = Function(f, args)
        self._predicates[lhs] = formula

    def add_init(self, formula):
        self._init.add(formula)

    def add_axiom(self, formula):
        if (formula.is_and()):
            for f in formula.args():
                self._axiom.add(f)
        else:
            self._axiom.add(formula)

    def add_definition(self, formula, name):
        self._definitions[name] = formula

    def add_prop(self, formula):
        clauses = flatten_and(formula)
        for cl in clauses:
            self._prop.add(cl)

    def add_state(self, formula, fnex):
        if formula.is_function_application():
            pre = formula.function_name()
        else:
            pre = formula
        self._states.add(pre)
        nex = Symbol(fnex, pre.symbol_type())
        self._nexstates.add(nex)
        self._pre2nex[pre] = nex
        self._nex2pre[nex] = pre

    def add_global_state(self, formula):
        if formula.is_function_application():
            pre = formula.function_name()
            pret = pre.symbol_type()
            paramt = pret.param_types
            if (len(paramt) == 2 and pret.return_type.is_bool_type()
                    and paramt[0] == paramt[1]):
                name_pre = str(pre)
                if name_pre == "le" or name_pre.endswith(".le"):
                    self.add_le_state(pre)
        else:
            pre = formula
        self._globals.add(pre)
        self._states.add(pre)
        self._nexstates.add(pre)

    def add_le_state(self, pre):
        self._le.add(pre)

    def is_ordered_state(self, s):
        res = s in self._le
        return res

    def add_other(self, formula):
        self._others.add(formula)

    def add_var(self, formula):
        pre = formula
        #         if not(pre in self._nex2pre):
        self._vars.add(pre)
#             if not(pre in self._pre2nex):
#                 pre_s = pre.symbol_name()
#                 if pre_s.startswith("__"):
#                     fnex = pre_s[2:]
#                 else:
#                     fnex = pre_s + "$next"
#                 nex = Symbol(fnex, pre.symbol_type())
#                 self._pre2nex[pre] = nex
#                 self._nex2pre[nex] = pre

    def action_noop(self):
        f = dict()
        for s in self._states:
            if s in self._pre2nex:
                n = self._pre2nex[s]

                s_type = s.symbol_type()

                args = []
                if s_type.is_function_type():
                    i = 0
                    for paramt in s_type.param_types:
                        i += 1
                        paramt_name = str(i) + ":" + str(paramt)
                        args.append(Symbol(paramt_name, paramt))
                lhs = Function(s, args)
                rhs = Function(n, args)
                eq = ForAll(args, EqualsOrIff(lhs, rhs))
                f[n] = eq
        return f

    def noop_name(self):
        return "noop"

    def is_noop(self, name):
        return name == self.noop_name()

    def input_action_name(self):
        return "__input_action_"

    def get_action_noop(self):
        noop = self.action_noop()
        name = self.noop_name()
        return (name, noop)

    def add_action_noop(self):
        name, noop = self.get_action_noop()
        formula = And([i for i in noop.values()])
        self.add_action(formula, name)
        return noop

    def add_action(self, formula, name):
        if name in self._actions:
            assert (0)
        action = formula
        if action.is_exists():
            qvars = action.quantifier_vars()
            for v in qvars:
                self.add_var(v)
                self.add_other(v)
            action = action.arg(0)
        self._actions.append([action, name, None])

#     def get_axiom_vars(self):
#         axiom_vars = set()
#         if len(self._axiom) != 0:
#             av = And(self._axiom).get_free_variables()
#             for v in av:
#                 axiom_vars.add(v)
#         return axiom_vars

    def add_trel(self):
        eprint("\t(found #%d actions)" % len(self._actions))
        print("\t(found #%d actions)" % len(self._actions))
        if len(self._actions) == 0:
            eprint("\t(error: no action found)")
            print("\t(error: no action found)")
            assert (0)
        if len(self._axiom) != 0:
            ax = And(self._axiom)
            axvar = ax.get_free_variables()
            for v in axvar:
                self._axiomvars.add(v)

        noop_name, noop = self.get_action_noop()
        noop_all = And([i for i in noop.values()])
        self._trel = noop_all
        self._input_action = Symbol(self.input_action_name(), INT)
        self.add_var(self._input_action)
        #         axiom_vars = self.get_axiom_vars()
        #         action_en = []
        #         self.add_action(noop_all, noop_name)
        for idx, f in enumerate(self._actions):
            action = f[0]
            action_name = f[1]
            #             action_vars = axiom_vars.copy()
            #             for v in action.get_free_variables():
            #                 action_vars.add(v)
            action_vars = action.get_free_variables()
            qvars = None
            if action.is_exists():
                qvars = action.quantifier_vars()
                action = action.arg(0)
            action_all = [action]
            missing_nex = []
            for n in self._nex2pre.keys():
                if n not in action_vars:
                    if str(n) not in self._definitions:
                        if True or (str(n) != "choosable"):
                            action_all.append(noop[n])
                            missing_nex.append(n)
            if len(missing_nex) != 0:
                print("adding #%d noops to action %s" %
                      (len(missing_nex), f[1]))
                for n in missing_nex:
                    print("\tnoop(%s)" % n)
            action = And(action_all)
            if qvars != None:
                action = Exists(qvars, action)
            self._actions[idx][0] = action

            #             self._trel = Or(action, self._trel)

            action_symbol = Int(idx)
            self._actions[idx][-1] = action_symbol
            cond = EqualsOrIff(self._input_action, action_symbol)
            self._trel = Ite(cond, action, self._trel)


#             action_symbol = Symbol("en_"+action_name)
#             action_en.append(action_symbol)
#             self._trel = Ite(action_symbol, action, self._trel)

#         action_cond = []
#         action_cond.append(self._trel)
#         for i in range(len(action_en)-1):
#             fi = Not(action_en[i])
#             for j in range(i+1, len(action_en)):
#                 fj = Not(action_en[j])
#                 cond = Or(fi, fj)
#                 action_cond.insert(0, cond)
#         self._trel = And(action_cond)

#         if len(self._axiom) != 0:
#             q = []
#             q.extend(self._axiom)
# #             self.add_init(And(q))
#             q.append(self._trel)
#             self._trel = And(q)

        self.add_action(noop_all, noop_name)

    def add_trel_new(self):
        eprint("\t(found #%d actions)" % len(self._actions))
        print("\t(found #%d actions)" % len(self._actions))
        if len(self._actions) == 0:
            eprint("\t(error: no action found)")
            print("\t(error: no action found)")
            assert (0)
        if len(self._axiom) != 0:
            ax = And(self._axiom)
            axvar = ax.get_free_variables()
            for v in axvar:
                self._axiomvars.add(v)

        tcond = []
        enVar = []
        enOr = []
        noop = self.add_action_noop()

        for idx, f in enumerate(self._actions):
            action = f[0]
            action_name = f[1]
            action_vars = action.get_free_variables()

            en = Symbol("en_" + action_name, BOOL)
            self._action_en2idx[en] = idx
            enVar.append(en)

            qvars = None
            if action.is_exists():
                qvars = action.quantifier_vars()
                action = action.arg(0)

            action_all = [action]
            missing_nex = []
            for n in self._nex2pre.keys():
                if n not in action_vars:
                    if str(n) not in self._definitions:
                        if True or (str(n) != "choosable"):
                            action_all.append(noop[n])
                            missing_nex.append(n)
            if len(missing_nex) != 0:
                print("adding #%d noops to action %s" %
                      (len(missing_nex), f[1]))
                for n in missing_nex:
                    print("\tnoop(%s)" % n)
            action = And(action_all)
            if qvars != None:
                action = Exists(qvars, action)

            self._actions[idx][0] = action
            self._actions[idx][2] = en

            cond = Implies(en, action)
            tcond.append(cond)
            enOr.append(en)

        cond = Or(enOr)
        tcond.append(cond)
        for i in range(len(enVar) - 1):
            ei = enVar[i]
            for j in range(i + 1, len(enVar)):
                assert (i != j)
                ej = enVar[j]
                cond = Or(Not(ei), Not(ej))
                tcond.append(cond)
        self._trel = And(tcond)

    def __str__(self):
        res = []
        res.append(
            "-----------------------------------------------------------------"
        )
        res.append("\nInit #")
        res.append(str(len(self._init)) + "\n")
        for f in self._init:
            res.append("\t" + str(f) +
                       "\n\t\twith variables %s\n" % f.get_free_variables())
        res.append("\nAxioms #")
        res.append(str(len(self._axiom)) + "\n")
        for f in self._axiom:
            res.append("\t" + f.serialize() +
                       "\n\t\twith variables %s\n" % f.get_free_variables())
        res.append("\nActions #")
        res.append(str(len(self._actions)) + "\n")
        for idx, f in enumerate(self._actions):
            res.append("\t" + str(idx) + ":\t" + f[1] + " (en: " + str(f[2]) +
                       ")\t" + str(f[0]) +
                       "\n\t\twith variables %s\n" % f[0].get_free_variables())
        res.append("\nProperties #")
        res.append(str(len(self._prop)) + "\n")
        for f in self._prop:
            res.append("\t" + str(f) +
                       "\n\t\twith variables %s\n" % f.get_free_variables())
        res.append("\nVariables #")
        res.append(str(len(self._vars)) + "\n")
        for f in self._vars:
            res.append("\t" + str(f) + " of type %s\n" % f.symbol_type())
        res.append("\nState variables #")
        res.append(str(len(self._states)) + "\n")
        for f in self._states:
            res.append("\t" + str(f) + " of type %s\n" % f.symbol_type())
        res.append("\nNex state variables #")
        res.append(str(len(self._nexstates)) + "\n")
        for f in self._nexstates:
            res.append("\t" + str(f) + " of type %s\n" % f.symbol_type())
        res.append("\nGlobal variables #")
        res.append(str(len(self._globals)) + "\n")
        for f in self._globals:
            res.append("\t" + str(f) + " of type %s\n" % f.symbol_type())
        res.append("\nOrdered variables #")
        res.append(str(len(self._le)) + "\n")
        for f in self._le:
            res.append("\t" + str(f) + " of type %s\n" % f.symbol_type())
        res.append("\nNex to pre #")
        res.append(str(len(self._nex2pre)) + "\n")
        for nex, pre in self._nex2pre.items():
            res.append("\t" + str(nex) + " <- " + str(pre) + "\n")
        res.append("\nPre to nex #")
        res.append(str(len(self._pre2nex)) + "\n")
        for pre, nex in self._pre2nex.items():
            res.append("\t" + str(pre) + " -> " + str(nex) + "\n")
        res.append("\nOther variables #")
        res.append(str(len(self._others)) + "\n")
        for f in self._others:
            res.append("\t" + str(f) + " of type %s\n" % f.symbol_type())
        res.append("\nAxiom variables #")
        res.append(str(len(self._axiomvars)) + "\n")
        for f in self._axiomvars:
            res.append("\t" + str(f) + "\n")
        res.append("\nPredicates #")
        res.append(str(len(self._predicates)) + "\n")
        for k, v in self._predicates.items():
            res.append("\t%s := %s\n\t\twith variables %s\n" %
                       (str(k), str(v), v.get_free_variables()))
        res.append("\nHelpers #")
        res.append(str(len(self._helpers)) + "\n")
        for k, v in self._helpers.items():
            res.append("\t%s := %s\n\t\twith variables %s\n" %
                       (str(v), str(k), k.get_free_variables()))
        res.append("\nInferences #")
        res.append(str(len(self._infers)) + "\n")
        for k, v in self._infers.items():
            res.append("\t%s := %s\n\t\twith variables %s\n" %
                       (str(v), str(k), k.get_free_variables()))
        res.append("\nDefinitions #")
        res.append(str(len(self._definitions)) + "\n")
        for k, v in self._definitions.items():
            res.append("\t%s := %s\n\t\twith variables %s\n" %
                       (str(k), str(v), v.get_free_variables()))
        res.append("\nDefinition Map #")
        res.append(str(len(self._definitionMap)) + "\n")
        for k, v in self._definitionMap.items():
            res.append("\t%s := %s\n\t\twith variables %s\n" %
                       (str(k), str(v[0]), v[-1]))
        res.append("\nTrel:\n%s\n" % (self._trel.serialize()))
        res.append(
            "-----------------------------------------------------------------"
        )
        return "".join(res)