def reduce(diagram, linear=True): variables = [t[0] for t in column_variables + row_variables] if linear: reduction = LinearReduction(diagram.pool) result = reduction.reduce(diagram.root_node.node_id, variables) else: reduction = SmtReduce(diagram.pool) result = reduction.reduce(diagram.root_node.node_id, variables) return Diagram(diagram.pool, result)
def reduce(self, variables=None, method="linear"): if method == "linear": from pyxadd.reduce import LinearReduction reducer = LinearReduction(self.pool) elif method == "smt": from pyxadd.reduce import SmtReduce reducer = SmtReduce(self.pool) else: raise RuntimeError("Unknown reduction method {} (valid options are 'linear' or 'smt')".format(method)) return Diagram(self.pool, reducer.reduce(self.root_node.node_id, variables))
def reduce(self, variables=None, method="linear", smt_solver=None): if method == "linear": from pyxadd.reduce import LinearReduction reducer = LinearReduction(self.pool) elif method == "smt": from pyxadd.reduce import SmtReduce reducer = SmtReduce(self.pool, solver=smt_solver) else: raise RuntimeError( "Unknown reduction method {} (valid options are 'linear' or 'smt')" .format(method)) return Diagram(self.pool, reducer.reduce(self.root_node.node_id, variables))
def test_constant(self): b = self.builder pool = b.pool test_d = b.limit("x", 1, 1) * b.exp(5) + b.limit("x", 2, 2) * b.exp(5) test_d = pool.diagram( LinearReduction(pool).reduce(test_d.root_node.node_id)) self.exporter.export(test_d, "test_d") # Test with profile add_profile_cache(pool) get_profile(self.diagram) self.exporter.export(self.diagram, "to_constant") constant = to_constant(self.diagram) get_profile(constant) self.exporter.export(constant, "constant") def t(_, node): self.assertTrue(is_constant(node), msg="{} still contains variables".format( node.expression)) walk_leaves(t, constant)
def test_mixed_symbolic(self): diagram_y = Diagram(self.diagram.pool, SummationWalker(self.diagram, "x").walk()) diagram_y = Diagram(diagram_y.pool, LinearReduction(diagram_y.pool).reduce(diagram_y.root_node.node_id, ["y"])) for y in range(0, 12): row_result = 0 for x in range(0, 12): row_result += self.diagram.evaluate({"x": x, "y": y}) self.assertEqual(diagram_y.evaluate({"y": y}), row_result)
def test_linear_reduce_2(self): diagram2 = self.build_diagram_2() # self.exporter.export(diagram2, "diagram2") variables = [("x", 0, 11), ("y", 0, 11)] reduced_linear2 = diagram2.pool.diagram(LinearReduction(diagram2.pool).reduce(diagram2.root_id)) # self.exporter.export(reduced_linear2, "reduced_linear2") self.control(variables, diagram2, reduced_linear2) reduced_smt2 = diagram2.pool.diagram(SmtReduce(diagram2.pool).reduce(diagram2.root_id)) # self.exporter.export(reduced_smt2, "reduced_smt2") self.control(variables, diagram2, reduced_smt2)
class ConstantWalker(DownUpWalker): def __init__(self, diagram, diagram_vars): DownUpWalker.__init__(self, diagram) self._diagram_vars = diagram_vars self._reduction = LinearReduction(self.diagram.pool) def visit_internal_aggregate(self, internal_node, true_result, false_result): node_id = self._reduction.reduce((true_result + false_result).root_node.node_id, self._diagram_vars) return self.diagram.pool.diagram(node_id) def visit_internal_down(self, internal_node, parent_message): if parent_message is None: parent_message = self._initial_message() bounds, path = parent_message bounds_t = dict(bounds) bounds_f = dict(bounds) # Avoiding having to find all integer points in complex areas by only looking at "simple" constraints operator = internal_node.test.operator if operator.is_singular(): var = operator.variables[0] lb, ub = bounds[var] if var in bounds else (-oo, oo) bounds_t[var] = internal_node.test.update_bounds(var, lb, ub, test=True) bounds_f[var] = internal_node.test.update_bounds(var, lb, ub, test=False) pool = self.diagram.pool path_t = path & pool.diagram(pool.internal(LinearTest(operator), pool.one_id, pool.zero_id)) path_f = path & pool.diagram(pool.internal(LinearTest(~operator), pool.one_id, pool.zero_id)) return (bounds_t, path_t), (bounds_f, path_f) def visit_terminal(self, terminal_node, parent_message): print(parent_message, terminal_node.expression) if parent_message is None: parent_message = self._initial_message() bounds, path = parent_message pool = self.diagram.pool if terminal_node.expression == 0: return pool.diagram(pool.zero_id) elif len(terminal_node.expression.free_symbols) == 0: return path * pool.diagram(terminal_node.node_id) else: variables_present = terminal_node.expression.free_symbols # FIXME todo return pool.diagram(pool.zero_id) def _initial_message(self): return {}, self.diagram.pool.diagram(self.diagram.pool.one_id)
def test_linear_reduce_1(self): diagram1 = self.build_diagram_1() # self.exporter.export(diagram1, "diagram1") variables = [("x", 0, 11)] reduced_linear1 = diagram1.pool.diagram(LinearReduction(diagram1.pool).reduce(diagram1.root_id)) # self.exporter.export(reduced_linear1, "reduced_linear1") self.control(variables, diagram1, reduced_linear1) reduced_smt1 = diagram1.pool.diagram(SmtReduce(diagram1.pool).reduce(diagram1.root_id)) # self.exporter.export(reduced_smt1, "reduced_smt1") self.control(variables, diagram1, reduced_smt1) reduced_simple1 = diagram1.pool.diagram(SimpleBoundReducer(diagram1.pool).reduce(diagram1.root_id)) # self.exporter.export(reduced_simple1, "reduced_simple1") self.control(variables, diagram1, reduced_simple1)
def test_reduce(self): self.exporter.export(self.diagram, "to_reduce") result = LinearReduction(self.diagram.pool).reduce( self.diagram.root_node.node_id, ["x"]) self.exporter.export(Diagram(self.diagram.pool, result), "result")
def __init__(self, diagram, diagram_vars): DownUpWalker.__init__(self, diagram) self._diagram_vars = diagram_vars self._reduction = LinearReduction(self.diagram.pool)
def test_reduce(self): diagram = build_diagram_1() result = LinearReduction(diagram.pool).reduce(diagram.root_id, ["r", "c"]) result = diagram.pool.diagram(result) self.assertEqual(3, get_terminal_count(result))