Skip to content

Commit d9e6429

Browse files
committed
removed var-args in MethodAction to debug high mem usage
1 parent 470eba3 commit d9e6429

4 files changed

Lines changed: 197 additions & 141 deletions

File tree

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>com.github.gbenroscience</groupId>
55
<artifactId>parser-ng</artifactId>
6-
<version>0.2.5</version>
6+
<version>0.2.6</version>
77
<packaging>jar</packaging>
88
<!--
99
I started this project 2009 and have been upgrading it since then.

src/main/java/com/github/gbenroscience/parser/Function.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public double calc() {
221221
* were supplied in the original question.
222222
* @return the value of the function with these variables set.
223223
*/
224-
public MathExpression.EvalResult calc(MathExpression.EvalResult... x) {
224+
public MathExpression.EvalResult calc(MathExpression.EvalResult[] x) {
225225

226226
if (type == TYPE.ALGEBRAIC_EXPRESSION) {
227227
if (x.length == independentVariables.size()) {
@@ -242,7 +242,7 @@ public MathExpression.EvalResult calc(MathExpression.EvalResult... x) {
242242
}
243243

244244
@Override
245-
public MathExpression.EvalResult calc(MathExpression.EvalResult nextResult, int arity, MathExpression.EvalResult... x) {
245+
public MathExpression.EvalResult calc(MathExpression.EvalResult nextResult, int arity, MathExpression.EvalResult[] x) {
246246
if (type == TYPE.ALGEBRAIC_EXPRESSION) {
247247
if (x.length == independentVariables.size()) {
248248

src/main/java/com/github/gbenroscience/parser/MathExpression.java

Lines changed: 94 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,14 @@ public void setVariableManager(VariableManager variableManager) {
595595
this.variableManager = variableManager;
596596
}
597597

598+
public VariableRegistry getRegistry() {
599+
return registry;
600+
}
601+
602+
public boolean hasVariable(String var) {
603+
return registry.hasVariable(var);
604+
}
605+
598606
/**
599607
* Retrieves a Variable handle from the expression's registry. This handle
600608
* is "Pre-Bound" to the correct slot in the execution frame.
@@ -620,8 +628,7 @@ public Variable getVariable(String name) {
620628

621629
return v;
622630
}
623-
624-
throw new NoSuchElementException("Variable '" + name + "' was not found in the compiled expression.");
631+
return null;
625632
}
626633

627634
public static final class Slot {
@@ -1049,13 +1056,19 @@ public void updateArgs(double... values) {
10491056
*/
10501057
public void updateArgs(int[] slots, double... values) {
10511058
for (int i = 0; i < slots.length; i++) {
1052-
this.executionFrame[slots[i]] = values[i];
1059+
int slot = slots[i];
1060+
double value = values[i];
1061+
if (slot >= 0 && slot < this.executionFrame.length) {
1062+
this.executionFrame[slot] = value;
1063+
}
10531064
}
10541065
}
10551066

10561067
// Or, for a single variable update (the most common benchmark case):
10571068
public void updateSlot(int slot, double value) {
1058-
this.executionFrame[slot] = value;
1069+
if (slot >= 0 && slot < this.executionFrame.length) {
1070+
this.executionFrame[slot] = value;
1071+
}
10591072
}
10601073

10611074
public void setReturnType(TYPE returnType) {
@@ -1275,7 +1288,7 @@ private void compileToPostfix() {
12751288
Token callable = opStack.pop();
12761289

12771290
int actualArgCount = argCounts.pop();
1278-
lastWasComma.pop();
1291+
lastWasComma.pop();
12791292
callable.arity = Math.max(1, actualArgCount);
12801293
postfix[p++] = callable;
12811294

@@ -1351,17 +1364,24 @@ private final class ExpressionSolver {
13511364
private static final int ABSOLUTE_MAX_ARITY = 100_000;
13521365

13531366
private EvalResult[][] argCache = new EvalResult[MAX_ARITY + 1][];
1367+
private EvalResult[] stack;
13541368

13551369
public ExpressionSolver() {
13561370
// Pre-allocate ONE array per arity that we reuse
13571371
for (int i = 0; i <= MAX_ARITY; i++) {
13581372
argCache[i] = new EvalResult[i];
13591373
}
1360-
13611374
}
13621375

13631376
public EvalResult evaluate() {
1364-
final EvalResult[] stack = new EvalResult[Math.max(cachedPostfix.length * 2, 64)];
1377+
if(stack == null){
1378+
stack = new EvalResult[Math.max(cachedPostfix.length * 2, 64)];
1379+
}else{
1380+
if(cachedPostfix.length > stack.length ){
1381+
stack = new EvalResult[Math.max(cachedPostfix.length * 2, 64)];
1382+
}
1383+
}
1384+
13651385
int ptr = -1;
13661386

13671387
for (int i = 0; i < cachedPostfix.length; i++) {
@@ -1432,7 +1452,7 @@ public EvalResult evaluate() {
14321452
int valuesOnStack = ptr + 1;
14331453

14341454
if (arity == 0) {
1435-
EvalResult result = t.action.calc(getNextResult(), arity);
1455+
EvalResult result = t.action.calc(getNextResult(), arity,argCache[arity]);
14361456
stack[++ptr] = result;
14371457
break;
14381458
}
@@ -1607,11 +1627,10 @@ private void foldConstantsWithSafetyGuards() {
16071627
if ((t.kind == Token.FUNCTION || t.kind == Token.METHOD) && writePtr >= t.arity) {
16081628

16091629
// CRITICAL: Never fold trigonometric functions!
1610-
/* if (isTrigonometricFunction(t)) {
1630+
/* if (isTrigonometricFunction(t)) {
16111631
folded[writePtr++] = t; // Keep the function token as-is
16121632
continue;
16131633
}*/
1614-
16151634
if (!isConstantFoldableFunction(t)) {
16161635
folded[writePtr++] = t;
16171636
continue;
@@ -1654,37 +1673,6 @@ private void foldConstantsWithSafetyGuards() {
16541673
}
16551674
}
16561675

1657-
/**
1658-
* CRITICAL: Detect trigonometric functions that must NOT be folded because
1659-
* setDRG() needs to be able to modify them after compilation.
1660-
*/
1661-
private boolean isTrigonometricFunction(Token t) {
1662-
if (t.name == null) {
1663-
return false;
1664-
}
1665-
1666-
String name = t.name.toLowerCase();
1667-
1668-
// All trig functions (in any DRG variant) must NOT be folded
1669-
java.util.Set<String> trigFunctions = new java.util.HashSet<>(
1670-
Arrays.asList(
1671-
// Basic trig
1672-
"sin_deg", "sin_rad", "sin_grad", "sin",
1673-
"cos_deg", "cos_rad", "cos_grad", "cos",
1674-
"tan_deg", "tan_rad", "tan_grad", "tan",
1675-
// Inverse trig
1676-
"asin", "acos", "atan", "atan2",
1677-
// Hyperbolic (also angle-dependent in some contexts)
1678-
"sinh", "cosh", "tanh", "asinh", "acosh", "atanh",
1679-
// Cotangent, Secant, Cosecant (if you support them)
1680-
"cot", "sec", "csc",
1681-
// DRG-aware variants
1682-
"arcsin", "arccos", "arctan")
1683-
);
1684-
1685-
return trigFunctions.stream().anyMatch(name::equalsIgnoreCase);
1686-
}
1687-
16881676
/**
16891677
* Whitelist of functions that ARE safe to constant-fold. Note: Trig
16901678
* functions are handled separately (never folded).
@@ -1696,36 +1684,79 @@ private boolean isConstantFoldableFunction(Token t) {
16961684

16971685
String name = t.name.toLowerCase();
16981686

1699-
// ===== BLACKLIST: NON-FOLDABLE =====
1687+
// ===== BLACKLIST: NON-FOLDABLE (Side effects, randomness, I/O, user-defined) =====
17001688
java.util.Set<String> nonFoldable = new java.util.HashSet<>(
17011689
Arrays.asList(
1702-
// Stochastic
1703-
"rand", "random", "randbetween", "randi", "randint", "randnormal","rnd",
1690+
// Stochastic - different result each time
1691+
"rand", "random", "randbetween", "randi", "randint", "randnormal", "rnd",
17041692
// Time-dependent
17051693
"now", "time", "today", "clock", "timestamp", "millis",
1706-
// Side effects
1707-
"print", "println", "debug", "log",
1694+
// Side effects (I/O, output)
1695+
"print", "println", "debug", "log", "plot",
17081696
// System-dependent
17091697
"random_seed", "env", "getenv",
1710-
// I/O
1711-
"read", "readline", "input", "scan")
1698+
// I/O operations
1699+
"read", "readline", "input", "scan",
1700+
// User-defined or dynamic
1701+
"diff", "intg", "differentiation", "integration",
1702+
// Matrix operations (complex state-dependent results)
1703+
"linear_sys", "det", "determinant", "invert", "inverse_matrix",
1704+
"tri_mat", "triangular_matrix", "echelon", "echelon_matrix",
1705+
"matrix_mul", "matrix_multiply", "matrix_div", "matrix_divide",
1706+
"matrix_add", "matrix_subtract", "matrix_sub",
1707+
"matrix_pow", "matrix_power", "transpose", "matrix_edit",
1708+
"matrix_cofactors", "cofactor", "matrix_adjoint", "adjoint",
1709+
"matrix_eigenvec", "eigvec", "matrix_eigenvalues", "eigvalues",
1710+
"matrix_eigenpoly", "eigpoly",
1711+
// List sorting (order-dependent, may depend on implementation)
1712+
"sort",
1713+
// Help
1714+
"help",
1715+
// Quadratic/root solving (may have multiple solutions or complex numbers)
1716+
"quadratic", "tartaglia_roots", "t_root", "general_root", "root")
17121717
);
17131718

17141719
if (nonFoldable.contains(name)) {
17151720
return false;
17161721
}
17171722

1718-
// ===== WHITELIST: SAFE TO FOLD =====
1719-
java.util.Set<String> definitelyFoldable = new java.util.HashSet<>(
1720-
Arrays.asList()
1723+
// ===== SPECIAL HANDLING: Trigonometric functions =====
1724+
// These ARE foldable, but ONLY if NOT being used with setDRG() changes
1725+
// For safety, we fold them ONLY when the expression contains constants
1726+
// Since we're in compile-time, we CAN fold them with current DRG mode
1727+
java.util.Set<String> trigonometric = new java.util.HashSet<>(
1728+
Arrays.asList(MethodRegistry.expandedTrigAndHypMethodNames)
17211729
);
17221730

1723-
if (definitelyFoldable.contains(name)) {
1724-
return true;
1725-
}
1726-
1727-
// Conservative: don't fold unknown functions
1728-
return false;
1731+
// ===== WHITELIST: DEFINITELY FOLDABLE =====
1732+
java.util.Set<String> definitelyFoldable = new java.util.HashSet<>(
1733+
Arrays.asList(
1734+
// ===== EXPONENTIAL & LOGARITHMIC =====
1735+
"exp", "ln", "lg", "log", "log10", "log2",
1736+
"ln-¹", "lg-¹", "log-¹", "aln", "alg", "alog",
1737+
// ===== POWER & ROOT =====
1738+
"sqrt", "cbrt", "pow", "hypot",
1739+
"inverse", "square", "cube",
1740+
"fact",
1741+
// ===== COMBINATORICS =====
1742+
"comb", "perm",
1743+
// ===== ROUNDING & ABSOLUTE =====
1744+
"abs", "floor", "ceil", "round", "trunc", "sign",
1745+
// ===== LIST STATISTICS (pure functions - no state) =====
1746+
"listsum", "sum", "prod", "product",
1747+
"mean", "listavg", "avg", "average",
1748+
"median", "med",
1749+
"min", "max",
1750+
"mode", "sort",
1751+
"range", "rng", "mid_range", "mrng",
1752+
"rms",
1753+
"s_d", "std_dev",
1754+
"variance", "st_err",
1755+
"cov"
1756+
));
1757+
definitelyFoldable.addAll(trigonometric);
1758+
1759+
return definitelyFoldable.contains(name);
17291760
}
17301761

17311762
/**
@@ -2241,13 +2272,12 @@ private static void testConstantFolding() {
22412272
"2*sinh(5)"
22422273
};
22432274

2244-
double[] expected = {8.0, 9.0, 16.0, 2.0, 2.0, 17.0, 0.01, 0.42478219352309348656738397432167,5*148.40642115557751795401894399213};
2275+
double[] expected = {8.0, 9.0, 16.0, 2.0, 2.0, 17.0, 0.01, 0.42478219352309348656738397432167, 5 * 148.40642115557751795401894399213};
22452276

22462277
for (int i = 0; i < exprs.length; i++) {
22472278
try {
22482279
MathExpression me = new MathExpression(exprs[i]);
22492280
double result = Double.parseDouble(me.solve());
2250-
22512281

22522282
String status = Math.abs(result - expected[i]) < 1e-9 ? "✓" : "✗";
22532283
System.out.printf("%s %s = %.6f (expected: %.6f)%n",
@@ -2449,16 +2479,15 @@ public static void main(String... args) {
24492479
System.out.println("VARIABLES--1 = " + VariableManager.VARIABLES);
24502480
Function f = FunctionManager.add("f(x,y) = x - x/y");
24512481
System.out.println("VARIABLES--2 = " + VariableManager.VARIABLES);
2452-
2453-
2454-
f.updateArgs(2,3);
2482+
2483+
f.updateArgs(2, 3);
24552484
double r = f.calc();
24562485
System.out.println("VARIABLES--3 = " + VariableManager.VARIABLES);
24572486
System.out.println("r = " + r);
24582487
int iterations = 1;
24592488
double vvv[] = new double[1];
24602489
long start = System.nanoTime();
2461-
f.updateArgs(2,3);
2490+
f.updateArgs(2, 3);
24622491
for (int i = 1; i <= iterations; i++) {
24632492
vvv[0] = f.calc();
24642493
}
@@ -2533,9 +2562,9 @@ public static void main(String... args) {
25332562
System.out.println(quadRoots1.solve());
25342563
MathExpression tartRoots = new MathExpression("t_root(@(x)5*x^3-12*x+120)");
25352564
System.out.println(tartRoots.solve());
2536-
2565+
25372566
MathExpression printer = new MathExpression("print(anon22,C)");
2538-
System.out.println(printer.solve());
2567+
System.out.println(printer.solve());
25392568
System.out.println(new MathExpression("M=@(x)7*x^2;M(2)").solve());
25402569

25412570
// double N = 100;

0 commit comments

Comments
 (0)