def xsdd(): domain, formula, weight = get_problem() return XsddEngine(domain, formula, weight, repeated=True).compute_probabilities([ domain.get_symbol("x") <= 0.5, domain.get_symbol("x") <= 1.0 ])
def run_xsdd(density, n_bins, n_samples, log_path): #log_path = join(output_folder, f"{name}-xsdd.json") print(f"running XSDD(Sampling) with {n_bins} bins and {n_samples} samples") print(f"dumping the result in {log_path}") if not isfile(log_path): xsdd_log = {} # create queries qs = {} for xvar in density.domain.get_real_symbols(): x = xvar.symbol_name() qs[x] = [] low, up = density.domain.var_domains[x] slices = [(i / n_bins) * (up - low) + low for i in range(0, n_bins + 1)] for i in range(len(slices) - 1): l, u = slices[i], slices[i + 1] qs[x].append((l, u, And(LE(Real(l), xvar), LE(xvar, Real(u))))) t0 = time.perf_counter() backend = RejectionIntegrator(n_samples, 0) xsdd_engine = XsddEngine(density.domain, density.support, density.weight, convex_backend=backend, factorized=True, ordered=False) xsdd_bin_probs = {} for x in qs: xsdd_bin_probs[x] = [] for l, u, q in qs[x]: prob_q = xsdd_engine.compute_probability(q) xsdd_bin_probs[x].append((l, u, prob_q)) t1 = time.perf_counter() xsdd_log['time'] = t1 - t0 xsdd_log['query_marginals'] = xsdd_bin_probs with open(log_path, 'w') as f: json.dump(xsdd_log, f) else: print(f"Found {log_path}") with open(log_path, 'r') as f: xsdd_bin_probs = json.load(f)['query_marginals'] return xsdd_bin_probs
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_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)
logging.info("using pa") # pa t1 = time.perf_counter() wmipa = WMI(density.support, density.weight) Z, _ = wmipa.computeWMI(Bool(True), mode=WMI.MODE_PA) t2 = time.perf_counter() elif args.solver == "xsdd": logging.info("using xsdd") # xsdd t1 = time.perf_counter() xsdd = XsddEngine(density.domain, density.support, density.weight, factorized=False, algebra=PyXaddAlgebra(), ordered=False) Z = xsdd.compute_volume(add_bounds=False) t2 = time.perf_counter() else: logging.info(f"Unrecognized solver: {args.solver}") logging.info(f"done in {t2-t1} secs") logging.info(f"Z: {Z}") z_path = os.path.join(res_path, 'Z') with open(z_path, 'w') as f: f.write(f"{Z}\n") logging.info(f"Z saved to {z_path}")
def main(path, file_name, domain_real): domain, queries, support, weight = load(path, file_name, domain_real) return XsddEngine(domain, support, weight).compute_probability(queries[0], collapse=True)
def test_xsdd_manual(): inspect_manual( lambda d, s, w: XsddEngine(d, s, w, convex_backend=LatteIntegrator()), 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)