diff --git a/symja_android_library/tools/src/main/java/org/matheclipse/core/decisiontree/DecisionTree.java b/symja_android_library/tools/src/main/java/org/matheclipse/core/decisiontree/DecisionTree.java new file mode 100644 index 0000000000..856adec79e --- /dev/null +++ b/symja_android_library/tools/src/main/java/org/matheclipse/core/decisiontree/DecisionTree.java @@ -0,0 +1,610 @@ +package org.matheclipse.core.decisiontree; + +import static org.matheclipse.core.expression.F.C0; +import static org.matheclipse.core.expression.F.C1; +import static org.matheclipse.core.expression.F.C1D2; +import static org.matheclipse.core.expression.F.C1D4; +import static org.matheclipse.core.expression.F.C2; +import static org.matheclipse.core.expression.F.C2Pi; +import static org.matheclipse.core.expression.F.C3; +import static org.matheclipse.core.expression.F.C5; +import static org.matheclipse.core.expression.F.CI; +import static org.matheclipse.core.expression.F.CN1; +import static org.matheclipse.core.expression.F.CN1D2; +import static org.matheclipse.core.expression.F.CN2; +import static org.matheclipse.core.expression.F.CN3; +import static org.matheclipse.core.expression.F.CSqrtPi; +import static org.matheclipse.core.expression.F.Cos; +import static org.matheclipse.core.expression.F.Exp; +import static org.matheclipse.core.expression.F.Plus; +import static org.matheclipse.core.expression.F.Power; +import static org.matheclipse.core.expression.F.QQ; +import static org.matheclipse.core.expression.F.Sin; +import static org.matheclipse.core.expression.F.SphericalHarmonicY; +import static org.matheclipse.core.expression.F.Sqr; +import static org.matheclipse.core.expression.F.Sqrt; +import static org.matheclipse.core.expression.F.Times; +import static org.matheclipse.core.expression.F.ZZ; +import static org.matheclipse.core.expression.F.n_; +import static org.matheclipse.core.expression.F.p_; +import static org.matheclipse.core.expression.F.t_; +import static org.matheclipse.core.expression.S.Pi; +import static org.matheclipse.core.expression.S.n; +import static org.matheclipse.core.expression.S.p; +import static org.matheclipse.core.expression.S.t; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.Stack; +import java.util.TreeMap; +import java.util.TreeSet; +import org.matheclipse.core.eval.EvalEngine; +import org.matheclipse.core.eval.util.SourceCodeProperties; +import org.matheclipse.core.expression.F; +import org.matheclipse.core.expression.Pattern; +import org.matheclipse.core.generic.GenericPair; +import org.matheclipse.core.interfaces.IAST; +import org.matheclipse.core.interfaces.IASTAppendable; +import org.matheclipse.core.interfaces.IExpr; +import org.matheclipse.core.interfaces.IPattern; +import org.matheclipse.core.interfaces.ISymbol; +import org.matheclipse.core.patternmatching.IPatternMatcher; +import org.matheclipse.core.patternmatching.PatternMatcherAndEvaluator; + +public class DecisionTree { + Map> treeMap = new TreeMap<>(); + + public Set>> entrySet() { + return treeMap.entrySet(); + } + + public TreeSet get(int key) { + return treeMap.get(key); + } + + public DecisionTree() {} + + public Set put(Integer key, TreeSet value) { + return treeMap.put(key, value); + } + + public int size() { + return treeMap.size(); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + + for (Map.Entry> entry : treeMap.entrySet()) { + Integer key = entry.getKey(); + Set set = entry.getValue(); + for (DiscriminationNode val : set) { + buf.append(key.toString()); + buf.append(" -> ["); + buf.append(val.expr().toString()); + buf.append(", "); + DecisionTree net = val.decisionTree(); + if (net != null) { + buf.append("\n"); + buf.append(net.toString()); + } + buf.append(","); + List downRules = val.downRules(); + if (downRules != null) { + buf.append(downRules.toString()); + } + buf.append("] | "); + } + + } + return buf.toString(); + } + + public final static List putDownRule(final int setSymbol, + final IExpr leftHandSide, final IExpr rightHandSide, List pmList) { + final PatternMatcherAndEvaluator pmEvaluator = + new PatternMatcherAndEvaluator(setSymbol, leftHandSide, rightHandSide, false, 0); + pmList.add(pmEvaluator); + return pmList; + } + + private static boolean insertRule(DecisionTree[] dts, IAST lhs, IExpr rhs) { + if (!lhs.forAll(x -> x.isFreeOfPatterns() || (x.isPattern() && !x.isPatternDefault()), 0)) { + return false; + } + if (lhs.forAll(x -> x.isFreeOfPatterns(), 0)) { + // "equals" rules don't need a decision tree + return false; + } + DecisionTree net = dts[lhs.size()]; + + DiscriminationNode node = null; + for (int i = 0; i < lhs.size(); i++) { + IExpr arg = lhs.get(i); + if (arg.isFreeOfPatterns()) { + if (node != null) { + DecisionTree subNet = node.decisionTree(); + if (subNet == null) { + subNet = new DecisionTree(); + node.decisionTree = subNet; + net = subNet; + } + } + TreeSet set = net.get(i); + if (set == null) { + set = new TreeSet(); + node = new DiscriminationNode(arg, null, null); + set.add(node); + net.put(i, set); + } else { + node = new DiscriminationNode(arg, null, null); + DiscriminationNode floor = set.floor(node); + if (floor != null && floor.equals(node)) { + node = floor; + net = node.decisionTree; + } else { + set.add(node); + } + } + } + } + for (int i = 0; i < lhs.size(); i++) { + IExpr arg = lhs.get(i); + if (arg.isPattern()) { + Pattern p = (Pattern) arg; + if (node != null) { + DecisionTree subNet = node.decisionTree(); + if (subNet == null) { + subNet = new DecisionTree(); + node.decisionTree = subNet; + net = subNet; + } + } + TreeSet set = net.get(i); + if (set == null) { + set = new TreeSet(); + node = new DiscriminationNode(p, null, null); + set.add(node); + net.put(i, set); + } else { + node = new DiscriminationNode(p, null, null); + DiscriminationNode floor = set.floor(node); + if (floor != null && floor.equals(node)) { + node = floor; + net = node.decisionTree; + } else { + set.add(node); + } + } + } + } + if (node != null) { + List downRules = node.downRules(); + if (downRules == null) { + node.patternDownRules = new ArrayList(); + } + PatternMatcherAndEvaluator pm = new PatternMatcherAndEvaluator(lhs, rhs); + node.patternDownRules.add(pm); + } + return true; + } + + /** + * Experimental. Don't use it. + * + * @param dn + * @param evalLHS + * @return + * @deprecated + */ + @Deprecated + private static IExpr matchLHSRecursive(DecisionTree dn, IAST evalLHS) { + DecisionTree net = dn; + DiscriminationNode node = null; + for (Map.Entry> entry : net.entrySet()) { + Integer key = entry.getKey(); + TreeSet set = entry.getValue(); + IExpr arg = evalLHS.get(key); + node = new DiscriminationNode(arg, null, null); + DiscriminationNode floor = set.floor(node); + if (node.equals(floor)) { + List downRules = floor.downRules(); + if (downRules != null) { + // match downRules + for (int i = 0; i < downRules.size(); i++) { + IPatternMatcher patternMatcher = downRules.get(i); + IExpr result = patternMatcher.eval(evalLHS, EvalEngine.get()); + if (result.isPresent()) { + return result; + } + } + } + DecisionTree subNet = floor.decisionTree(); + if (subNet != null) { + IExpr temp = matchLHSRecursive(subNet, evalLHS); + if (temp.isPresent()) { + return temp; + } + } + } + } + return F.NIL; + } + + private static CharSequence toJava(IExpr expr) { + return expr.internalJavaString(SourceCodeProperties.JAVA_FORM_PROPERTIES_NO_SYMBOL_PREFIX, 0, + z -> null); + } + + private static IExpr toJavaMethodRecursive(DecisionTree dn, StringBuilder buf, + List> patternIndexMap) { + DecisionTree net = dn; + boolean patternEval = false; + for (Map.Entry> entry : net.entrySet()) { + int index = entry.getKey(); + String arg = EvalEngine.uniqueName("a"); + buf.append("IExpr " + arg + " = evalLHS.get(" + index + ");\n"); + TreeSet set = entry.getValue(); + for (DiscriminationNode node : set) { + + String x = EvalEngine.uniqueName("x"); + IExpr expr = node.expr(); + CharSequence patternValueVar = null; + ISymbol patternSymbol = null; + IPattern pattern = null; + if (expr.isPattern()) { + patternEval = true; + pattern = (IPattern) expr; + patternSymbol = pattern.getSymbol(); + for (int i = 0; i < patternIndexMap.size(); i++) { + GenericPair pair = patternIndexMap.get(i); + if (pair.getFirst().equals(patternSymbol)) { + patternValueVar = pair.getSecond(); + break; + } + } + } else { + patternValueVar = toJava(expr); + } + try { + if (patternValueVar == null) { + buf.append("IPattern " + x + " = (IPattern)" + toJava(pattern) + ";\n"); + buf.append("if (" + x + ".isConditionMatched(" + arg + ",null)) {\n"); + buf.append("patternIndexMap.push(new GenericPair(" + arg + ", " + x + + ".getSymbol()));\n"); + buf.append("try {\n"); + patternIndexMap.add(new GenericPair(patternSymbol, arg)); + } else { + buf.append("IExpr " + x + " = " + patternValueVar + ";\n"); + buf.append("if (" + x + ".equals(" + arg + ")) {\n"); + } + List downRules = node.downRules(); + if (downRules != null) { + // match downRules + for (int i = 0; i < downRules.size(); i++) { + IPatternMatcher pm = downRules.get(i); + if (patternEval) { + + buf.append("result = PatternMatcherAndEvaluator.evalInternal(evalLHS," + + toJava(pm.getRHS()) + ", patternIndexMap );\n"); + + } else { + + buf.append("pm = new PatternMatcherAndEvaluator(" + toJava(pm.getLHS()) + "," + + toJava(pm.getRHS()) + ");\n"); + buf.append("result = pm.eval(evalLHS, engine);\n"); + + } + + buf.append("if (result.isPresent()) { return result; }\n"); + } + } + DecisionTree subTree = node.decisionTree(); + if (subTree != null) { + IExpr temp = toJavaMethodRecursive(subTree, buf, patternIndexMap); + if (temp.isPresent()) { + return temp; + } + } + if (patternValueVar == null) { + buf.append("} finally { patternIndexMap.pop(); }\n"); + } + } finally { + if (patternValueVar == null) { + patternIndexMap.remove(patternIndexMap.size() - 1); + } + } + buf.append("\n}\n"); + } + + } + + return F.NIL; + + } + + + public static void main(String[] args) { + F.initSymbols(); + TreeMap ts; + + List pmList = new ArrayList(); + putDownRule(IPatternMatcher.SET_DELAYED, F.Beta(F.C0, F.C1, F.a_, F.b_), F.List(F.a, F.b), + pmList); + + // SphericalHarmonicY(0, 0, t_, p_) = 1/(2*Sqrt(Pi)), + IAST lhs1 = SphericalHarmonicY(C0, C0, t_, p_); + IExpr rhs1 = Times(C1D2, Power(Pi, CN1D2)); + // SphericalHarmonicY(1, -1, t_, p_) := ((1/2)*Sqrt(3/(2*Pi))*Sin(t))/E^(I*p), + IAST lhs2 = SphericalHarmonicY(C1, CN1, t_, p_); + IExpr rhs2 = + Times(C1D2, Power(Exp(Times(CI, p)), CN1), Sqrt(Times(C3, Power(C2Pi, CN1))), Sin(t)); + // SphericalHarmonicY(1, 1, t_, p_) := (-1/2)*E^(I*p)*Sqrt(3/(2*Pi))*Sin(t), + IAST lhs3 = SphericalHarmonicY(C1, C1, t_, p_); + IExpr rhs3 = Times(CN1D2, Exp(Times(CI, p)), Sqrt(Times(C3, Power(C2Pi, CN1))), Sin(t)); + IAST lhs3a = SphericalHarmonicY(C1, C3, t_, t_); + IExpr rhs3a = Times(CN1D2, Exp(Times(CI, t)), Sqrt(Times(C3, Power(C2Pi, CN1))), Sin(t)); + // SphericalHarmonicY(n_, 0, 0, p_) := Sqrt(1 + 2*n)/(2*Sqrt(Pi)), + IAST lhs4 = SphericalHarmonicY(n_, C0, C0, p_); + IExpr rhs4 = Times(Sqrt(Plus(C1, Times(C2, n))), Power(Times(C2, CSqrtPi), CN1)); + // SphericalHarmonicY(2, -2, t_, p_) := ((1/4)*Sqrt(15/(2*Pi))*Sin(t)^2)/E^(2*I*p), + IAST lhs5 = SphericalHarmonicY(C2, CN2, t_, p_); + IExpr rhs5 = Times(C1D4, Power(Exp(Times(C2, CI, p)), CN1), + Sqrt(Times(ZZ(15L), Power(C2Pi, CN1))), Sqr(Sin(t))); + // SphericalHarmonicY(2, -1, t_, p_) := ((1/2)*Sqrt(15/(2*Pi))*Cos(t)*Sin(t))/E^(I*p); + IAST lhs6 = SphericalHarmonicY(C3, CN3, t_, p_); + IExpr rhs6 = Times(QQ(1L, 8L), Power(Exp(Times(C3, CI, p)), CN1), + Sqrt(Times(ZZ(35L), Power(Pi, CN1))), Power(Sin(t), C3)); + // SphericalHarmonicY(2, 0, t_, p_) := (1/4)*Sqrt(5/Pi)*(-1 + 3*Cos(t)^2), + IAST lhs7 = SphericalHarmonicY(C3, CN2, t_, p_); + IExpr rhs7 = Times(C1D4, Power(Exp(Times(C2, CI, p)), CN1), + Sqrt(Times(ZZ(105L), Power(C2Pi, CN1))), Cos(t), Sqr(Sin(t))); + // SphericalHarmonicY(3, -3, t_, p_) := ((1/8)*Sqrt(35/Pi)*Sin(t)^3)/E^(3*I*p), + IAST lhs8 = SphericalHarmonicY(C3, CN1, t_, p_); + IExpr rhs8 = Times(QQ(1L, 8L), Power(Exp(Times(CI, p)), CN1), + Sqrt(Times(ZZ(21L), Power(Pi, CN1))), Plus(CN1, Times(C5, Sqr(Cos(t)))), Sin(t)); + // SphericalHarmonicY(3, -2, t_, p_) := ((1/4)*Sqrt(105/(2*Pi))*Cos(t)*Sin(t)^2)/E^(2*I*p), + // SphericalHarmonicY(3, -1, t_, p_) := ((1/8)*Sqrt(21/Pi)*(-1 + 5*Cos(t)^2)*Sin(t))/E^(I*p), + // SphericalHarmonicY(3, 0, t_, p_) := (1/4)*Sqrt(7/Pi)*(-3*Cos(t) + 5*Cos(t)^3), + // SphericalHarmonicY(3, 1, t_, p_) := (-(1/8))*E^(I*p)*Sqrt(21/Pi)*(-1 + 5*Cos(t)^2)*Sin(t), + // SphericalHarmonicY(3, 2, t_, p_) := (1/4)*E^(2*I*p)*Sqrt(105/(2*Pi))*Cos(t)*Sin(t)^2, + // SphericalHarmonicY(3, 3, t_, p_) + + + // DiscriminationNet netLevel2 = new DiscriminationNet(); + // netLevel1.put(2, new DiscriminationRecord(F.C0, netLevel2, null)); + // netLevel1.put(3, new DiscriminationRecord(F.C1, null, pmList)); + // netLevel2.put(3, new DiscriminationRecord(F.C1, null, pmList)); + + DecisionTree[] dts = new DecisionTree[10]; + for (int i = 0; i < dts.length; i++) { + dts[i] = new DecisionTree(); + } + insertRule(dts, lhs1, rhs1); + insertRule(dts, lhs2, rhs2); + insertRule(dts, lhs3, rhs3); + insertRule(dts, lhs3a, rhs3a); + for (int i = 0; i < dts.length; i++) { + if (dts[i].size() > 0) { + System.out.println(dts[i].toString()); + } + } + + IAST evalAST = SphericalHarmonicY(C1, C1, F.C10, F.ZZ(12)); + IExpr result = matchLHSRecursive(dts[evalAST.size()], evalAST); + System.out.println("\nResult: " + result.toString()); + + evalAST = SphericalHarmonicY(C1, CN1, F.C10, F.ZZ(12)); + // result = matchLHSRecursive(rootNet, evalAST); + result = match5(evalAST, EvalEngine.get()); + System.out.println("\nResult: " + result.toString()); + + StringBuilder buf = toJavaMethods(dts); + + System.out.println(buf.toString()); + } + + public static String insertRules(IASTAppendable rules) { + DecisionTree[] dts = new DecisionTree[10]; + for (int i = 0; i < dts.length; i++) { + dts[i] = new DecisionTree(); + } + int i = 1; + while (i < rules.size()) { + IExpr setDelayed = rules.get(i); + if (setDelayed.isAST2()) { + IExpr lhs = ((IAST) setDelayed).arg1(); + IExpr rhs = ((IAST) setDelayed).arg2(); + if (lhs.isAST()) { + if (insertRule(dts, (IAST) lhs, rhs)) { + rules.remove(i); + continue; + } + } + } + i++; + } + // for (int i = 0; i < dts.length; i++) { + // if (dts[i].size() > 0) { + // // System.out.println(dts[i].toString()); + // } + // } + StringBuilder buf = toJavaMethods(dts); + System.out.println(buf.toString()); + return buf.toString(); + } + + private static StringBuilder toJavaMethods(DecisionTree[] dts) { + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < dts.length; i++) { + DecisionTree decisionTree = dts[i]; + if (decisionTree.size() > 0) { + toSingleJavaMethod(decisionTree, buf, i); + } + } + return buf; + } + + private static void toSingleJavaMethod(DecisionTree decisionTree, StringBuilder buf, + int methodNumber) { + buf.append( + "\n\npublic static IExpr match" + methodNumber + "(IAST evalLHS, EvalEngine engine) {\n"); + buf.append( + "Stack> patternIndexMap = new Stack>();\n"); + // buf.append("PatternMatcherAndEvaluator pm = null;\n"); + buf.append("IExpr result = F.NIL;\n"); + + List> patternIndexMap = + new ArrayList>(); + toJavaMethodRecursive(decisionTree, buf, patternIndexMap); + buf.append("return F.NIL;\n"); + buf.append("\n}\n\n"); + } + + public static IExpr match5(IAST evalLHS, EvalEngine engine) { + Stack> patternIndexMap = new Stack>(); + IExpr result = F.NIL; + IExpr a1 = evalLHS.get(0); + IExpr x2 = F.SphericalHarmonicY; + if (x2.equals(a1)) { + IExpr a3 = evalLHS.get(1); + IExpr x4 = F.C0; + if (x4.equals(a3)) { + IExpr a5 = evalLHS.get(2); + IExpr x6 = F.C0; + if (x6.equals(a5)) { + IExpr a7 = evalLHS.get(3); + IPattern x8 = F.t_; + if (x8.isConditionMatched(a7, null)) { + patternIndexMap.push(new GenericPair(a7, x8.getSymbol())); + try { + IExpr a9 = evalLHS.get(4); + IPattern x10 = F.p_; + if (x10.isConditionMatched(a9, null)) { + patternIndexMap.push(new GenericPair(a9, x10.getSymbol())); + try { + result = PatternMatcherAndEvaluator.evalInternal(evalLHS, + F.Times(F.C1D2, F.Power(F.Pi, F.CN1D2)), patternIndexMap); + if (result.isPresent()) { + return result; + } + } finally { + patternIndexMap.pop(); + } + + } + } finally { + patternIndexMap.pop(); + } + + } + + } + + } + IExpr x11 = F.C1; + if (x11.equals(a3)) { + IExpr a12 = evalLHS.get(2); + IExpr x13 = F.CN1; + if (x13.equals(a12)) { + IExpr a14 = evalLHS.get(3); + IPattern x15 = F.t_; + if (x15.isConditionMatched(a14, null)) { + patternIndexMap.push(new GenericPair(a14, x15.getSymbol())); + try { + IExpr a16 = evalLHS.get(4); + IPattern x17 = F.p_; + if (x17.isConditionMatched(a16, null)) { + patternIndexMap.push(new GenericPair(a16, x17.getSymbol())); + try { + result = PatternMatcherAndEvaluator.evalInternal(evalLHS, + F.Times(F.C1D2, F.Power(F.Exp(F.Times(F.CI, p)), F.CN1), + F.Sqrt(F.Times(F.C3, F.Power(F.C2Pi, F.CN1))), F.Sin(t)), + patternIndexMap); + if (result.isPresent()) { + return result; + } + } finally { + patternIndexMap.pop(); + } + + } + } finally { + patternIndexMap.pop(); + } + + } + + } + IExpr x18 = F.C1; + if (x18.equals(a12)) { + IExpr a19 = evalLHS.get(3); + IPattern x20 = F.t_; + if (x20.isConditionMatched(a19, null)) { + patternIndexMap.push(new GenericPair(a19, x20.getSymbol())); + try { + IExpr a21 = evalLHS.get(4); + IPattern x22 = F.p_; + if (x22.isConditionMatched(a21, null)) { + patternIndexMap.push(new GenericPair(a21, x22.getSymbol())); + try { + result = PatternMatcherAndEvaluator.evalInternal(evalLHS, + F.Times(F.CN1D2, F.Exp(F.Times(F.CI, p)), + F.Sqrt(F.Times(F.C3, F.Power(F.C2Pi, F.CN1))), F.Sin(t)), + patternIndexMap); + if (result.isPresent()) { + return result; + } + } finally { + patternIndexMap.pop(); + } + + } + } finally { + patternIndexMap.pop(); + } + + } + + } + IExpr x23 = F.C3; + if (x23.equals(a12)) { + IExpr a24 = evalLHS.get(3); + IPattern x25 = F.t_; + if (x25.isConditionMatched(a24, null)) { + patternIndexMap.push(new GenericPair(a24, x25.getSymbol())); + try { + IExpr a26 = evalLHS.get(4); + IExpr x27 = a24; + if (x27.equals(a26)) { + result = + PatternMatcherAndEvaluator.evalInternal(evalLHS, + F.Times(F.CN1D2, F.Exp(F.Times(F.CI, t)), + F.Sqrt(F.Times(F.C3, F.Power(F.C2Pi, F.CN1))), F.Sin(t)), + patternIndexMap); + if (result.isPresent()) { + return result; + } + + } + } finally { + patternIndexMap.pop(); + } + + } + + } + + } + + } + return F.NIL; + + } + + + +} diff --git a/symja_android_library/tools/src/main/java/org/matheclipse/core/decisiontree/DiscriminationNode.java b/symja_android_library/tools/src/main/java/org/matheclipse/core/decisiontree/DiscriminationNode.java new file mode 100644 index 0000000000..2b9a23809c --- /dev/null +++ b/symja_android_library/tools/src/main/java/org/matheclipse/core/decisiontree/DiscriminationNode.java @@ -0,0 +1,57 @@ +package org.matheclipse.core.decisiontree; + +import java.util.List; +import org.matheclipse.core.interfaces.IExpr; +import org.matheclipse.core.patternmatching.IPatternMatcher; + +public class DiscriminationNode implements Comparable { + IExpr value; + + DecisionTree decisionTree; + + List patternDownRules; + + public DiscriminationNode(IExpr value, DecisionTree dn, + List patternDownRules) { + this.value = value; + this.decisionTree = dn; + this.patternDownRules = patternDownRules; + } + @Override + public int compareTo(DiscriminationNode o) { + return value.compareTo(o.value); + } + + public DecisionTree decisionTree() { + return decisionTree; + } + + public List downRules() { + return patternDownRules; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + DiscriminationNode other = (DiscriminationNode) obj; + return value.equals(other.value); + } + + public boolean equalsValue(IExpr expr) { + return value.equals(expr); + } + + public IExpr expr() { + return value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/symja_android_library/tools/src/main/java/org/matheclipse/core/decisiontree/RulesToDecisionTree.java b/symja_android_library/tools/src/main/java/org/matheclipse/core/decisiontree/RulesToDecisionTree.java new file mode 100644 index 0000000000..fdedbfd07f --- /dev/null +++ b/symja_android_library/tools/src/main/java/org/matheclipse/core/decisiontree/RulesToDecisionTree.java @@ -0,0 +1,688 @@ +package org.matheclipse.core.decisiontree; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import org.matheclipse.core.eval.EvalEngine; +import org.matheclipse.core.eval.util.SourceCodeProperties; +import org.matheclipse.core.expression.F; +import org.matheclipse.core.expression.S; +import org.matheclipse.core.expression.WL; +import org.matheclipse.core.interfaces.IAST; +import org.matheclipse.core.interfaces.IASTAppendable; +import org.matheclipse.core.interfaces.IASTMutable; +import org.matheclipse.core.interfaces.IExpr; +import org.matheclipse.core.parser.ExprParser; +import org.matheclipse.core.patternmatching.RulesData; +import org.matheclipse.parser.client.ParserConfig; + +/** Generate java sources for Symja rule files. */ +public class RulesToDecisionTree { + private static SourceCodeProperties p = + SourceCodeProperties.of(false, false, SourceCodeProperties.Prefix.NONE, false); + + /** + * If true abort rule creation, if the left-hand-side contains a variable (instead of + * an expected pattern) + */ + private static boolean TEST_LHS_FOR_VARIABLES = false; + + static final String PACKAGE = "package org.matheclipse.core.reflection.system."; + + static final String HEADER_CLASS = "\n" + "import static org.matheclipse.core.expression.F.*;\n" // + + "import org.matheclipse.core.interfaces.IAST;\n" // + + "import static org.matheclipse.core.expression.S.*;\n" // + + "import java.util.Stack;\n" // + + "import java.util.Stack;\n" // + + "import org.matheclipse.core.eval.EvalEngine;\n" // + + "import org.matheclipse.core.expression.F;\n" // + + "import org.matheclipse.core.generic.GenericPair;\n" // + + "import org.matheclipse.core.interfaces.IAST;\n" // + + "import org.matheclipse.core.interfaces.IExpr;\n" // + + "import org.matheclipse.core.interfaces.IPattern;\n" // + + "import org.matheclipse.core.interfaces.ISymbol;\n" // + + "import org.matheclipse.core.patternmatching.PatternMatcherAndEvaluator;"// + + "\n" // + + "/**\n" // + + " *

Generated by org.matheclipse.core.preprocessor.RulePreprocessor.

\n" // + + " *

See GIT repository at: github.com/axkr/symja_android_library under the tools directory.

\n" // + + " */\n" + "public class "; + + static final String HEADER_INTERFACE = "\n" + + "import static org.matheclipse.core.expression.F.*;\n" // + + "import org.matheclipse.core.interfaces.ISymbol;\n" // + + "import org.matheclipse.core.interfaces.IAST;\n" // + + "import org.matheclipse.core.patternmatching.Matcher;\n" // + + "/**\n" // + + " *

Generated by org.matheclipse.core.preprocessor.RulePreprocessor.

\n" // + + " *

See GIT repository at: github.com/axkr/symja_android_library under the tools directory.

\n" // + + " */\n" + "public interface "; + + static final String HEADER_AUTO = "\n" + "import static org.matheclipse.core.expression.F.*;\n" // + + "import org.matheclipse.core.interfaces.ISymbol;\n" // + + "import org.matheclipse.core.interfaces.IAST;\n" // + + "import org.matheclipse.core.patternmatching.Matcher;\n" // + + "/**\n" + + " *

Generated by org.matheclipse.core.preprocessor.RulePreprocessor.

\n" // + + " *

See GIT repository at: github.com/axkr/symja_android_library under the tools directory.

\n" + + " */\n" + "public class "; + + static final String SIZES = " /**\n" + " *
    \n" + + " *
  • index 0 - number of equal rules in RULES
  • \n" + " *
\n" + + " */\n" + " final public static int[] SIZES = { "; + + private static final String LIST0 = " final public static IAST RULES"; + private static final String LIST1 = " = List("; + + static final String FOOTER0 = " );\n"; + static final String FOOTER1 = "}"; + + public RulesToDecisionTree() {} + + public static void appendSetDelayedToRule(IAST ast, StringBuilder buffer, boolean evalRHS, + boolean last, boolean createISet) { + IExpr leftHandSide = ast.arg1(); + IExpr rightHandSide = ast.arg2(); + if (leftHandSide.isAST()) { + if (TEST_LHS_FOR_VARIABLES && !leftHandSide.isFree(x -> x.isVariable() && // + !x.isBuiltInSymbol(), true)) { + throw new IllegalArgumentException( + "Variable used in left-hand-side of rule: " + ast.toString()); + } + // leftHandSide = EvalEngine.get().evalHoldPattern((IAST) leftHandSide); + } + if (evalRHS) { + rightHandSide = F.eval(rightHandSide); + } + buffer.append(leftHandSide.internalJavaString(p, 1, x -> null)); + buffer.append(",\n "); + buffer.append(rightHandSide.internalJavaString(p, 1, x -> null)); + if (createISet && leftHandSide.isFreeOfPatterns() && !leftHandSide.isSymbol()) { + buffer.append(", true"); + } + if (last) { + buffer.append(")\n"); + } else { + buffer.append("),\n"); + } + } + + public static void appendSetDelayedToMatcher(IAST ast, StringBuilder buffer, boolean evalRHS, + boolean last) { + IExpr leftHandSide = ast.arg1(); + IExpr rightHandSide = ast.arg2(); + if (leftHandSide.isAST()) { + if (TEST_LHS_FOR_VARIABLES && !leftHandSide.isFree(x -> x.isVariable() && // + !x.isBuiltInSymbol(), true)) { + throw new IllegalArgumentException( + "Variable used in left-hand-side of rule: " + ast.toString()); + } + leftHandSide = EvalEngine.get().evalHoldPattern((IAST) leftHandSide); + } + if (evalRHS) { + rightHandSide = F.eval(rightHandSide); + } + buffer.append(leftHandSide.internalJavaString(p, 1, x -> null)); + buffer.append(",\n "); + buffer.append(rightHandSide.internalJavaString(p, 1, x -> null)); + buffer.append(");\n"); + } + + public static void convertList(IExpr expr, String rulePostfix, StringBuilder buffer, + final PrintWriter out, String symbolName, EvalEngine engine) { + try { + // if (expr.isListOfLists()) { + // IAST list = (IAST) expr; + // for (int i = 1; i < list.size(); i++) { + // convertExpr(list.get(i), Integer.toString(i), out, null); + // } + // } else { + convertListExpr(expr, rulePostfix, out, symbolName); + // } + } catch (UnsupportedOperationException uoe) { + System.out.println(uoe.getMessage()); + System.out.println(expr.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static byte[] convertListSerialized(IExpr expr, StringBuilder buffer, + final PrintWriter out, EvalEngine engine) { + try { + return convertSerialized(expr, out); + } catch (UnsupportedOperationException uoe) { + System.out.println(uoe.getMessage()); + System.out.println(expr.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static void convert(IExpr expr, String rulePostfix, final PrintWriter out, + String symbolName, boolean createMatcher, EvalEngine engine) { + try { + + if (expr.isListOfLists()) { + IAST list = (IAST) expr; + for (int i = 1; i < list.size(); i++) { + if (createMatcher) { + convertToMatcher(list.get(i), Integer.toString(i), out, null, engine); + } else { + convertToRule(list.get(i), Integer.toString(i), out, null, engine); + } + } + } else { + if (createMatcher) { + convertToMatcher(expr, rulePostfix, out, symbolName, engine); + } else { + convertToRule(expr, rulePostfix, out, symbolName, engine); + } + } + } catch (UnsupportedOperationException uoe) { + System.out.println(uoe.getMessage()); + System.out.println(expr.toString()); + } + } + + private static void convertToRule(IExpr expr, String rulePostfix, final PrintWriter out, + String symbolName, EvalEngine engine) { + boolean last; + StringBuilder buffer = new StringBuilder(); + String decisionTree = ""; + // ArraySet headerSymbols = new ArraySet(); + if (expr.isAST()) { + IASTAppendable list = ((IAST) expr).copyAppendable(); + decisionTree = DecisionTree.insertRules(list); + if (symbolName != null) { + int equalsRuleCounter = 0; + int simpleRuleCounter = 0; + for (int i = 1; i < list.size(); i++) { + last = i == (list.argSize()); + expr = list.get(i); + if (expr.isAST(S.SetDelayed, 3)) { + IAST ast = (IAST) expr; + if (!RulesData.isComplicatedPatternRule(ast.arg1())) { + simpleRuleCounter++; + } + } else if (expr.isAST(S.Set, 3)) { + equalsRuleCounter++; + } + } + + out.print(SIZES); + out.append(Integer.toString(equalsRuleCounter)); + out.append(", "); + out.append(Integer.toString(simpleRuleCounter)); + out.append(" };\n\n"); + buffer.append(" IInit("); + buffer.append(symbolName); + if (equalsRuleCounter > 0 || simpleRuleCounter > 0 || list.size() > 1) { + buffer.append(", SIZES),\n"); + } else { + buffer.append(", SIZES) \n"); + } + } + + for (int i = 1; i < list.size(); i++) { + last = i == (list.argSize()); + expr = list.get(i); + if (expr.isAST(S.SetDelayed, 3)) { + IASTMutable ast = ((IAST) expr).copy(); + if (ast.arg1().isAST()) { + ast.set(1, engine.evalHoldPattern((IAST) ast.arg1())); + } + buffer.append(" // " + ast.toString().replaceAll("\\n", "") + "\n"); + + buffer.append(" ISetDelayed("); + + appendSetDelayedToRule(ast, buffer, false, last, true); + } else if (expr.isAST(S.Set, 3)) { + IASTMutable ast = ((IAST) expr).copy(); + if (ast.arg1().isAST()) { + ast.set(1, engine.evalHoldPattern((IAST) ast.arg1())); + } + buffer.append(" // " + ast.toString().replaceAll("\\n", "") + "\n"); + + buffer.append(" ISet("); + + appendSetDelayedToRule(ast, buffer, true, last, true); + } else if (expr.isAST(S.Rule, 3)) { + IASTMutable ast = ((IAST) expr).copy(); + if (ast.arg1().isAST()) { + ast.set(1, engine.evalHoldPattern((IAST) ast.arg1())); + } + buffer.append(" // " + ast.toString().replaceAll("\\n", "") + "\n"); + buffer.append(" Rule("); + appendSetDelayedToRule(ast, buffer, true, last, false); + } + } + } else { + if (expr.isAST(S.SetDelayed, 3)) { + IAST ast = (IAST) expr; + + buffer.append(" ISetDelayed("); + + appendSetDelayedToRule(ast, buffer, false, true, false); + } else if (expr.isAST(S.Set, 3)) { + IAST ast = (IAST) expr; + + buffer.append(" ISet("); + + appendSetDelayedToRule(ast, buffer, true, true, false); + } else if (expr.isAST(S.Rule, 3)) { + IAST ast = (IAST) expr; + buffer.append(" Rule("); + appendSetDelayedToRule(ast, buffer, true, true, false); + } + } + out.print(LIST0); + out.print(rulePostfix); + out.println(LIST1); + out.print(buffer.toString()); + out.print(FOOTER0); + out.print(decisionTree); + } + + private static void convertToMatcher(IExpr expr, String rulePostfix, final PrintWriter out, + String symbolName, EvalEngine engine) { + boolean last; + StringBuilder buffer = new StringBuilder(); + StringBuilder symbolBuffer = new StringBuilder(); + // ArraySet headerSymbols = new ArraySet(); + if (expr.isAST()) { + IAST list = (IAST) expr; + + for (int i = 1; i < list.size(); i++) { + last = i == (list.argSize()); + expr = list.get(i); + if (expr.isSymbol()) { + String name = expr.toString(); + symbolBuffer + .append("\n public final static ISymbol " + name + " = Dummy(\"" + name + "\");\n"); + } else if (expr.isAST(S.SetDelayed, 3)) { + IASTMutable ast = ((IAST) expr).copy(); + if (ast.arg1().isAST()) { + ast.set(1, engine.evalHoldPattern((IAST) ast.arg1())); + } + buffer.append(" // " + ast.toString().replaceAll("\\n", "") + "\n"); + buffer.append("matcher.caseOf("); + appendSetDelayedToMatcher(ast, buffer, false, last); + } else if (expr.isAST(S.Set, 3)) { + IASTMutable ast = ((IAST) expr).copy(); + if (ast.arg1().isAST()) { + ast.set(1, engine.evalHoldPattern((IAST) ast.arg1())); + } + buffer.append(" // " + ast.toString().replaceAll("\\n", "") + "\n"); + buffer.append("matcher.caseOf("); + appendSetDelayedToMatcher(ast, buffer, true, last); + } else if (expr.isAST(S.Rule, 3)) { + throw new UnsupportedOperationException(); + } + } + } else { + if (expr.isSymbol()) { + String name = expr.toString(); + symbolBuffer + .append("\n public final static ISymbol " + name + " = Dummy(\"" + name + "\");\n"); + } else if (expr.isAST(S.SetDelayed, 3)) { + IAST ast = (IAST) expr; + buffer.append("matcher.caseOf("); + appendSetDelayedToMatcher(ast, buffer, false, true); + } else if (expr.isAST(S.Set, 3)) { + IAST ast = (IAST) expr; + buffer.append("matcher.caseOf("); + appendSetDelayedToMatcher(ast, buffer, true, true); + } else if (expr.isAST(S.Rule, 3)) { + throw new UnsupportedOperationException(); + } + } + + out.print(symbolBuffer.toString()); + out.print("public static Matcher init"); + out.print(rulePostfix); + out.print("() {\n"); + out.print(" Matcher matcher = new Matcher();"); + out.print(buffer.toString()); + out.print("return matcher;\n"); + out.print("}\n"); + } + + private static void convertListExpr(IExpr expr, String rulePostfix, final PrintWriter out, + String symbolName) { + boolean last; + StringBuilder buffer = new StringBuilder(); + // ArraySet headerSymbols = new ArraySet(); + if (expr.isAST()) { + IASTAppendable list = ((IAST) expr).copyAppendable(); + // decisionTree = DecisionTree.insertRules(list); + if (symbolName != null) { + int equalsRuleCounter = 0; + int simpleRuleCounter = 0; + for (int i = 1; i < list.size(); i++) { + last = i == (list.argSize()); + expr = list.get(i); + if (expr.isAST(S.SetDelayed, 3)) { + IAST ast = (IAST) expr; + if (!RulesData.isComplicatedPatternRule(ast.arg1())) { + simpleRuleCounter++; + } + } else if (expr.isAST(S.Set, 3)) { + equalsRuleCounter++; + } + } + // if (equalsRuleCounter > 0 || simpleRuleCounter > 0) { + // out.print(SIZES); + // out.append(Integer.toString(equalsRuleCounter)); + // out.append(", "); + // out.append(Integer.toString(simpleRuleCounter)); + // out.append(" };\n\n"); + // buffer.append(" IInit("); + // buffer.append(symbolName); + // buffer.append(", SIZES),\n"); + // } + } + + for (int i = 1; i < list.size(); i++) { + last = i == (list.argSize()); + expr = list.get(i); + if (expr.isAST(S.SetDelayed, 3)) { + IAST ast = (IAST) expr; + buffer.append(" // " + ast.toString().replaceAll("\\n", "") + "\n"); + buffer.append(" SetDelayed("); + appendSetDelayedToRule(ast, buffer, false, last, false); + } else if (expr.isAST(S.Set, 3)) { + IAST ast = (IAST) expr; + buffer.append(" // " + ast.toString().replaceAll("\\n", "") + "\n"); + buffer.append(" Set("); + appendSetDelayedToRule(ast, buffer, true, last, false); + // } else if (expr.isAST(F.Rule, 3)) { + // IAST ast = (IAST) expr; + // buffer.append(" // " + ast.toString().replaceAll("\\n", "") + "\n"); + // buffer.append(" Rule("); + // appendSetDelayedToBuffer(ast, buffer, true, last); + } + } + // } else { + // if (expr.isAST(F.SetDelayed, 3)) { + // IAST ast = (IAST) expr; + // buffer.append(" SetDelayed("); + // appendSetDelayedToBuffer(ast, buffer, false, true); + // } else if (expr.isAST(F.Set, 3)) { + // IAST ast = (IAST) expr; + // buffer.append(" ISet("); + // appendSetDelayedToBuffer(ast, buffer, true, true); + // } else if (expr.isAST(F.Rule, 3)) { + // IAST ast = (IAST) expr; + // buffer.append(" Rule("); + // appendSetDelayedToBuffer(ast, buffer, true, true); + // } + } + out.print(LIST0); + out.print(rulePostfix); + out.println(LIST1); + out.print(buffer.toString()); + out.print(FOOTER0); + } + + private static byte[] convertSerialized(IExpr expr, final PrintWriter out) { + if (expr.isAST()) { + IAST list = (IAST) expr; + IASTAppendable list2 = F.ListAlloc(list.size()); + for (int i = 1; i < list.size(); i++) { + expr = list.get(i); + if (expr.isAST(S.SetDelayed, 3)) { + list2.append(expr); + } else if (expr.isAST(S.Set, 3)) { + list2.append(expr); + } + } + return WL.serializeInternal(list2); + } + out.print("Error in serializeing " + expr.toString()); + return null; + } + + public static IExpr parseFileToList(File file, EvalEngine engine) { + try { + final BufferedReader f = new BufferedReader(new FileReader(file)); + final StringBuilder buff = new StringBuilder(1024); + String line; + while ((line = f.readLine()) != null) { + buff.append(line); + buff.append('\n'); + } + f.close(); + String inputString = buff.toString(); + ExprParser p = new ExprParser(engine, true); + return p.parse(inputString); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * Generate Java files (*.java) from Symja rule files (*.m) + * + * @param sourceLocation source directory for rule (*.m) files + * @param targetLocation target directory for the generated Java files + * @param createMatcher + * @param ignoreTimestamp if false only change the target file (*.java), if the + * source file (*.m) has a newer time stamp than the target file. + */ + public static void generateFunctionStrings(final File sourceLocation, File targetLocation, + boolean createMatcher, boolean ignoreTimestamp) { + if (sourceLocation.exists()) { + PrintWriter automaticRules = null; + File automaticRulesFile = new File(targetLocation, "AutomaticRules" + ".java"); + if (!createMatcher) { + try { + automaticRules = createAutoHeader("AutomaticRules", automaticRulesFile, createMatcher); + automaticRules.println(" public static void initialize() {"); + automaticRules.println(" IAST rules = null;"); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + // Get the list of the files contained in the package + final String[] files = sourceLocation.list(); + if (files != null) { + StringBuilder buffer; + EvalEngine engine = new EvalEngine(true); + for (int i = 0; i < files.length; i++) { + File sourceFile = new File(sourceLocation, files[i]); + // we are only interested in .m files + if (files[i].endsWith(".m")) { + IExpr expr = parseFileToList(sourceFile, engine); + + if (expr == null) { + System.err.println(); + System.err.println("Abort after not parsed expression."); + return; + } else { + buffer = new StringBuilder(100000); + PrintWriter out; + try { + String className = files[i].substring(0, files[i].length() - 2); + String symbolName = className.substring(0, className.length() - 5); + + if (!createMatcher) { + if (!isSpecialRuleList(className)) { + automaticRules.println(" rules = " + className + ".RULES;"); + } + } + + File targetFile = new File(targetLocation, className + ".java"); + if (targetFile.exists()) { + if (!ignoreTimestamp + && (sourceFile.lastModified() <= targetFile.lastModified())) { + // only copy if timestamp is newer than + // existing ones + continue; + } + } + System.out.println(className); + if (isSpecialRuleList(className)) { + out = createHeader(className, targetFile, createMatcher); + convertList(expr, "", buffer, out, symbolName, engine); + out.println(FOOTER1); + out.close(); + } else { + out = createHeader(className, targetFile, createMatcher); + convert(expr, "", out, symbolName, createMatcher, engine); + out.println(FOOTER1); + out.close(); + } + // } catch (IOException e) { + // e.printStackTrace(); + } catch (Exception e) { + System.err.println(); + System.err.println("Abort after exception."); + e.printStackTrace(); + return; + } + } + } + } + } + if (!createMatcher) { + automaticRules.println(" }"); + automaticRules.println(FOOTER1); + automaticRules.close(); + } + } else { + System.out.println("source location doesn't exists: " + sourceLocation.toString()); + } + } + + private static boolean isSpecialRuleList(String className) { + return className.equals("IntegratePowerTimesFunctionRules") + || className.equals("FunctionExpandRules") || className.equals("FunctionRangeRules") + || className.equals("PodDefaultsRules"); + } + + private static PrintWriter createAutoHeader(String className, File targetFile, boolean useSets) + throws FileNotFoundException, IOException { + PrintWriter out; + out = new PrintWriter(targetFile.getCanonicalPath()); + out.print(PACKAGE); + if (useSets) { + out.print("rulesets;\n"); + } else { + out.print("rules;\n"); + } + out.print(HEADER_AUTO); + out.print(className); + out.print(" {\n"); + return out; + } + + private static PrintWriter createHeader(String className, File targetFile, boolean useSets) + throws FileNotFoundException, IOException { + PrintWriter out; + out = new PrintWriter(targetFile.getCanonicalPath()); + out.print(PACKAGE); + if (useSets) { + out.print("rulesets;\n"); + out.print(HEADER_INTERFACE); + } else { + out.print("rules;\n"); + out.print(HEADER_CLASS); + } + + out.print(className); + out.print(" {\n"); + return out; + } + + public static void generateFunctionSerialized(final File sourceLocation, File targetLocation, + boolean ignoreTimestamp) { + if (sourceLocation.exists()) { + // Get the list of the files contained in the package + final String[] files = sourceLocation.list(); + if (files != null) { + StringBuilder buffer; + EvalEngine engine = new EvalEngine(true); + for (int i = 0; i < files.length; i++) { + File sourceFile = new File(sourceLocation, files[i]); + // we are only interested in .m files + if (files[i].endsWith(".m")) { + IExpr expr = parseFileToList(sourceFile, engine); + + if (expr == null) { + System.err.println(); + System.err.println("Abort after not parsed expression."); + return; + } else { + buffer = new StringBuilder(100000); + // PrintWriter out; + try { + String className = files[i].substring(0, files[i].length() - 2); + String symbolName = className.substring(0, className.length() - 5); + File targetFile = new File(targetLocation, className + ".bin"); + if (targetFile.exists()) { + if (!ignoreTimestamp + && (sourceFile.lastModified() <= targetFile.lastModified())) { + // only copy if timestamp is newer than + // existing ones + continue; + } + } + System.out.println(className); + if (className.equals("FunctionExpandRules")) { + // || className.equals("PodDefaultsRules")) { + try (PrintWriter out = new PrintWriter(targetFile.getCanonicalPath())) { + byte[] binaryData = convertListSerialized(expr, buffer, out, engine); + com.google.common.io.Files.write(binaryData, targetFile); + } + } + } catch (Exception e) { + System.err.println(); + System.err.println("Abort after exception."); + e.printStackTrace(); + return; + } + } + } + } + } + } + } + + public static void main(final String[] args) { + ParserConfig.EXPLICIT_TIMES_OPERATOR = true; + + // Slot is considered as variable if we enable this check the processor will + // fail: + // TEST_LHS_FOR_VARIABLES = true; + + F.initSymbols(); + + System.out.println("Generate Java source files from rule definitions"); + + String userHome = System.getProperty("user.home"); + File sourceLocation = + new File(userHome + "/git/symja_android_library/symja_android_library/rules/"); + File javaTargetLocation = new File(userHome + + "/git/symja_android_library/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/reflection/system/rules"); + generateFunctionStrings(sourceLocation, javaTargetLocation, false, true); + + sourceLocation = + new File(userHome + "/git/symja_android_library/symja_android_library/rule_sets/"); + javaTargetLocation = new File(userHome + + "/git/symja_android_library/symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/reflection/system\\rulesets"); + generateFunctionStrings(sourceLocation, javaTargetLocation, true, true); + // + // System.out.println("Generate binary serialized files in internal format from rule + // definitions"); + // File binTargetLocation = + // new File("..\\symja_android_library\\matheclipse-core\\src\\main\\resources\\rules"); + // generateFunctionSerialized(sourceLocation, binTargetLocation, true); + } +}