mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +00:00 
			
		
		
		
	updated experiment
This commit is contained in:
		
							parent
							
								
									b918f121ef
								
							
						
					
					
						commit
						7fab0f5923
					
				
					 1 changed files with 125 additions and 18 deletions
				
			
		|  | @ -51,6 +51,8 @@ def count_sets_by_size(sets): | ||||||
| 
 | 
 | ||||||
| #set_param("sat.euf", True) | #set_param("sat.euf", True) | ||||||
| #set_param("tactic.default_tactic","sat") | #set_param("tactic.default_tactic","sat") | ||||||
|  | #set_param("sat.cardinality.solver",False) | ||||||
|  | #set_param("sat.cardinality.encoding", "circuit") | ||||||
| #set_param(verbose=1) | #set_param(verbose=1) | ||||||
|                  |                  | ||||||
| class Soft: | class Soft: | ||||||
|  | @ -108,14 +110,17 @@ class HsPicker: | ||||||
|         opt.set("timeout", self.timeout_value) |         opt.set("timeout", self.timeout_value) | ||||||
|         is_sat = opt.check() |         is_sat = opt.check() | ||||||
|         lo = max(lo, opt.lower(obj).as_long()) |         lo = max(lo, opt.lower(obj).as_long()) | ||||||
|  |         self.opt_backoff_count = 0 | ||||||
|         if is_sat == sat: |         if is_sat == sat: | ||||||
|  |             if self.opt_backoff_limit > 1: | ||||||
|  |                 self.opt_backoff_limit -= 1 | ||||||
|  |                 self.timeout_value += 500 | ||||||
|             mdl = opt.model() |             mdl = opt.model() | ||||||
|             hs = [self.soft.name2formula[n] for n in self.soft.formula2name.values() if is_true(mdl.eval(n))] |             hs = [self.soft.name2formula[n] for n in self.soft.formula2name.values() if is_true(mdl.eval(n))] | ||||||
|             return set(hs), lo |             return set(hs), lo | ||||||
|         else: |         else: | ||||||
|             print("Timeout", self.timeout_value, "lo", lo, "limit", self.opt_backoff_limit) |             print("Timeout", self.timeout_value, "lo", lo, "limit", self.opt_backoff_limit) | ||||||
|             self.opt_backoff_limit += 1 |             self.opt_backoff_limit += 1 | ||||||
|             self.opt_backoff_count = 0 |  | ||||||
|             self.timeout_value += 500 |             self.timeout_value += 500 | ||||||
|             return self.pick_hs_(Ks, lo) |             return self.pick_hs_(Ks, lo) | ||||||
| 
 | 
 | ||||||
|  | @ -147,11 +152,11 @@ class HsMaxSAT: | ||||||
|         min_size = min(len(s) for s in sets) |         min_size = min(len(s) for s in sets) | ||||||
|         def insert(bound, sets, hs, result):             |         def insert(bound, sets, hs, result):             | ||||||
|             for s in sets: |             for s in sets: | ||||||
|                 if len(s) <= bound and not any(c in hs for c in s): |                 if len(s) == bound and not any(c in hs for c in s): | ||||||
|                     result += [s] |                     result += [s] | ||||||
|                     hs = hs | set(s) |                     hs = hs | set(s) | ||||||
|             return hs, result |             return hs, result | ||||||
|         for sz in range(min_size, self.small_set_size + 1): |         for sz in range(min_size, min_size + 3): | ||||||
|             hs, result = insert(sz, sets, hs, result) |             hs, result = insert(sz, sets, hs, result) | ||||||
|         return result |         return result | ||||||
| 
 | 
 | ||||||
