def timed_xadd_engine(problem_generator, size_range, reduce_strategy=None): """ Execute the problems problem_generator(n) for each n in size_range, using the PyXaddEngine. """ total_times = [] result = [] for size in size_range: density = problem_generator(size) engine = PyXaddEngine(density.domain, density.support, density.weight, reduce_strategy=reduce_strategy) def execute_computation(): starttime = time.time() result = engine.compute_volume(add_bounds=False) endtime = time.time() return result, (endtime - starttime) (res, runtime), error = run_exp_in_process(function=execute_computation, inputs=dict(), timeout_value=(None, None)) if res is None: if isinstance(error, ProcessExpired): print( "Experiment %s with size %s on xaddEngine raised exitcode %s." % (problem_generator, size, error.exitcode)) break else: result.append(res) total_times.append(runtime) return result, total_times
def test_latte_backend(): print(xadd_installed) x, y = [Symbol(n, REAL) for n in "xy"] inequalities = [LinearInequality.from_smt(f) for f in [(x >= 0), (x <= y), (y <= 1)]] polynomial = Polynomial.from_smt((x*2/3 + 13/15) * (y*1/8 + x)) domain = Domain.make([], ["x", "y"], [(0, 1), (0, 1)]) result = LatteIntegrator().integrate(domain, inequalities, polynomial) xadd_result = EngineConvexIntegrationBackend(PyXaddEngine()).integrate(domain, inequalities, polynomial) print(result, xadd_result) assert result == pytest.approx(xadd_result, rel=0.001)
def test_trivial_weight_function_partial(): # Support: (a | b) & (~a | ~b) & (x >= 0) & (x <= y) & (y <= 10) # Weight: 1 domain = Domain.make(["a", "b"], ["x", "y"], [(0, 1), (0, 1)]) a, b, x, y = domain.get_symbols(domain.variables) support = (a | b) & (~a | ~b) & (x >= 0) & (x <= y) & (y <= 1) weight = Real(1.0) computed_volume = XsddEngine( domain=domain, support=support, weight=weight, convex_backend=EngineConvexIntegrationBackend(PyXaddEngine()), ).compute_volume() correction_volume_rej = RejectionEngine(domain, support, weight, 1000000).compute_volume() correction_volume_xadd = PyXaddEngine(domain, support, weight).compute_volume() # print(correction_volume_rej, correction_volume_xadd, computed_volume) assert computed_volume == pytest.approx(correction_volume_rej, rel=ERROR) assert computed_volume == pytest.approx(correction_volume_xadd, rel=ERROR)
def test_partial_0b_2r_branch_weight(): domain = Domain.make([], ["x", "y"], real_bounds=(0, 1)) x, y = domain.get_symbols(domain.variables) support = (x >= 0.1) & (x <= 0.9) & (y >= 0.3) & (y <= 0.7) weight = Ite(x <= y, x, y * 3.17) engine = FactorizedXsddEngine(domain, support, weight) computed_volume = engine.compute_volume() should_be = PyXaddEngine(domain, support, weight).compute_volume() # print(computed_volume, should_be) assert computed_volume == pytest.approx(should_be, rel=ERROR)
def test_trivial_weight_function_partial_0b_1r_disjoint(): domain = Domain.make([], ["x"], real_bounds=(0, 1)) (x, ) = domain.get_symbols(domain.variables) support = (x >= 0.1) & (x <= 0.9) & ~((x >= 0.3) & (x <= 0.7)) weight = Real(2.0) engine = FactorizedXsddEngine(domain, support, weight) computed_volume = engine.compute_volume() should_be = PyXaddEngine(domain, support, weight).compute_volume() # print(computed_volume, should_be) assert computed_volume == pytest.approx(should_be, rel=ERROR)
def get_test_engine_factory(domain, formula, weight_function, allow_rejection=True): if check_installation_pyxadd(): return PyXaddEngine(domain, formula, weight_function) elif check_installation_pa(): return PredicateAbstractionEngine(domain, formula, weight_function) elif allow_rejection: return RejectionEngine(domain, formula, weight_function, TEST_SAMPLE_COUNT) else: raise InstallError()
def test_volume(): # Support: (a | b) & (~a | ~b) & (x >= 0) & (x <= y) & (y <= 10) # Weight: { # a b (x>=0.5): 0.6*0.8*(0.5x+0.1y) 0.5 <= x <= y, x <= y <= 10 # a b !(x>=0.5): 0.6*0.8*(0.1x+0.7y) 0 <= x <= [y, 0.5], x <= y <= 10 # a !b (x>=0.5): 0.6*0.2*(0.5x+0.1y) 0.5 <= x <= y, x <= y <= 10 # a !b !(x>=0.5): 0.6*0.2*(0.1x+0.7y) 0 <= x <= [y, 0.5], x <= y <= 10 # !a b (x>=0.5): 0.4*0.8*(0.5x+0.1y) 0.5 <= x <= y, x <= y <= 10 # !a b !(x>=0.5): 0.4*0.8*(0.1x+0.7y) 0 <= x <= [y, 0.5], x <= y <= 10 # !a !b (x>=0.5): 0.4*0.2*(0.5x+0.1y) 0.5 <= x <= y, x <= y <= 10 # !a !b !(x>=0.5): 0.4*0.2*(0.1x+0.7y) 0 <= x <= [y, 0.5], x <= y <= 10 # } # TODO What if we don't expand the Weight Function, only compile the support? # TODO => Can we reuse the SDD? It doesn't seem so... => Need multiple SDDs to use caching domain = Domain.make(["a", "b"], ["x", "y"], [(0, 1), (0, 1)]) a, b, x, y = domain.get_symbols(domain.variables) support = (a | b) & (~a | ~b) & (x >= 0.0) & (x <= y) & (y <= 1.0) weight = (Ite(a, Real(0.6), Real(0.4)) * Ite(b, Real(0.8), Real(0.2)) * (Ite( x >= Real(0.5), Real(0.5) * x + Real(0.1) * y, Real(0.1) * x + Real(0.7) * y, ))) computed_volume = XsddEngine( domain=domain, support=support, weight=weight, convex_backend=EngineConvexIntegrationBackend(PyXaddEngine()), ).compute_volume() correction_volume_rej = RejectionEngine(domain, support, weight, 1000000).compute_volume() correction_volume_xadd = PyXaddEngine(domain, support, weight).compute_volume() # print(correction_volume_rej, correction_volume_xadd, computed_volume) assert computed_volume == pytest.approx(correction_volume_rej, rel=ERROR) assert computed_volume == pytest.approx(correction_volume_xadd, rel=ERROR)
def get_engine(description, domain, support, weight): # type: (str, Domain, FNode, FNode) -> Engine parts = description.split(":") if parts[0].lower() == "pa": options = parse_options(parts[1:], "timeout") return PredicateAbstractionEngine(domain, support, weight, **options) if parts[0].lower() == "mpwmi": options = parse_options(parts[1:], "cache") return MPWMIEngine(domain, support, weight, **options) if parts[0].lower() == "rej": options = parse_options(parts[1:], "sample_count", "seed") return RejectionEngine(domain, support, weight, **options) if parts[0].lower() == "adapt": options = parse_options(parts[1:], "sample_count", "seed") return AdaptiveRejection(domain, support, weight, **options) if parts[0].lower() == "xadd": options = parse_options(parts[1:], "mode", "timeout") return XaddEngine(domain, support, weight, **options) if parts[0].lower() == "pyxadd": options = parse_options(parts[1:], "reduce") return PyXaddEngine(domain, support, weight, **options) if parts[0].lower() == "praise": # options = parse_options(parts[1:]) return PraiseEngine(domain, support, weight) if parts[0].lower() == "xsdd": options = parse_options( parts[1:], "backend", "factorized", "find_conflicts", "ordered", "balance", "minimize", ) backend_string = options.get("backend", None) if backend_string is None: backend = None else: parts = backend_string.split(".") if parts[0] == "rej": from .engines.rejection import RejectionIntegrator bb = int(parts[2]) if len(parts) > 2 else 0 seed = int(parts[3]) if len(parts) > 3 else None backend = RejectionIntegrator(int(parts[1]), bb, seed=seed) elif parts[0] == "xadd": from .engines.xadd import XaddIntegrator backend = XaddIntegrator(parts[1] if len(parts) > 1 else None) elif parts[0] == "latte": from .engines.latte_backend import LatteIntegrator backend = LatteIntegrator() else: raise ValueError( "Please specify a valid backend instead of {}".format(parts[0]) ) if "backend" in options: del options["backend"] # TODO figure out this # return XsddEngine(domain, support, weight, factorized=True,algebra=PyXaddAlgebra(), ordered=True) return XsddEngine(domain, support, weight, convex_backend=backend, **options)
def diabetes_example1(): domain = Domain.make(["f0", "d0"], ["r0"], [(10, 45)]) ( f0, d0, ) = domain.get_bool_symbols() (r0, ) = domain.get_real_symbols() support = ((f0 & (((d0 | ~d0) & ~(r0 <= 35)) | ((r0 <= 35) & (~d0)))) | (~f0 & (d0 & (r0 <= 35)))) & domain.get_bounds() # support_smaller = ((f0 & ((~(r0 <= 35)) | ~d0)) | # (~f0 & d0 & (r0 <= 35))) & \ # domain.get_bounds() # support_smaller = ((f0 & ((~(r0 <= 35)) | ~d0))) & \ # domain.get_bounds() support_smaller = ((f0 & ~(r0 <= 35) & ~d0) | (f0 & (r0 <= 35) & ~d0)) & domain.get_bounds() weight_function = smt.Ite(f0, smt.Real(0.0001), smt.Real(0.00001)) * \ smt.Ite(d0, (r0/10)-1, 8-(r0/10)) * \ smt.Ite(r0 <= 35, -0.001*(r0-27)*(r0-27)+0.3, -0.001*(r0-27)*(r0-27)+0.3) # # weight_function_smaller = smt.Ite(f0, smt.Real(0.0001), smt.Real(0.00001)) * \ # r0 *\ # smt.Ite(r0 <= 35, -0.001*(r0)*(r0)+0.3, -0.001*(r0)*(r0)+0.3) weight_function_smaller = ( smt.Real(0.00000001) * r0 * r0 * r0 ) # * smt.Real(1000) #<--- add this changes the result from 0.0 to 102 density = Density(domain, support & domain.get_bounds(), weight_function) # weight_function) query = d0 startTime = time.time() rejection_engine = RejectionEngine(density.domain, density.support, density.weight, sample_count=1000000) vol1 = rejection_engine.compute_volume() result1 = rejection_engine.compute_probability(query) endTime = time.time() time1 = endTime - startTime startTime = time.time() xadd_engine = PyXaddEngine(density.domain, density.support, density.weight) vol2 = xadd_engine.compute_volume(add_bounds=False) result2 = xadd_engine.compute_probability(query) endTime = time.time() time2 = endTime - startTime # XsddEngine algebra = PyXaddAlgebra(reduce_strategy=PyXaddAlgebra.FULL_REDUCE) mfxsdd = FXSDD( density.domain, density.support, density.weight, vtree_strategy=balanced, algebra=algebra, ordered=False, ) startTime = time.time() vol3 = mfxsdd.compute_volume(add_bounds=False) result3 = mfxsdd.compute_probability(query=query, add_bounds=False) endTime = time.time() time3 = endTime - startTime print(f"R1 {result1}, time1: {time1}") print(f"R2 {result2}, time2: {time2}") print(f"R3 {result3}, time3: {time3}") print("") print(f"Vol1 {vol1}, time1: {time1}") print(f"Vol2 {vol2}, time2: {time2}") print(f"Vol3 {vol3}, time3: {time3}") return result1, result2, time1, time2