Skip to content

Commit ec6a326

Browse files
Added NumExprCapability
1 parent 6a44548 commit ec6a326

10 files changed

Lines changed: 162 additions & 19 deletions

File tree

vcell-math/src/main/java/cbit/vcell/parser/ASTAndNode.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,14 @@ public String infixString(int lang)
178178
buffer.append(jjtGetChild(i).infixString(lang));
179179
}
180180
buffer.append("))");
181+
}else if (lang == LANGUAGE_NUM_EXPR) {
182+
int numChildren = jjtGetNumChildren();
183+
for (int i=0;i<numChildren;i++){
184+
if (i>0) buffer.append(" & ");
185+
buffer.append("(0.0!=");
186+
buffer.append(jjtGetChild(i).infixString(lang));
187+
buffer.append(")");
188+
}
181189
}else{
182190
for (int i=0;i<jjtGetNumChildren();i++){
183191
if (i>0) {

vcell-math/src/main/java/cbit/vcell/parser/ASTFloatNode.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,11 @@ public String infixString(int lang)
146146
if (value == Double.POSITIVE_INFINITY) return "float('inf')";
147147
if (value == Double.NEGATIVE_INFINITY) return "float('-inf')";
148148
return value.toString();
149-
} else {
149+
} else if (lang == LANGUAGE_NUM_EXPR) {
150+
if (value == Double.POSITIVE_INFINITY) return "inf";
151+
if (value == Double.NEGATIVE_INFINITY) return "-inf";
152+
return value.toString();
153+
} else {
150154
return value.toString();
151155
}
152156
}

vcell-math/src/main/java/cbit/vcell/parser/ASTFuncNode.java

Lines changed: 96 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,29 @@ public final String getPythonTranslation() {
134134
default -> "math." + getName();
135135
};
136136
}
137+
138+
public final String getNumExprTranslation() {
139+
return switch (this){
140+
case USERDEFINED -> throw new IllegalArgumentException("User defined functions have nothing to do with standard python names.");
141+
case ABS -> "abs";
142+
case MAX -> "maximum";
143+
case MIN -> "minimum";
144+
case CSC -> "1.0/" + SIN.getNumExprTranslation();
145+
case COT -> "1.0/" + TAN.getNumExprTranslation();
146+
case SEC -> "1.0/" + COS.getNumExprTranslation();
147+
case ASIN -> "arcsin";
148+
case ACOS -> "arccos";
149+
case ATAN -> "arctan";
150+
case ATAN2 -> "arctan2";
151+
case CSCH -> "1.0/" + SINH.getNumExprTranslation();
152+
case COTH -> "1.0/" + TANH.getNumExprTranslation();
153+
case SECH -> "1.0/" + COSH.getNumExprTranslation();
154+
case LOGBASE -> "1.0/" + LOG.getNumExprTranslation();
155+
case ACSC, ACOT, ASEC, ACSCH, ACOTH, ASECH, FACTORIAL -> throw new UnsupportedOperationException("Python has no equivalent name.");
156+
default -> getName();
157+
};
158+
}
159+
137160
public final String getHtmlDescription() {
138161
return htmlDescription;
139162
}
@@ -2389,12 +2412,28 @@ String getMathMLName() {
23892412
}
23902413