|  | @ -168,7 +173,7 @@ class HsMaxSAT: | ||||||
|         # If there are sufficiently many small cores, then |         # If there are sufficiently many small cores, then | ||||||
|         # we reduce the soft constraints by maxres. |         # we reduce the soft constraints by maxres. | ||||||
|         # |         # | ||||||
|         if self.has_many_small_sets(self.Ks): |         if self.has_many_small_sets(self.Ks) or (not self.corr_set_enabled and not self.has_many_small_sets(self.Cs) and self.num_max_res_failures > 0): | ||||||
|             self.num_max_res_failures = 0 |             self.num_max_res_failures = 0 | ||||||
|             cores = self.get_small_disjoint_sets(self.Ks) |             cores = self.get_small_disjoint_sets(self.Ks) | ||||||
|             for core in cores: |             for core in cores: | ||||||
|  | @ -179,7 +184,7 @@ class HsMaxSAT: | ||||||
|             return |             return | ||||||
|         # |         # | ||||||
|         # If there are sufficiently many small correction sets, then |         # If there are sufficiently many small correction sets, then | ||||||
|         # we reduce the soft constraints by dual maxres (IJCAI 2014) |         # we reduce the soft constraints by dual maxres (IJCAI 2015) | ||||||
|         # |         # | ||||||
|         # TODO: the heuristic for when to invoking correction set restriction |         # TODO: the heuristic for when to invoking correction set restriction | ||||||
|         # needs fine-tuning. For example, the if min(Ks)*optimality_gap < min(Cs)*(max(SS)) |         # needs fine-tuning. For example, the if min(Ks)*optimality_gap < min(Cs)*(max(SS)) | ||||||
|  | @ -193,7 +198,7 @@ class HsMaxSAT: | ||||||
|             cs = self.get_small_disjoint_sets(self.Cs) |             cs = self.get_small_disjoint_sets(self.Cs) | ||||||
|             for corr_set in cs: |             for corr_set in cs: | ||||||
|                 print("restrict cs", len(corr_set)) |                 print("restrict cs", len(corr_set)) | ||||||
|                 self.small_set_size = max(4, min(self.small_set_size, len(corr_set) - 2)) |                 # self.small_set_size = max(4, min(self.small_set_size, len(corr_set) - 2)) | ||||||
|                 restrict_cs(self.s, corr_set, self.soft.formulas) |                 restrict_cs(self.s, corr_set, self.soft.formulas) | ||||||
|                 self.s.add(Or(corr_set)) |                 self.s.add(Or(corr_set)) | ||||||
|             self.reinit_soft(0) |             self.reinit_soft(0) | ||||||
|  | @ -204,9 +209,10 @@ class HsMaxSAT: | ||||||
|         # then increment the lower bounds for performing maxres or dual maxres |         # then increment the lower bounds for performing maxres or dual maxres | ||||||
|         #  |         #  | ||||||
|         self.num_max_res_failures += 1 |         self.num_max_res_failures += 1 | ||||||
|         if self.num_max_res_failures > 6: |         print("Small set size", self.small_set_size, "num skips", self.num_max_res_failures) | ||||||
|  |         if self.num_max_res_failures > 3: | ||||||
|             self.num_max_res_failures = 0 |             self.num_max_res_failures = 0 | ||||||
|             self.small_set_size += 2 |             self.small_set_size += 100 | ||||||
| 
 | 
 | ||||||
|     def pick_hs(self): |     def pick_hs(self): | ||||||
|         hs, self.lo = self.hs.pick_hs(self.Ks, self.lo) |         hs, self.lo = self.hs.pick_hs(self.Ks, self.lo) | ||||||
|  | @ -240,6 +246,34 @@ class HsMaxSAT: | ||||||
|             counts = [sum(b[i] for b in self.patterns) for i in range(len(bits))] |             counts = [sum(b[i] for b in self.patterns) for i in range(len(bits))] | ||||||
|             print(counts) |             print(counts) | ||||||
| 
 | 
 | ||||||
|  |     # | ||||||
|  |     # Crude, quick core reduction attempt | ||||||
|  |     #  | ||||||
|  |     def reduce_core(self, core): | ||||||
|  |         s = self.s         | ||||||
|  |         if len(core) <= 4: | ||||||
|  |             return core | ||||||
|  | 
 | ||||||
