WD2 = matchpy.Wildcard.dot("WD2") WD3 = matchpy.Wildcard.dot("WD3") SYM1 = matchpy.Wildcard.symbol("SYM1") SYM2 = matchpy.Wildcard.symbol("SYM2") SYM3 = matchpy.Wildcard.symbol("SYM3") _A = matchpy.Wildcard.symbol( "_A" ) # It's important that this Wildcard has the same name as the one in the pattern for Cholesky WS1 = matchpy.Wildcard.star("WS1") WP1 = matchpy.Wildcard.plus("WP1") WP2 = matchpy.Wildcard.plus("WP2") eigen1 = matchpy.Pattern( Plus(Times(Transpose(SYM1), SYM2, SYM1), Times(WD1, SYM3), WS1), matchpy.CustomConstraint( lambda SYM1, SYM2, SYM3, WD1: SYM1.has_property(Property.ORTHOGONAL) and SYM2.has_property(Property.DIAGONAL) and WD1.has_property( Property.SCALAR) and SYM3.has_property(Property.IDENTITY))) def eigen1_callback(substitution, equations, eqn_idx, position): # Here, the "Eigen-Trick" is applied. That is, given # Plus([Q^T W Q + alpha I]), tmp = W + alpha I is extraced and the # entire expression is replaced with Times([Q^T tmp Q]) # The sum can not be computed directly with decompose_sum # because it is not necessarily a sufficiently simple # sum. equations_list = list(equations.equations) diagonal_sum = Plus(substitution["SYM2"], Times(substitution["WD1"], substitution["SYM3"])) tmp = temporaries.create_tmp(diagonal_sum, True)
##################### # Cholesky # # Note: We assume that all symmetric matrices are stored as lower triangular # matrices. Actually, that's not necessary in Julia, obtaining the other half is # just more expensive. Test which conversion is more expensive. # Actually, with storage format conversions, we don't need this assumption. _A = matchpy.Wildcard.symbol("_A", symbol_type=ae.Matrix) _L = matchpy.Wildcard.symbol("_L") cf = lambda d: (d["N"]**3) / 3 cholesky = FactorizationKernel( matchpy.Pattern( _A, matchpy.CustomConstraint(lambda _A: _A.has_property(Property.SPSD))), [InputOperand(_A, StorageFormat.symmetric_triangular)], Times(_L, Transpose(_L)), [ OutputOperand(_L, _A, ("N", "N"), [Property.LOWER_TRIANGULAR, Property.NON_SINGULAR], StorageFormat.lower_triangular) ], cf, None, CodeTemplate("""LinearAlgebra.LAPACK.potrf!('L', $_A)"""), None, [SizeArgument("N", _A, "rows")], ) #####################
# base case, length 0 vector register( Transpose(Sequence(sw("_", Int), VectorCallable()), w("array")), lambda _, array: array, ) # recursive case register( Transpose( Sequence( sw("_", Int), VectorCallable(Scalar(sw("first_order", Int)), ws("ordering"))), w("array"), ), _tranpose_sequence, matchpy.CustomConstraint(lambda ordering: all( isinstance(o, Scalar) and isinstance(o.operands[0], Int ) # type: ignore for o in ordering)), ) @operation(name="·", to_str=lambda op, l, r: f"({l} ·{op} {r})") def OuterProduct(op: CCallableBinary[CArray, CArray, CArray], l: CArray, r: CArray) -> CArray: ... register( OuterProduct(w("op"), Scalar(w("l")), w("r")), lambda op, l, r: BinaryOperation(op, Scalar(l), r), ) register(
def scalar_accessor_is(x, prefix=""): return matchpy.CustomConstraint(lambda y: y.value == x).with_renamed_vars( {"y": f"scalar_accessor_{prefix}"})
name = "ForwardGetAccessor" arity = matchpy.Arity(1, True) register( Get(x, ForwardGetAccessor(Array(x1, x2))), lambda x, x1, x2: Array(x1, Content(Get(x, x2))), ) # simplify unbound accessor that just forward register( GetBySubstituting(scalar_accessor, Array(x, Content(Get(unbound_accessor, x1)))), matchpy.CustomConstraint( lambda scalar_accessor, unbound_accessor: scalar_accessor.value == unbound_accessor.variable_name), lambda scalar_accessor, x, unbound_accessor, x1: ForwardGetAccessor( Array(x, x1)), ) def _abstract_with_dimension_inner(shape, content, n_dim, i=0): if i == n_dim: return Array(NoLengthAccessor(), content) return Array( Content(Get(ScalarAccessor(i), shape)), with_get(lambda idx: _abstract_with_dimension_inner( shape=shape, content=Content(Get(idx, content)),
return "Array{{{0},2}}".format(config.data_type_string) def remove_files(directory_name): if os.path.exists(directory_name): for file in os.listdir(directory_name): path_to_file = os.path.join(directory_name, file) if os.path.isfile(path_to_file): os.remove(path_to_file) WD1 = matchpy.Wildcard.dot("WD1") WD2 = matchpy.Wildcard.dot("WD2") WS1 = matchpy.Wildcard.star("WS1") WS2 = matchpy.Wildcard.star("WS2") PS1 = matchpy.CustomConstraint(lambda WD1: WD1.has_property(Property.MATRIX) or WD1.has_property(Property.VECTOR)) PS2 = matchpy.CustomConstraint(lambda WD2: WD2.has_property(Property.MATRIX) or WD2.has_property(Property.VECTOR)) notInv1 = matchpy.CustomConstraint(lambda WD1: not is_inverse(WD1)) notInv2 = matchpy.CustomConstraint(lambda WD2: not is_inverse(WD2)) linsolveL = matchpy.ReplacementRule( matchpy.Pattern(Times(WS1, Inverse(WD1), WD2, WS2), PS1, PS2), lambda WS1, WD1, WD2, WS2: Times(*WS1, LinSolveL(WD1, WD2), *WS2)) linsolveLT = matchpy.ReplacementRule( matchpy.Pattern(Times(WS1, InverseTranspose(WD1), WD2, WS2), PS1, PS2), lambda WS1, WD1, WD2, WS2: Times( *WS1, LinSolveL(Transpose(WD1), WD2), *WS2)) linsolveR = matchpy.ReplacementRule(
@symbol def SubstituteStatements( name: typing.Callable[..., CStatements]) -> CSubstituteStatements: ... def all_of_type(type_): return lambda args: all(isinstance(a, type_) for a in args) register( CallUnary(sw("fn", SubstituteStatements), VectorCallable(ws("args"))), lambda fn, args: fn.name(*(a.name for a in args)), matchpy.CustomConstraint(all_of_type(Statement)), ) def statements_then_init( fn: typing.Callable[[], typing.Generator[CStatements, None, CInitializer]] ) -> CInitializer: """ statements_then_init is called to wrap a function that yields a bunch of statements and then returns an initializer """ def inner(id_: CIdentifier) -> typing.Iterator[CStatements]: generator = fn() while True: try: