def test_normalization_negative(): def get_normalization_file(filename): return path.join(path.dirname(__file__), "res", "bug_z_negative", filename) domain = Domain.from_file(get_normalization_file("domain")) support = domain.get_bounds() & read_smtlib( get_normalization_file("vanilla.support")) weight = read_smtlib(get_normalization_file("vanilla.weight")) new_support = read_smtlib(get_normalization_file("renorm.support")) pa_engine = RejectionEngine( domain, Iff(new_support, ~normalize_formula(new_support)), Real(1), 1000000) difference_volume = pa_engine.compute_volume() assert difference_volume == pytest.approx(0, EXACT_REL_ERROR**2) support = normalize_formula(support) new_support = normalize_formula(new_support) weight = normalize_formula(weight) engine = XaddEngine(domain, support, weight) new_weight = engine.normalize(new_support, paths=False) computed_volume = engine.copy_with(weight=new_weight).compute_volume() # print(pa_engine.copy_with(support=domain.get_bounds(), weight=new_weight).compute_volume()) # print(pa_engine.copy_with(support=new_support, weight=new_weight).compute_volume()) illegal_volume = engine.copy_with(support=~new_support, weight=new_weight).compute_volume() print(computed_volume, illegal_volume) # new_new_weight = engine.copy_with(support=domain.get_bounds(), weight=new_weight).normalize(new_support, paths=False) # print(pa_engine.copy_with(support=domain.get_bounds(), weight=new_new_weight).compute_volume()) assert computed_volume == pytest.approx(1, rel=0.1) assert illegal_volume == pytest.approx(0, rel=EXACT_REL_ERROR)
def test_rejection_iff_real(): domain = Domain.make([], ["x", "y"], real_bounds=(-1, 1)) x, y = domain.get_symbols() c = 0.00000001 f1 = (x * c > 0) & (x * c <= y * c) & (y * c < c) f2 = normalize_formula(f1) rej_vol1 = RejectionEngine(domain, (f1 | f2) & (~f1 | ~f2), smt.Real(1.0), 100000).compute_volume() rej_vol2 = RejectionEngine(domain, smt.Iff(f1, ~f2), smt.Real(1.0), 100000).compute_volume() rej_vol3 = RejectionEngine(domain, ~smt.Iff(f1, f2), smt.Real(1.0), 100000).compute_volume() assert rej_vol1 == pytest.approx(0, REL_ERROR**3) assert rej_vol2 == pytest.approx(0, REL_ERROR**3) assert rej_vol3 == pytest.approx(0, REL_ERROR**3)
def test_pyxadd_automated(e): inspect_density( PyXaddEngine(), e, test_engine=RejectionEngine(e.domain, e.support, e.weight, sample_count=TEST_SAMPLE_COUNT), )
def test_adaptive_unweighted_real(): domain = Domain.make([], ["x", "y"], [(-5, 10), (-5, 10)]) x, y = domain.get_symbols(domain.variables) support = (x >= -4) & (x <= y) & (y <= 9) & ((y <= -1) | (y >= 6)) weight = Real(1.0) engine = AdaptiveRejection(domain, support, weight, SAMPLE_COUNT, SAMPLE_COUNT / 10) computed_volume = engine.compute_volume() rejection_engine = RejectionEngine(domain, support, weight, SAMPLE_COUNT) correction_volume_rej = rejection_engine.compute_volume() print(computed_volume, correction_volume_rej, APPROX_ERROR * correction_volume_rej) assert computed_volume == pytest.approx(correction_volume_rej, rel=APPROX_ERROR) query = x <= y / 2 prob_adaptive = engine.compute_probability(query) prob_rej = rejection_engine.compute_probability(query) assert prob_adaptive == pytest.approx(prob_rej, rel=APPROX_ERROR)
def run_rej(density, n_bins, n_samples, log_path): #log_path = join(output_folder, f"{name}-rej.json") if not isfile(log_path): print(log_path) rej_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() rejection_engine = RejectionEngine(density.domain, density.support, density.weight, sample_count=n_samples) rej_bin_probs = {} for x in qs: rej_bin_probs[x] = [] for l, u, q in qs[x]: prob_q = rejection_engine.compute_probability(q) rej_bin_probs[x].append((l, u, prob_q)) t1 = time.perf_counter() rej_log['time'] = t1 - t0 rej_log['query_marginals'] = rej_bin_probs with open(log_path, 'w') as f: json.dump(rej_log, f) else: print(f"Found {log_path}") with open(log_path, 'r') as f: rej_bin_probs = json.load(f)['query_marginals'] return rej_bin_probs
def test_rejection_iff_bool(): domain = Domain.make(["a", "b"]) a, b = domain.get_symbols() print(domain) vol_t = RejectionEngine(domain, smt.TRUE(), smt.Real(1.0), 100000).compute_volume() vol1 = RejectionEngine(domain, (a | b) & (~a | ~b), smt.Real(1.0), 100000).compute_volume() vol2 = RejectionEngine(domain, smt.Iff(a, ~b), smt.Real(1.0), 100000).compute_volume() vol3 = RejectionEngine(domain, ~smt.Iff(a, b), smt.Real(1.0), 100000).compute_volume() print(vol1, vol2, vol3, vol_t) # print(PredicateAbstractionEngine(domain, a | b, smt.Real(1.0)).compute_volume()) print(XaddEngine(domain, a | b, smt.Real(1.0)).compute_volume()) quit()
def test_adaptive_unweighted(): 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) engine = AdaptiveRejection(domain, support, weight, SAMPLE_COUNT, SAMPLE_COUNT / 10) computed_volume = engine.compute_volume() correction_volume_rej = RejectionEngine(domain, support, weight, SAMPLE_COUNT).compute_volume() assert computed_volume == pytest.approx(correction_volume_rej, rel=APPROX_ERROR)
def test_volume(): 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)) engine = AdaptiveRejection(domain, support, weight, SAMPLE_COUNT) computed_volume = engine.compute_volume() correction_volume_rej = RejectionEngine(domain, support, weight, SAMPLE_COUNT).compute_volume() assert computed_volume == pytest.approx(correction_volume_rej, rel=APPROX_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_adaptive_threshold(): random.seed(888) np.random.seed(888) domain = Domain.make([], ["x", "y"], [(0, 1), (0, 1)]) x, y = domain.get_symbols(domain.variables) formula = (x <= y) & (x <= 0.5) & (y <= 0.5) & domain.get_bounds() thresholds = {"x": 0.1, "y": 0.1} data, _ = RejectionEngine(domain, formula, x * x, 100000).get_samples(50) k = 4 nearest_neighbors = [] for i in range(len(data)): nearest_neighbors.append([]) for j in range(len(data)): if i != j: distance = 1 if any(data[i, b] != data[j, b] for b, v in enumerate(domain.variables) if domain.is_bool(v))\ else max(abs(data[i, r] - data[j, r]) / (domain.var_domains[v][1] - domain.var_domains[v][0]) for r, v in enumerate(domain.variables) if domain.is_real(v)) if len(nearest_neighbors[i]) < k: nearest_neighbors[i].append((j, distance)) else: index_of_furthest = None for fi, f in enumerate(nearest_neighbors[i]): if index_of_furthest is None or f[ 1] > nearest_neighbors[i][index_of_furthest][1]: index_of_furthest = fi if distance < nearest_neighbors[i][index_of_furthest][1]: nearest_neighbors[i][index_of_furthest] = (j, distance) print(nearest_neighbors) t = [[ sum(n[1] for n in nearest_neighbors[i]) / len(nearest_neighbors[i]) * (domain.var_domains[v][1] - domain.var_domains[v][0]) for v in domain.real_vars ] for i in range(len(nearest_neighbors))] t = np.array(t) print(t) print(data) # data = uniform(domain, 400) labels = evaluate(domain, formula, data) data = data[labels == 1] labels = labels[labels == 1] data, labels = OneClassStrategy.add_negatives(domain, data, labels, t, 1000) directory = "test_output{}adaptive{}{}".format( os.path.sep, os.path.sep, time.strftime("%Y-%m-%d %Hh%Mm%Ss")) os.makedirs(directory) name = os.path.join(directory, "combined.png") plot.plot_combined("x", "y", domain, formula, (data, labels), None, name, set(), set())
def accuracy_approx(experiment): key = "accuracy_approx:{}".format(experiment.imported_from_file) if Properties.db.exists(key): return Properties.db.get(key) else: pysmt.environment.push_env() pysmt.environment.get_env().enable_infix_notation = True if os.path.basename(experiment.imported_from_file).startswith("synthetic"): db = Properties.get_db_synthetic(experiment) name = Properties.to_synthetic_name(experiment.imported_from_file) entry = db.get(name) domain = import_domain(json.loads(entry["domain"])) true_formula = nested_to_smt(entry["formula"]) else: density = Density.import_from(experiment.parameters.original_values["domain"]) domain = Domain(density.domain.variables, density.domain.var_types, Properties.get_bound(experiment)) true_formula = density.support learned_formula = nested_to_smt(experiment.results.formula) engine = RejectionEngine(domain, smt.TRUE(), smt.Real(1.0), 100000) accuracy = engine.compute_probability(smt.Iff(true_formula, learned_formula)) pysmt.environment.pop_env() print(accuracy) Properties.db.set(key, accuracy) return accuracy
def check_Z_normalize(model, seed, sample_count): """Tests whether the model is normalized. If not, updates the weight function accordingly.""" logger.debug("Approximating Z") solver = RejectionEngine(model.domain, model.support, model.weightfun, sample_count=sample_count, seed=seed) all_ohes = dict() for var in model.domain.bool_vars: print("VAR:", var) if "_OHE_" in var: prefix = var.partition("_OHE_")[0] if prefix not in all_ohes: all_ohes[prefix] = [] all_ohes[prefix].append(var) ohe_variables = list(all_ohes.values()) if len(all_ohes) > 0 else None Z_approx = solver.compute_volume(ohe_variables=ohe_variables) logger.debug("Z_approx: {}".format(Z_approx)) if Z_approx <= 0: raise ModelException("Partition function is <= 0") if not abs(Z_approx - 1.0) <= DEF_CLOSE_ENOUGH: model.weightfun = Times(Real(float(1.0/Z_approx)), model.weightfun)
def ISE(model1, model2, seed, sample_count, engine='pa'): assert(set(model1.get_vars()) == set(model2.get_vars())),\ "M1 vars: {}\n M2 vars: {}".format(model1.get_vars(),model2.get_vars()) support1, weightfun1 = model1.support, model1.weightfun support2, weightfun2 = model2.support, model2.weightfun support_d = Or(support1, support2) weight_d = Ite(And(support1, support2), Times(Minus(weightfun1, weightfun2), Minus(weightfun1, weightfun2)), Ite(support1, Times(weightfun1, weightfun1), Times(weightfun2, weightfun2))) domain, _ = merged_domain(model1, model2) if engine == 'pa': engine = PredicateAbstractionEngine(domain, support_d, weight_d) result = solver.compute_volume() elif engine == 'rej': result = None solver = RejectionEngine(domain, support_d, weight_d, sample_count=sample_count, seed=seed) while result is None: #logger.debug("Attempting with sample_count {}".format( #solver.sample_count)) result = solver.compute_volume() solver.sample_count *= 2 else: raise NotImplementedError() return result
def normalize(model, seed, sample_count, engine='pa'): if engine == 'pa': solver = PredicateAbstractionEngine(model.domain, model.support, model.weightfun) elif engine == 'rej': solver = RejectionEngine(model.domain, model.support, model.weightfun, sample_count=sample_count, seed=seed) else: raise NotImplementedError() Z = solver.compute_volume() assert(Z >= 0), "Z is negative" if not np.isclose(Z, 1.0): logger.debug("Normalizing w with Z: {}".format(Z)) model.weightfun = Times(Real(1.0/Z), model.weightfun) return Z
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)
def rejection_factory(d, s, w): return RejectionEngine(d, s, w, SAMPLE_COUNT)
x, y = domain.get_real_symbols( ) # Get PySMT variables for the continuous variables # Create support support = (a | b) & (~a | ~b) & (x <= y) & domain.get_bounds() # Create weight function (PySMT requires constants to be wrapped, e.g., smt.Real(0.2)) weight_function = smt.Ite(a, smt.Real(0.2), smt.Real(0.8)) * ( smt.Ite(x <= 0.5, smt.Real(0.2), 0.2 + y) + smt.Real(0.1)) # Create query query = x <= y / 2 # Create rejection-sampling based engine (no setup required) rejection_engine = RejectionEngine(domain, support, weight_function, sample_count=100000) print("Volume (Rejection): ", rejection_engine.compute_volume()) # Compute the weighted model integral print("Query probability (Rejection):", rejection_engine.compute_probability(query)) # Compute query probability # Create XADD engine (mode resolve refers to the integration algorithm described in # Kolb et al. Efficient symbolic integration for probabilistic inference. IJCAI 2018) # !! Requires XADD solver to be setup (see above) !! xadd_engine = XaddEngine(domain, support, weight_function, mode="resolve") print("Volume (XADD): ", xadd_engine.compute_volume()) # Compute the weighted model integral print("Query probability (XADD): ",
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 test_normalization(): def get_normalization_file(filename): return path.join(path.dirname(__file__), "res", "renorm_bug", filename) for i in range(5): domain = Domain.from_file(get_normalization_file("domain.json")) support = read_smtlib(get_normalization_file("vanilla.support")) weight = read_smtlib(get_normalization_file("vanilla.weight")) new_support = read_smtlib( get_normalization_file("renorm_chi_{}.support".format(i))) # print(smt_to_nested(support)) clean_support = normalize_formula(support) clean_new_support = normalize_formula(new_support) clean_weight = normalize_formula(weight) print(smt_to_nested(clean_weight)) assert (RejectionEngine(domain, ~Iff(support, clean_support), Real(1.0), 1000000).compute_volume() == 0) assert (RejectionEngine(domain, ~Iff(new_support, clean_new_support), Real(1.0), 1000000).compute_volume() == 0) # plot_formula("new_support", domain, new_support, ["r0", "r1"]) # plot_formula("clean_new_support", domain, clean_new_support, ["r0", "r1"]) support = clean_support new_support = clean_new_support weight = clean_weight # print(RejectionEngine(domain, Iff(weight, ~clean_weight), Real(1.0), 1000000).compute_volume()) # print(smt_to_nested(support)) print("Problem", i) engine = XaddEngine(domain, support, weight, "original") print("Volume before starting", engine.compute_volume()) new_weight = engine.normalize(new_support, paths=False) Density(domain, new_support, new_weight).to_file("normalized.json") illegal_volume = XaddEngine(domain, ~new_support, new_weight, "mass").compute_volume() assert illegal_volume == pytest.approx(0, rel=EXACT_REL_ERROR) computed_volume = XaddEngine(domain, TRUE(), new_weight, "mass").compute_volume() computed_volume_within = XaddEngine(domain, new_support, new_weight, "mass").compute_volume() computed_volume_within2 = XaddEngine(domain, new_support, new_weight).compute_volume() computed_volume_within3 = RejectionEngine(domain, new_support, new_weight, 1000000).compute_volume() print( "pa new_support new_weight", computed_volume_within, "xadd new_support new_weight:", computed_volume_within2, "rej new_support new_weight:", computed_volume_within3, ) assert computed_volume_within == pytest.approx(computed_volume_within2, EXACT_REL_ERROR) print( "pa true new_weight:", computed_volume, "pa new_support new_weight", computed_volume_within, "pa outside new_support new_weight", illegal_volume, ) assert computed_volume == pytest.approx(1, rel=EXACT_REL_ERROR) assert computed_volume_within == pytest.approx(1, rel=EXACT_REL_ERROR) illegal_volume = engine.copy_with(support=~new_support, weight=new_weight).compute_volume() assert illegal_volume == pytest.approx(0, rel=EXACT_REL_ERROR)
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