|  |         s.set("timeout", 200) | ||||||
|  |         i = 0 | ||||||
|  |         num_undef = 0 | ||||||
|  |         orig_len = len(core) | ||||||
|  |         core = list(core) | ||||||
|  |         while i < len(core): | ||||||
|  |             is_sat = s.check([core[j] for j in range(len(core)) if j != i]) | ||||||
|  |             if is_sat == unsat: | ||||||
|  |                 core = s.unsat_core() | ||||||
|  |             elif is_sat == sat: | ||||||
|  |                 self.improve(s.model()) | ||||||
|  |                 bound = self.hi - self.soft.offset - 1 | ||||||
|  |             else: | ||||||
|  |                 num_undef += 1 | ||||||
|  |                 if num_undef > 3: | ||||||
|  |                     break | ||||||
|  |             i += 1 | ||||||
|  |         print("Reduce", orig_len, "->", len(core), "iterations", i, "unknown", num_undef) | ||||||
|  |         s.set("timeout", 100000000) | ||||||
|  |         return core | ||||||
|                  |                  | ||||||
|     def improve(self, new_model): |     def improve(self, new_model): | ||||||
|         mss = { f for f in self.soft.formulas if is_true(new_model.eval(f)) } |         mss = { f for f in self.soft.formulas if is_true(new_model.eval(f)) } | ||||||
|  | @ -254,12 +288,82 @@ class HsMaxSAT: | ||||||
|             print("improve", self.hi, cost) |             print("improve", self.hi, cost) | ||||||
|             self.model = new_model |             self.model = new_model | ||||||
|             self.save_model() |             self.save_model() | ||||||
|  |         assert self.model             | ||||||
|         if cost < self.hi: |         if cost < self.hi: | ||||||
|             self.hi = cost |             self.hi = cost | ||||||
|         assert self.model |             return True | ||||||
|  |         return False | ||||||
|  | 
 | ||||||
|  |     def try_rotate(self, mss): | ||||||
|  |         backbones = set() | ||||||
|  |         backbone2core = {} | ||||||
|  |         ps = self.soft.formulas - mss | ||||||
|  |         num_sat = 0 | ||||||
|  |         num_unsat = 0 | ||||||
|  |         improved = False | ||||||
|  |         while len(ps) > 0: | ||||||
|  |             p = random.choice([p for p in ps]) | ||||||
|  |             ps = ps - { p } | ||||||
|  |             is_sat = self.s.check(mss | backbones | { p }) | ||||||
|  |             if is_sat == sat: | ||||||
|  |                 mdl = self.s.model() | ||||||
|  |                 mss = mss | {p} | ||||||
|  |                 ps = ps - {p} | ||||||
|  |                 if self.improve(mdl): | ||||||
|  |                     improved = True | ||||||
|  |                 num_sat += 1 | ||||||
|  |             elif is_sat == unsat: | ||||||
|  |                 backbones = backbones | { Not(p) } | ||||||
|  |                 core = set() | ||||||
|  |                 for c in self.s.unsat_core(): | ||||||
|  |                     if c in backbone2core: | ||||||
|  |                         core = core | backbone2core[c] | ||||||
|  |                     else: | ||||||
|  |                         core = core | { c } | ||||||
|  |                 if len(core) < 20: | ||||||
|  |                     self.Ks += [core] | ||||||
|  |                 backbone2core[Not(p)] = set(core) - { p } | ||||||
|  |                 num_unsat += 1 | ||||||
|  |             else: | ||||||
|  |                 print("unknown") | ||||||
|  |         print("rotate-1 done, sat", num_sat, "unsat", num_unsat) | ||||||
|  |         if improved: | ||||||
|  |             self.mss_rotate(mss, backbone2core) | ||||||
|  |         return improved | ||||||
|  | 
 | ||||||
|  |     def mss_rotate(self, mss, backbone2core): | ||||||
|  |         counts = { c : 0 for c in mss } | ||||||
|  |         max_count = 0 | ||||||
|  |         max_val = None | ||||||
|  |         for core in backbone2core.values(): | ||||||
|  |             for c in core: | ||||||
|  |                 assert c in mss | ||||||
|  |                 counts[c] += 1 | ||||||
|  |                 if max_count < counts[c]: | ||||||
|  |                     max_count = counts[c] | ||||||
|  |                     max_val = c | ||||||
|  |         print("rotate max-count", max_count, "num occurrences", len({c for c in counts if counts[c] == max_count})) | ||||||
|  |         print("Number of plateaus", len({ c for c in counts if counts[c] <= 1 })) | ||||||
|  |         for c in counts: | ||||||
|  |             if counts[c] > 1: | ||||||
|  |                 print("try-rotate", counts[c]) | ||||||
|  |                 if self.try_rotate(mss - { c }): | ||||||
|  |                     break | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     def local_mss(self, new_model): |     def local_mss(self, new_model): | ||||||
|         mss = { f for f in self.soft.formulas if is_true(new_model.eval(f)) } |         mss = { f for f in self.soft.formulas if is_true(new_model.eval(f)) } | ||||||
|  | 
 | ||||||
