Beispiel #1
0
class Task(object):
	def __init__(self):
		# all the appropriate scopes
		self.functions = Scope()
		self.synth_function = None
		self.variables = Scope()
		self.constraints = []
		self.system = None
	def add_system(self, s):
		self.system = s
	def parse(self, sexpr):
		# now let's process the file
		for cmd, *args in sexpr:
			if cmd == "set-logic":
				self.logic = args[0]
			elif cmd == "define-fun":
				func = Function(*args, self.functions.zoom())
				self.functions[func.name] = func
			elif cmd == "synth-fun":
				if self.synth_function != None:
					raise Exception("We only support a single function")
				self.synth_function = SynthFun(*args, self.functions.zoom())
			elif cmd == "declare-var":
				var = Variable(*args)
				self.variables[var.name] = var
			elif cmd == "constraint":
				self.constraints.append(args[0])
			elif cmd == "check-synth":
				return self.synthesize()
			else:
				pass
	def synthesize(self):
		# let's make some solvers
		#synth_solver = Solver()
		#verify_solver = Solver()
		# get our spec constraint
		scope = self.functions.update(mapping)
		constraint = Constraint(self.constraints, self.synth_function, self.variables, scope)
		# define some search parameters
		if DEBUG:
			print(self.constraints)
			print(constraint.constraints)
			print(constraint.input)
			input("Hit enter to start synthesis")
		breadth = 1
		while breadth < MAX_BREADTH:
			components = {}
			# create components based on breadth:
			for component in self.synth_function.components:
				if component.is_constant:
					comp_id = "{}.const".format(component._id)
					components[comp_id] = component
				else:
					for b in range(breadth):
						comp_id = "{}.{}".format(component._id, b)
						components[comp_id] = component
			if DEBUG: 
				print("Starting synthesis with breadth {}...".format(breadth))
				print("Components map:")
				pprint(components)
			# now actually synthesize
			solution = self.synthesize_with_components(components, constraint, self.system)
			if solution:
				if DEBUG: print("Found solution.")
				return self.extract_program(solution, components)
			else:
				if DEBUG: print("No solution at that size.")
				breadth += 1
	def synthesize_with_components(self, components, constraint, system):
		# components maps unique comp_ids to component objects
		# not one-to-one, but def. onto
		# step 0: some useful values
		card_I, N = len(self.synth_function.parameters), len(components)
		# step 1: make some solvers
		synth_solver = Solver()
		verify_solver = Solver()
		# step 2: initialize examples
		S = []
		# step 2b: create location variables and location constraints
		initial_constraints = []
		L = create_location_variables(components)
		if system:
			patterns = create_pattern_constraints(L, components, system)
			initial_constraints.append(patterns)
		wfp = create_wfp_constraint(L, N)
		initial_constraints.append(wfp)
		# step 3: looooooooop
		while True:
			# step 4: assert L constraint
			synth_solver.assert_exprs(*initial_constraints)
			# step 5: start the looooop
			for i, X in enumerate(S):
				I, O, T = [], [], []
				for w in range(constraint.width):
					# step 6: create I, O, T for synth at width i
					I_w = create_input_variables(self.synth_function.parameters, i, w)
					O_w = create_output_variables(self.synth_function.output, i, w)
					T_w = create_temp_variables(components, i, w)
					# step 7: assert library and connection constraints
					lib = create_lib_constraint(T_w, I_w, components)
					# for conn constraint, need map from component_id to l value
					locations = create_location_map(O_w, T_w, L, N)
					conn = create_conn_constraint(O_w, T_w, locations)
					synth_solver.assert_exprs(lib, conn)
					I += I_w
					O += O_w
					T += T_w
				# step 8: once we've got all the I, O, we can assert the spec constraint
				conn_spec, spec = create_spec_constraint(I, O, X, constraint)
				synth_solver.assert_exprs(conn_spec, spec)
			# get a model, or just bail
			if synth_solver.check() == unsat:
				if DEBUG: print("Failed to find a model.")
				return None
			model = synth_solver.model()
			curr_l = [l._replace(value=model[l.value]) for l in L]

			# step 9: need to verify the model we just found, so we'll construct verificatio constraint
			I, O, T = [], [], []
			for w in range(constraint.width):
				# same as above, but we only have a single example
				I_w = create_input_variables(self.synth_function.parameters, 0, w)
				O_w = create_output_variables(self.synth_function.output, 0, w)
				T_w = create_temp_variables(components, 0, w)
				lib = create_lib_constraint(T_w, I_w, components)
				locations = create_location_map(O_w, T_w, curr_l, N)
				conn = create_conn_constraint(O_w, T_w, locations)
				verify_solver.assert_exprs(lib, conn)
				I += I_w
				O += O_w
				T += T_w
			# now we need to create variables for X so we can check our spec
			X = create_spec_variables(constraint, self.variables)
			conn_spec, spec = create_spec_constraint(I, O, X, constraint)
			verify_solver.assert_exprs(conn_spec, Not(spec))
			# now we'll try and get a model of our exectution
			if verify_solver.check() == unsat:
				return curr_l
			model = verify_solver.model()
			example = [x._replace(value=model[x.value]) for x in X]
			S.append(example)
			if DEBUG:
				print("Found bad solution: ", [l.value.sexpr() for l in curr_l])
			# clear synthesizers and start anew
			synth_solver.reset()
			verify_solver.reset()
		return None
	def extract_program(self, L, components):
		N = len(components)
		# we need to work our way back through the program, all the way to the params
		worklist = [N - 1]
		components_used = []
		# pick up all the components used, and in which order
		while worklist:
			cur = worklist.pop()
			source = [l for l in L if l.value.as_long() == cur and l.type == "return"][0]
			for p, s in components[source.component].parameters:
				k = [l for l in L if l.component == source.component and l.parameter == p][0]
				worklist.append(k.value.as_long())
			components_used.append(components[source.component])
		left = []
		while components_used:
			cur = components_used.pop()
			if isinstance(cur, Component):
				arity = len(cur.parameters)
				args = {}
				for i in range(arity):
					args["PARAM.{}".format(i)] = left.pop()
				left.append(cur.eval_as_sexpr(args))
			else:
				left.append(cur)
		return ['define-fun', self.synth_function.name, self.synth_function.parameters, left[0]]