23912414
String getPythonName(){
2392-
if (funcType == FunctionType.USERDEFINED){
2415+
return getPythonName(funcType);
2416+
}
2417+
2418+
// This function is used when we need to "override" `funcType` to get the correct answer
2419+
private String getPythonName(ASTFuncNode.FunctionType functionType){
2420+
if (functionType == FunctionType.USERDEFINED){
23932421
return funcName;
23942422
}
2395-
return funcType.getPythonTranslation();
2423+
return functionType.getPythonTranslation();
23962424
}
23972425

2426+
String getNumExprName(){
2427+
return getNumExprName(funcType);
2428+
}
2429+
2430+
// This function is used when we need to "override" `funcType` to get the correct answer
2431+
private String getNumExprName(ASTFuncNode.FunctionType functionType){
2432+
if (functionType == FunctionType.USERDEFINED){
2433+
return funcName;
2434+
}
2435+
return functionType.getNumExprTranslation();
2436+
}
23982437

23992438
/**
24002439
* Insert the method's description here.
@@ -2455,7 +2494,7 @@ public String infixString(int lang) {
24552494
buffer.append(",");
24562495
buffer.append("((double)(" + jjtGetChild(1).infixString(lang) + "))");
24572496
buffer.append(")");
2458-
} else if (lang == LANGUAGE_PYTHON) {
2497+
} else if (lang == LANGUAGE_PYTHON || lang == LANGUAGE_NUM_EXPR) {
24592498
buffer.append("((");
24602499
buffer.append(jjtGetChild(0).infixString(lang));
24612500
buffer.append(")**(");
@@ -2485,34 +2524,74 @@ public String infixString(int lang) {
24852524
buffer.append(jjtGetChild(0).infixString(lang));
24862525
buffer.append("))");
24872526
break;
2527+
} else if (lang == LANGUAGE_NUM_EXPR){
2528+
// Need parenthesis to encapsulate the "1.0/x" operation
2529+
buffer.append("(");
2530+
buffer.append(getNumExprName());
2531+
buffer.append("(");
2532+
buffer.append(jjtGetChild(0).infixString(lang));
2533+
buffer.append("))");
2534+
break;
24882535
}
24892536
// DO NOT PUT A "BREAK" HERE! We want to "fall through" to default!
24902537
}
24912538
case ACSC:
2492-
case ACOT:
24932539
case ASEC:
24942540
case ACSCH:
24952541
case ACOTH:
24962542
case ASECH:{
2497-
if (lang == LANGUAGE_PYTHON){ // Need parenthesis to encapsulate the "1.0/x" operation
2543+
if (lang == LANGUAGE_PYTHON){
2544+
// Need parenthesis to encapsulate the "1.0/x" operation
24982545
Map<FunctionType, FunctionType> inversionMap = Map.of(
24992546
FunctionType.ACSC, FunctionType.ASIN,
2500-
FunctionType.ACOT, FunctionType.ATAN,
25012547
FunctionType.ASEC, FunctionType.ACOS,
25022548
FunctionType.ACSCH, FunctionType.ASINH,
25032549
FunctionType.ACOTH, FunctionType.ATANH,
25042550
FunctionType.ASECH, FunctionType.ACOSH
25052551
);
25062552
FunctionType inversionType = inversionMap.get(funcType);
25072553
buffer.append("(");
2508-
buffer.append(getPythonName());
2554+
buffer.append(getPythonName(inversionType));
2555+
buffer.append("(1.0/(");
2556+
buffer.append(jjtGetChild(0).infixString(lang));
2557+
buffer.append(")))");
2558+
break;
2559+
} else if (lang == LANGUAGE_NUM_EXPR){
2560+
// Need parenthesis to encapsulate the "1.0/x" operation
2561+
Map<FunctionType, FunctionType> inversionMap = Map.of(
2562+
FunctionType.ACSC, FunctionType.ASIN,
2563+
FunctionType.ASEC, FunctionType.ACOS,
2564+
FunctionType.ACSCH, FunctionType.ASINH,
2565+
FunctionType.ACOTH, FunctionType.ATANH,
2566+
FunctionType.ASECH, FunctionType.ACOSH
2567+
);
2568+
FunctionType inversionType = inversionMap.get(funcType);
2569+
buffer.append("(");
2570+
buffer.append(getNumExprName(inversionType));
25092571
buffer.append("(1.0/(");
25102572
buffer.append(jjtGetChild(0).infixString(lang));
25112573
buffer.append(")))");
25122574
break;
25132575
}
25142576
// DO NOT PUT A "BREAK" HERE! We want to "fall through" to default!
25152577
}
2578+
case ACOT:{
2579+
if (lang == LANGUAGE_PYTHON){
2580+
buffer.append(String.format("((%s/2.0) - ", Math.PI));
2581+
buffer.append(getPythonName(FunctionType.ATAN));
2582+
buffer.append("(");
2583+
buffer.append(jjtGetChild(0).infixString(lang));
2584+
buffer.append("))");
2585+
break;
2586+
} else if (lang == LANGUAGE_NUM_EXPR){
2587+
buffer.append(String.format("((%s/2.0) - ", Math.PI));
2588+
buffer.append(getNumExprName(FunctionType.ATAN));
2589+
buffer.append("(");
2590+
buffer.append(jjtGetChild(0).infixString(lang));
2591+
buffer.append("))");
2592+
break;
2593+
}
2594+
}
25162595
case FACTORIAL:
25172596
if (lang == LANGUAGE_PYTHON){
25182597
String name = getPythonName();
@@ -2525,8 +2604,7 @@ public String infixString(int lang) {
25252604
}
25262605
// DO NOT PUT A "BREAK" HERE! We want to "fall through" to default!
25272606
default:{
2528-
boolean needPythonicVersionOfName = lang == LANGUAGE_PYTHON && !funcType.equals(FunctionType.USERDEFINED);
2529-
String name = needPythonicVersionOfName ? getPythonName(): getName();
2607+
String name = getAppropriateName(lang);
25302608
buffer.append(name + "(");
25312609
for (int i=0;i<jjtGetNumChildren();i++){
25322610
if (i>0) buffer.append(", ");
@@ -2545,6 +2623,15 @@ public String infixString(int lang) {
25452623

25462624
}
25472625

2626+
private String getAppropriateName(int language){
2627+
if (FunctionType.USERDEFINED.equals(funcType)) return getName();
2628+
return switch (language){
2629+
case LANGUAGE_PYTHON -> getPythonName();
2630+
case LANGUAGE_NUM_EXPR -> getNumExprName();
2631+
default -> getName();
2632+
};
2633+
}
2634+
25482635
/**
25492636
* Insert the method's description here.
25502637
* Creation date: (6/20/01 11:04:41 AM)

vcell-math/src/main/java/cbit/vcell/parser/ASTMultNode.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ public String infixString(int lang){
416416

417417
buffer.append("(");
418418

419-
if (bAllBoolean || bNoBoolean || (lang != SimpleNode.LANGUAGE_C && lang != SimpleNode.LANGUAGE_VISIT && lang != SimpleNode.LANGUAGE_PYTHON)) { // old way
419+
if (bAllBoolean || bNoBoolean || (lang != SimpleNode.LANGUAGE_C && lang != SimpleNode.LANGUAGE_VISIT && lang != SimpleNode.LANGUAGE_PYTHON) && lang != SimpleNode.LANGUAGE_NUM_EXPR) { // old way
420420
for (int i=0;i<jjtGetNumChildren();i++){
421421
if (jjtGetChild(i) instanceof ASTInvertTermNode){
422422
// bAllBoolean must be false here!
@@ -428,12 +428,20 @@ public String infixString(int lang){
428428
buffer.append(jjtGetChild(i).infixString(lang));
429429
}else{
430430
if (i>0){
431-
if (lang == SimpleNode.LANGUAGE_MATLAB){
432-
buffer.append(" .* ");
433-
} else if(lang == SimpleNode.LANGUAGE_PYTHON && bAllBoolean){
434-
buffer.append(" and ");
435-
} else {
436-
buffer.append(" * ");
431+
if (bAllBoolean){
432+
if (lang == SimpleNode.LANGUAGE_PYTHON){
433+
buffer.append(" and ");
434+
} else if (lang == SimpleNode.LANGUAGE_NUM_EXPR) {
435+
buffer.append(" & ");
436+
} else {
437+
buffer.append(" * ");
438+
}
439+
} else { // mixed or no-boolean
440+
if (lang == SimpleNode.LANGUAGE_MATLAB){
441+
buffer.append(" .* ");
442+
} else {
443+
buffer.append(" * ");
444+
}
437445
}
438446
}
439447
buffer.append(jjtGetChild(i).infixString(lang));
@@ -447,6 +455,8 @@ public String infixString(int lang){
447455
if (conditionBuffer.length() > 0) {
448456
if (lang == SimpleNode.LANGUAGE_PYTHON){
449457
conditionBuffer.append(" and ");
458+
} else if (lang == SimpleNode.LANGUAGE_NUM_EXPR) {
459+
conditionBuffer.append(" & ");
450460
} else {
451461
conditionBuffer.append(" && ");
452462
}
@@ -476,6 +486,8 @@ public String infixString(int lang){
476486
}
477487
}else if (lang == SimpleNode.LANGUAGE_PYTHON) {
478488
buffer.append("(").append(valueBuffer).append(") if (").append(conditionBuffer).append(") else 0.0");
489+
}else if (lang == SimpleNode.LANGUAGE_NUM_EXPR) {
490+
buffer.append("where(").append(conditionBuffer).append(", ").append(valueBuffer).append(", 0.0)");
479491
}else{
480492
buffer.append("((" + conditionBuffer + ") ? (" + valueBuffer + ") : 0.0)");
481493
}

vcell-math/src/main/java/cbit/vcell/parser/ASTNotNode.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,19 +136,23 @@ public Node flatten(boolean substituteConstants) throws ExpressionException {
136136
public String infixString(int language) {
137137
StringBuffer buffer = new StringBuffer();
138138
boolean parentIsLogical = parent != null && parent.isLogical();
139+
boolean childIsLogical = jjtGetChild(0).isLogical();
139140
if (language == LANGUAGE_VISIT){
140141
buffer.append("not(");
141142
}else if(language == LANGUAGE_PYTHON){
142143
if (parentIsLogical) buffer.append("not(");
143144
else buffer.append("float(not(");
145+
}else if(language == LANGUAGE_NUM_EXPR){
146+
if (childIsLogical) buffer.append("~(");
147+
else buffer.append("(0.0==(");
144148
}else if (language == LANGUAGE_ECLiPSe){
145149
buffer.append("neg(");
146150
}else{
147151
buffer.append("!(");
148152
}
149153
buffer.append(jjtGetChild(0).infixString(language));
150154
buffer.append(")");
151-
if (language == LANGUAGE_PYTHON && !parentIsLogical) buffer.append(")");
155+
if ((language == LANGUAGE_PYTHON && !parentIsLogical) || (language == LANGUAGE_NUM_EXPR && !childIsLogical)) buffer.append(")");
152156

153157
return buffer.toString();
154158
}

vcell-math/src/main/java/cbit/vcell/parser/ASTOrNode.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ public String infixString(int lang)
180180
buffer.append(jjtGetChild(i).infixString(lang));
181181
}
182182
buffer.append("))");
183+
}else if (lang == LANGUAGE_NUM_EXPR) {
184+
int numChildren = jjtGetNumChildren();
185+
for (int i=0;i<numChildren;i++){
186+
if (i>0) buffer.append(" | ");
187+
buffer.append("(0.0!=");
188+
buffer.append(jjtGetChild(i).infixString(lang));
189+
buffer.append(")");
190+
}
183191
}else{
184192
for (int i=0;i<jjtGetNumChildren();i++){
185193
if (i>0) {

vcell-math/src/main/java/cbit/vcell/parser/ASTPowerNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ public String infixString(int lang){
260260
buffer.append(" ^ ");
261261
buffer.append(jjtGetChild(1).infixString(lang));
262262
buffer.append(")");
263-
} else if (lang == LANGUAGE_PYTHON) {
263+
} else if (lang == LANGUAGE_PYTHON || lang == LANGUAGE_NUM_EXPR) {
264264
buffer.append("((");
265265
buffer.append(jjtGetChild(0).infixString(lang));
266266
buffer.append(")**(");

vcell-math/src/main/java/cbit/vcell/parser/Expression.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,10 @@ public String infix_Matlab()
692692
public String infix_Python() {
693693
return rootNode == null ? null : rootNode.infixString(SimpleNode.LANGUAGE_PYTHON);
694694
}
695+
696+
public String infix_NumExpr() {
697+
return rootNode == null ? null : rootNode.infixString(SimpleNode.LANGUAGE_NUM_EXPR);
698+
}
695699
/**
696700
* This method was created by a SmartGuide.
697701
* @return cbit.vcell.model.Expression

vcell-math/src/main/java/cbit/vcell/parser/SimpleNode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public abstract class SimpleNode implements Node, java.io.Serializable {
3232
final static int LANGUAGE_UNITS = 6;
3333
final static int LANGUAGE_BNGL = 7;
3434
final static int LANGUAGE_PYTHON = 8;
35+
final static int LANGUAGE_NUM_EXPR = 9;
3536

3637
public SimpleNode(int i) {
3738
id = i;

vcell-math/src/test/java/cbit/vcell/parser/ExpressionTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,21 @@ public void testEval() {
413413
}
414414
}
415415

416+
@Test
417+
public void testNumExprGeneration() throws ExpressionException {
418+
Expression expr1 = new Expression("(2.0 && id_2) * 3.3 / acsc(1 + id_1) * pow(2, 3.2 ^ 2)");
419+
String numExpr1 = expr1.infix_NumExpr();
420+
Assertions.assertEquals("(where(((0.0!=2.0) & (0.0!=id_2)), 3.3 / (arcsin(1.0/((1.0 + id_1)))) * ((2.0)**(((3.2)**(2.0)))), 0.0))", numExpr1);
421+
422+
Expression expr2 = new Expression("(1.2 * 2.2) * logbase(3.3) * 2.0");
423+
String numExpr2 = expr2.infix_NumExpr();
424+
Assertions.assertEquals("((1.2 * 2.2) * (1.0/log(3.3)) * 2.0)", numExpr2);
425+
426+
Expression expr3 = new Expression("(1.2 || 2.2) * (3.3 && !(2.0 && 0.0))");
427+
String numExpr3 = expr3.infix_NumExpr();
428+
Assertions.assertEquals("(((0.0!=1.2) | (0.0!=2.2)) & ((0.0!=3.3) & (0.0!=~(((0.0!=2.0) & (0.0!=0.0))))))", numExpr3);
429+
}
430+
416431

417432
/**
418433
* Insert the method's description here.

0 commit comments

Comments
 (0)