|  |         ######################################## | ||||||
|  |         # test effect of random sub-sampling | ||||||
|  |         # | ||||||
|  |         #mss = list(mss) | ||||||
|  |         #ms = set() | ||||||
|  |         #for i in range(len(mss)//2): | ||||||
|  |         #    ms = ms | { random.choice([p for p in mss]) } | ||||||
|  |         #mss = ms | ||||||
|  |         #### | ||||||
|  |          | ||||||
|         ps = self.soft.formulas - mss |         ps = self.soft.formulas - mss | ||||||
|         backbones = set() |         backbones = set() | ||||||
|         qs = set() |         qs = set() | ||||||
|  | @ -286,37 +390,40 @@ class HsMaxSAT: | ||||||
|                 mss = mss | rs |                 mss = mss | rs | ||||||
|                 ps = ps - rs  |                 ps = ps - rs  | ||||||
|                 qs = qs - rs |                 qs = qs - rs | ||||||
|                 self.improve(mdl) |                 if self.improve(mdl): | ||||||
|  |                     self.mss_rotate(mss, backbone2core) | ||||||
|             elif is_sat == unsat: |             elif is_sat == unsat: | ||||||
|                 core = set() |                 core = set() | ||||||
|                 for c in self.s.unsat_core(): |                 for c in self.s.unsat_core(): | ||||||
|                     if c in backbone2core: |                     if c in backbone2core: | ||||||
|                         core = core | backbone2core[c] |                         core = core | backbone2core[c] | ||||||
|                     elif not p.eq(c): |                     else: | ||||||
|                         core = core | { c } |                         core = core | { c } | ||||||
|  |                 core = self.reduce_core(core) | ||||||
|                 self.Ks += [core] |                 self.Ks += [core] | ||||||
|                 backbone2core[Not(p)] = core |                 backbone2core[Not(p)] = set(core) - { p } | ||||||
|                 backbones = backbones | { Not(p) } |                 backbones = backbones | { Not(p) } | ||||||
|             else: |             else: | ||||||
|                 qs = qs | { p } |                 qs = qs | { p } | ||||||
|         if len(qs) > 0: |         if len(qs) > 0: | ||||||
|             print("Number undetermined", len(qs)) |             print("Number undetermined", len(qs)) | ||||||
| 
 | 
 | ||||||
|  |     def unsat_core(self): | ||||||
|  |         core = self.s.unsat_core() | ||||||
|  |         return self.reduce_core(core) | ||||||
|          |          | ||||||
|     def get_cores(self, hs): |     def get_cores(self, hs): | ||||||
|         core = self.s.unsat_core() |         core = self.unsat_core() | ||||||
|         remaining = self.soft.formulas - hs |         remaining = self.soft.formulas - hs | ||||||
|         num_cores = 0 |         num_cores = 0 | ||||||
|         cores = [core] |         cores = [core] | ||||||
|         if len(core) == 0: |         if len(core) == 0: | ||||||
|             self.lo = self.hi - self.soft.offset |             self.lo = self.hi - self.soft.offset | ||||||
|             return |             return | ||||||
|         print("new core of size", len(core))     |  | ||||||
|         while True:         |         while True:         | ||||||
|             is_sat = self.s.check(remaining) |             is_sat = self.s.check(remaining) | ||||||
|             if unsat == is_sat: |             if unsat == is_sat: | ||||||
|                 core = self.s.unsat_core() |                 core = self.unsat_core() | ||||||
|                 print("new core of size", len(core)) |  | ||||||
|                 if len(core) == 0: |                 if len(core) == 0: | ||||||
|                     self.lo = self.hi - self.soft.offset |                     self.lo = self.hi - self.soft.offset | ||||||
|                     return |                     return | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue