~ubuntu-branches/debian/sid/geogebra/sid

« back to all changes in this revision

Viewing changes to geogebra/cas/GeoGebraCAS.java

  • Committer: Package Import Robot
  • Author(s): Giovanni Mascellani
  • Date: 2012-01-10 11:37:41 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120110113741-satwohsd4de4ite1
Tags: 4.0.19.0+dfsg1-1
* New upstream version (closes: #649893).
* Update dependency: icedtea-plugin -> icedtea-netx-common (LP: #893007).
* New thumbnailer configuration compatible with Gnome 3.
* Package building is now managed by javahelper instead of upstream
  build.xml.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
package geogebra.cas;
2
2
 
 
3
import geogebra.cas.error.CASException;
 
4
import geogebra.cas.mpreduce.CASmpreduce;
 
5
import geogebra.kernel.GeoGebraCASInterface;
3
6
import geogebra.kernel.Kernel;
4
7
import geogebra.kernel.arithmetic.ExpressionNode;
 
8
import geogebra.kernel.arithmetic.ExpressionValue;
 
9
import geogebra.kernel.arithmetic.ValidExpression;
5
10
import geogebra.main.Application;
6
 
import jasymca.GeoGebraJasymca;
7
 
 
8
 
import java.util.HashMap;
9
 
 
10
 
import org.mathpiper.interpreters.EvaluationResponse;
11
 
import org.mathpiper.interpreters.Interpreter;
12
 
import org.mathpiper.interpreters.Interpreters;
13
 
 
 
11
import geogebra.util.MaxSizeHashMap;
 
12
 
 
13
import java.util.ArrayList;
 
14
import java.util.Map;
14
15
 
15
16
/**
16
17
 * This class provides an interface for GeoGebra to use the computer algebra
17
 
 * system MathPiper.
 
18
 * systems Maxima and MathPiper.
18
19
 * 
19
20
 * @author Markus Hohenwarter
20
21
 */
21
 
public class GeoGebraCAS {
 
22
public class GeoGebraCAS implements GeoGebraCASInterface {
22
23
 
23
 
        private Interpreter ggbMathPiper;
24
 
        private GeoGebraJasymca ggbJasymca;     
25
 
        private StringBuffer sbInsertSpecial, sbReplaceIndices, sbPolyCoeffs;
26
24
        private Application app;
27
 
        
 
25
        private Kernel kernel;
 
26
        private CASparser casParser;
 
27
        private CASgeneric cas;
 
28
        private CASmpreduce casMPReduce;
 
29
        public int currentCAS = -1;
 
30
 
28
31
        public GeoGebraCAS(Kernel kernel) {
29
 
                app = kernel.getApplication();
30
 
                sbInsertSpecial = new StringBuffer(80);
31
 
                sbReplaceIndices = new StringBuffer(80);
 
32
                app = (Application) kernel.getApplication();
 
33
                casParser = new CASparser(kernel);
 
34
 
 
35
                // DO NOT init underlying CAS here to avoid hanging animation,
 
36
                // see http://www.geogebra.org/trac/ticket/1565
 
37
                // getCurrentCAS();
 
38
        }
 
39
        
 
40
        public CASparser getCASparser() {
 
41
                return casParser;
 
42
        }
 
43
        
 
44
        public synchronized CASgeneric getCurrentCAS() {
 
45
                if (cas == null) {
 
46
                        setCurrentCAS(Kernel.DEFAULT_CAS);
 
47
                }
32
48
                
33
 
                initCAS();
34
 
        }
35
 
        
36
 
        private void initCAS() {
37
 
                ggbMathPiper = null;
38
 
                getMathPiper();
39
 
                ggbJasymca = new GeoGebraJasymca();
40
 
        }
41
 
 
42
 
        
43
 
    /** 
44
 
     * Evaluates a JASYMCA expression and returns the result as a string,
45
 
     * e.g. exp = "diff(x^2,x)" returns "2*x".
46
 
     * @return result string, null possible
47
 
     */ 
48
 
    final public String evaluateJASYMCA(String exp) {    
49
 
        String result = ggbJasymca.evaluate(exp);       
50
 
          
51
 
        // to handle x(A) and x(B) they are converted
52
 
        // to unicode strings in ExpressionNode, 
53
 
        // we need to convert them back here
54
 
        result = insertSpecialChars(result);
55
 
        
56
 
        //System.out.println("exp for JASYMCA: " + exp);  
57
 
        //System.out.println("         result: " + result);  
58
 
                
59
 
        return result;
60
 
    }
61
 
 
62
 
    /**
63
 
         * Evaluates a MathPiper expression and returns the result as a string in MathPiper syntax, 
64
 
         * e.g. evaluateMathPiper("D(x) (x^2)") returns "2*x".
65
 
         * 
66
 
         * @return result string (null possible)
 
49
                return cas;
 
50
        }
 
51
 
 
52
        
 
53
        public int getCurrentCASstringType() {
 
54
                switch (currentCAS) {
 
55
                        case Application.CAS_MAXIMA:
 
56
                                return ExpressionNode.STRING_TYPE_MAXIMA;
 
57
                                
 
58
                        case Application.CAS_MPREDUCE:
 
59
                                return ExpressionNode.STRING_TYPE_MPREDUCE;
 
60
                                
 
61
                        default:
 
62
                        case Application.CAS_MATHPIPER:
 
63
                                return ExpressionNode.STRING_TYPE_MATH_PIPER;   
 
64
                }
 
65
        }
 
66
        
 
67
        /**
 
68
         * Sets the currently used CAS for evaluateGeoGebraCAS().
 
69
         * @param CAS: use CAS_MATHPIPER or CAS_MAXIMA
67
70
         */
68
 
        final synchronized public String evaluateMathPiper(String exp) {
 
71
        public synchronized void setCurrentCAS(int CAS) {
69
72
                try {
70
 
                        String result;
71
 
                                                
72
 
                        // MathPiper has problems with indices like a_3, b_{12}
73
 
                        exp = replaceIndices(exp);
74
 
                        
75
 
                        // evaluate the MathPiper expression
76
 
                        Interpreter mathpiper = getMathPiper();
77
 
                        response = mathpiper.evaluate(exp);
78
 
                        
79
 
                        if (response.isExceptionThrown())
80
 
                        {
81
 
                                Application.debug("String for MathPiper: "+exp+"\nException from MathPiper: "+response.getExceptionMessage());
82
 
                                return null;
 
73
                        switch (CAS) {
 
74
                        /*
 
75
                                case Application.CAS_MAXIMA:
 
76
                                        cas = getMaxima();
 
77
                                        ((CASmaxima) cas).initialize();
 
78
                                        currentCAS = CAS;
 
79
                                        break;*/
 
80
                                        
 
81
                                default:
 
82
                                        cas = getMPReduce();
 
83
                                        app.getSettings().getCasSettings().addListener(cas);
 
84
                                        currentCAS = CAS;
 
85
                                        break;  
 
86
                                /*
 
87
                                case Application.CAS_MATHPIPER:
 
88
                                        cas = getMathPiper();
 
89
                                        currentCAS = CAS;
 
90
                                        break;
 
91
                                        */
83
92
                        }
84
 
                        result = response.getResult();
 
93
                        /*
 
94
                }catch (MaximaVersionUnsupportedExecption e){
 
95
                        app.showError("CAS.MaximaVersionUnsupported");
 
96
                        setCurrentCAS(Application.CAS_MPREDUCE);*/
 
97
                }catch (Exception e) {
 
98
                        e.printStackTrace();
 
99
                }
 
100
        }
 
101
        
 
102
        /**
 
103
         * Resets the cas and unbinds all variable and function definitions.
 
104
         */
 
105
        public void reset() {
 
106
                getCurrentCAS().reset();
 
107
        }
 
108
        
 
109
        /**
 
110
         * Sets the number of signficiant figures (digits) that should be used as print precision for the
 
111
         * output of Numeric[] commands.
 
112
         * 
 
113
         * @param significantNumbers
 
114
         */
 
115
        public void setSignificantFiguresForNumeric(int significantNumbers) {
 
116
                getCurrentCAS().setSignificantFiguresForNumeric(significantNumbers);
 
117
        }
 
118
        
 
119
        /*
 
120
        private CASmathpiper getMathPiper() {
 
121
                if (currentCAS == Application.CAS_MATHPIPER)
 
122
                        return (CASmathpiper) cas;
 
123
                else
 
124
                        return new CASmathpiper(casParser, new CasParserToolsImpl('e'));
 
125
        }*/
 
126
        
 
127
        /*
 
128
        private CASmaxima getMaxima() {
 
129
                if (currentCAS == Application.CAS_MAXIMA)
 
130
                        return (CASmaxima) cas;
 
131
                else
 
132
                        return new CASmaxima(casParser, new CasParserToolsImpl('b'));
 
133
        }*/
 
134
        
 
135
        private synchronized CASmpreduce getMPReduce() {
 
136
                if (casMPReduce == null)
 
137
                        casMPReduce = new CASmpreduce(casParser, new CasParserToolsImpl('e'));
 
138
                return casMPReduce;
 
139
        }
 
140
        
 
141
//      /**
 
142
//       * Returns whether var is a defined variable.
 
143
//       */
 
144
//      public boolean isVariableBound(String var) {
 
145
//              return cas.isVariableBound(var);
 
146
//      }
 
147
        
 
148
        /**
 
149
         * Unbinds (deletes) variable.
 
150
         * @param var
 
151
         * @param isFunction
 
152
         */
 
153
        public void unbindVariable(String var) {
 
154
                getCurrentCAS().unbindVariable(var);
 
155
        }
 
156
        
 
157
        /**
 
158
         * Evaluates a valid expression and returns the resulting String in GeoGebra notation.
 
159
         * @param casInput Input in GeoGebraCAS syntax
 
160
         * @return evaluation result
 
161
         * @throws CASException
 
162
         */
 
163
        public String evaluateGeoGebraCAS(ValidExpression casInput) throws CASException {
 
164
                Kernel kernel = app.getKernel();
 
165
                boolean oldDigits = kernel.internationalizeDigits;
 
166
                kernel.internationalizeDigits = false;                  
 
167
                
 
168
                String result = null;
 
169
                CASException exception = null;
 
170
                try {           
 
171
                        result = getCurrentCAS().evaluateGeoGebraCAS(casInput);                                 
 
172
                }       
 
173
                catch (CASException ce) {
 
174
                        exception = ce;                 
 
175
                }
 
176
                finally  {
 
177
                        kernel.internationalizeDigits = oldDigits;
 
178
                }
 
179
                
 
180
                // check if keep input command was successful
 
181
                // e.g. for KeepInput[Substitute[...]]
 
182
                // otherwise return input
 
183
                if (casInput.isKeepInputUsed() && 
 
184
                                (exception != null || "?".equals(result))) 
 
185
                {                       
 
186
                        // return original input
 
187
                        return casInput.toString();
 
188
                }
 
189
                
 
190
                // pass on exception
 
191
                if (exception != null)
 
192
                        throw exception;
85
193
                                        
86
 
                        // undo special character handling
87
 
                        result = insertSpecialChars(result);
88
 
 
89
 
                        //Application.debug("String for MathPiper: "+exp+"\nresult: "+result);
90
 
 
91
 
                        return result;
92
 
                } catch (Throwable th) {
93
 
                        //MathPiper.Evaluate("restart;");
94
 
                        th.printStackTrace();
95
 
                        return null;
96
 
                } 
97
 
        }
98
 
                                
99
 
        /**
100
 
         * Evaluates a MathPiper expression wrapped in a command and returns the result as a string, 
101
 
         * e.g. wrapperCommand = "Factor", exp = "3*(a+b)" evaluates "Factor(3*(a+b)" and 
102
 
         * returns "3*a+3*b".
103
 
         * 
104
 
         * @return result string (null possible)
105
 
         */
106
 
        final synchronized public String evaluateMathPiper(String wrapperCommand, String exp) {
107
 
                StringBuffer sb = new StringBuffer(exp.length()+wrapperCommand.length()+2);
108
 
                sb.append(wrapperCommand);
109
 
                sb.append('(');
110
 
                sb.append(exp);                         
111
 
                sb.append(')');
112
 
                return evaluateMathPiper(sb.toString());
113
 
        }       
114
 
        
115
 
        /**
116
 
         * Returns the error message of the last MathPiper evaluation.
 
194
                // success
 
195
                if (result != null) {
 
196
                        // get names of escaped global variables right
 
197
                        // e.g. "ggbcasvar1a" needs to be changed to "a"
 
198
                        // e.g. "ggbtmpvara" needs to be changed to "a"
 
199
                        result = app.getKernel().removeCASVariablePrefix(result, " ");
 
200
                }
 
201
                
 
202
                return result;
 
203
        }
 
204
        
 
205
        /** 
 
206
         * Evaluates an expression in GeoGebraCAS syntax.
 
207
         * @param exp 
 
208
     * @return result string in GeoGebra syntax (null possible)
 
209
         * @throws CASException 
 
210
     */
 
211
        final public String evaluateGeoGebraCAS(String exp) throws CASException {
 
212
                try
 
213
                {
 
214
                        ValidExpression inVE = casParser.parseGeoGebraCASInput(exp);
 
215
                        return evaluateGeoGebraCAS(inVE);
 
216
                } catch (Throwable t)
 
217
                {
 
218
                        throw new CASException(t);
 
219
                }
 
220
        }
 
221
        
 
222
        /** 
 
223
         * Evaluates an expression in the syntax of the currently active CAS
 
224
         * (MathPiper or Maxima).
 
225
     * @return result string (null possible)
 
226
         * @throws Throwable 
 
227
     */
 
228
        final public String evaluateRaw(String exp) throws Throwable {
 
229
                return getCurrentCAS().evaluateRaw(exp);
 
230
        }
 
231
        
 
232
        /**
 
233
         * Returns the error message of the last call of evaluateGeoGebraCAS().
117
234
         * @return null if last evaluation was successful.
118
235
         */
119
 
        final synchronized public String getMathPiperError() {
120
 
                if (response != null)
121
 
                        return response.getExceptionMessage();
122
 
                else 
123
 
                        return null;
124
 
        }
125
 
        
126
 
        EvaluationResponse response ;   
127
 
        
128
 
        private synchronized Interpreter getMathPiper() {                               
129
 
                if (ggbMathPiper == null) {
130
 
                        // where to find MathPiper scripts
131
 
                        //eg docBase = "jar:http://www.geogebra.org/webstart/alpha/geogebra_cas.jar!/";
132
 
                        String scriptBase = "jar:" + app.getCodeBase().toString() + 
133
 
                                                                                Application.CAS_JAR_NAME + "!/";                        
134
 
 
135
 
                        ggbMathPiper = Interpreters.getSynchronousInterpreter(scriptBase);
136
 
                        boolean success = initMyMathPiperFunctions();
137
 
                        
138
 
                        if (!success) {
139
 
                                System.err.println("MathPiper creation failed with scriptbase: " + scriptBase);
140
 
                                ggbMathPiper = Interpreters.getSynchronousInterpreter(scriptBase);
141
 
                                success = initMyMathPiperFunctions();
142
 
                                if (!success)
143
 
                                        System.out.println("MathPiper creation failed again with null scriptbase");
144
 
                        }
145
 
                }
146
 
                
147
 
                return ggbMathPiper;
148
 
        }       
149
 
        
150
 
        /**
151
 
         * Initialize special commands needed in our ggbMathPiper instance,e.g.
152
 
         * getPolynomialCoeffs(exp,x).
153
 
         */
154
 
        private synchronized boolean initMyMathPiperFunctions() {
155
 
// Expand expression and get polynomial coefficients using MathPiper:
156
 
//              getPolynomialCoeffs(expr,x) :=
157
 
//                             If( CanBeUni(expr),
158
 
//                                 [
159
 
//                                                      Coef(MakeUni(expr,x),x, 0 .. Degree(expr,x));                              ],
160
 
//                                 {};
161
 
//                            );
162
 
                String strGetPolynomialCoeffs = "getPolynomialCoeffs(expr,x) := If( CanBeUni(expr),[ Coef(MakeUni(expr,x),x, 0 .. Degree(expr,x));],{});";
163
 
                EvaluationResponse resp = ggbMathPiper.evaluate(strGetPolynomialCoeffs);
164
 
                if (resp.isExceptionThrown()) {
165
 
                        return false;
166
 
                }
167
 
                
168
 
                // make sure we get (x^n)^2 not x^n^2
169
 
                // (Issue 125)
170
 
                ggbMathPiper.evaluate("LeftPrecedence(\"^\",19);");
171
 
 
172
 
                // make sure Factor((((((((9.1) * ((x)^(7))) - ((32) * ((x)^(6)))) + ((48) * ((x)^(5)))) - ((40) * ((x)^(4)))) + ((20) * ((x)^(3)))) - ((6) * ((x)^(2)))) + (x))] works
173
 
                String initFactor = "Factors(p_IsRational)_(Denom(p) != 1) <-- {{Factor(Numer(p)) / Factor(Denom(p)) , 1}};";
174
 
                ggbMathPiper.evaluate(initFactor);
175
 
 
176
 
                // define constanct for Degree
177
 
                response = ggbMathPiper.evaluate("Degree := 180/pi;");
178
 
                
179
 
                return true;
180
 
        }
181
 
        
182
 
 
183
 
        final public String simplifyMathPiper(String exp) {
184
 
                return evaluateMathPiper("Simplify", exp );
185
 
        }
186
 
        
187
 
        final public String factorMathPiper(String exp) {
188
 
                return evaluateMathPiper("Factor", exp );
189
 
        }
190
 
 
191
 
        final public String expandMathPiper(String exp) {
192
 
                return evaluateMathPiper("ExpandBrackets", exp );
193
 
        }
194
 
        
195
 
        HashMap getPolynomialCoeffsCache = new HashMap(50);
196
 
        StringBuffer getPolynomialCoeffsSB = new StringBuffer();
197
 
        
198
 
        /**
199
 
         * Expands the given MathPiper expression and tries to get its polynomial
 
236
        final synchronized public String getGeoGebraCASError() {
 
237
                return getCurrentCAS().getEvaluateGeoGebraCASerror();
 
238
        }
 
239
        
 
240
        /** 
 
241
         * Evaluates an expression in MathPiper syntax.
 
242
     * @return result string (null possible)
 
243
     * @deprecated since GeoGebra 4.0
 
244
     *
 
245
        final public String evaluateMathPiper(String exp) {             
 
246
                return getMathPiper().evaluateMathPiper(exp);
 
247
        }*/
 
248
        
 
249
        /** 
 
250
         * Evaluates an expression in Maxima syntax.
 
251
     * @return result string (null possible)
 
252
     *
 
253
        final public String evaluateMaxima(String exp) {
 
254
                return getMaxima().evaluateMaxima(exp);
 
255
        }
 
256
         * @throws Throwable */
 
257
        
 
258
        final public String evaluateMPReduce(String exp) throws CASException
 
259
        {
 
260
                return getMPReduce().evaluateMPReduce(exp);
 
261
        }
 
262
 
 
263
 
 
264
        // these variables are cached to gain some speed in getPolynomialCoeffs
 
265
        private Map<String, String[]> getPolynomialCoeffsCache = new MaxSizeHashMap<String, String[]>(Kernel.GEOGEBRA_CAS_CACHE_SIZE);
 
266
        private StringBuilder getPolynomialCoeffsSB = new StringBuilder();
 
267
        private StringBuilder sbPolyCoeffs = new StringBuilder();
 
268
        
 
269
        /**
 
270
         * Expands the given MPreduce expression and tries to get its polynomial
200
271
         * coefficients. The coefficients are returned in ascending order. If exp is
201
272
         * not a polynomial, null is returned.
202
273
         * 
203
274
         * example: getPolynomialCoeffs("3*a*x^2 + b"); returns ["b", "0", "3*a"]
204
275
         */
205
 
        final public String[] getPolynomialCoeffs(String MathPiperExp, String variable) {
206
 
                //return ggbJasymca.getPolynomialCoeffs(MathPiperExp, variable);
207
 
                
 
276
        final public String[] getPolynomialCoeffs(String polyExpr, String variable) {
208
277
                getPolynomialCoeffsSB.setLength(0);
209
 
                getPolynomialCoeffsSB.append(MathPiperExp);
210
 
                getPolynomialCoeffsSB.append(':');
 
278
                getPolynomialCoeffsSB.append(polyExpr);
 
279
                getPolynomialCoeffsSB.append(',');
211
280
                getPolynomialCoeffsSB.append(variable);
212
281
                
213
 
                String result = (String)(getPolynomialCoeffsCache.get(getPolynomialCoeffsSB.toString()));
214
 
                
215
 
                if (result != null) {
216
 
                        //Application.debug("using cached result: "+result);
217
 
                        // remove { } to get "b, 0, 3*a"
218
 
                        result = result.substring(1, result.length()-1);
219
 
                        
220
 
                        // split to get coefficients array ["b", "0", "3*a"]
221
 
                        String [] coeffs = result.split(",");                               
222
 
                return coeffs;  
223
 
                }
224
 
                
225
 
                
226
 
                if (sbPolyCoeffs == null)
227
 
                        sbPolyCoeffs = new StringBuffer();
228
 
                else
229
 
                        sbPolyCoeffs.setLength(0);
230
 
                
231
 
                
232
 
                /* replaced Michael Borcherds 2009-02-08
233
 
                 * doesn't seem to work properly polyCoeffsbug.ggb
234
 
                 */
235
 
                sbPolyCoeffs.append("getPolynomialCoeffs(");
236
 
                sbPolyCoeffs.append(MathPiperExp);
237
 
                sbPolyCoeffs.append(',');
238
 
                sbPolyCoeffs.append(variable);
 
282
                String[] result = getPolynomialCoeffsCache.get(getPolynomialCoeffsSB.toString());
 
283
                if (result != null)
 
284
                        return result;
 
285
                
 
286
                sbPolyCoeffs.setLength(0);
 
287
                sbPolyCoeffs.append("coeff(");
 
288
                sbPolyCoeffs.append(getPolynomialCoeffsSB.toString());
239
289
                sbPolyCoeffs.append(')');
240
 
                
241
 
 
242
 
                // Expand expression and get polynomial coefficients using MathPiper:
243
 
                // Prog( Local(exp), 
244
 
                //       exp := ExpandBrackets( 3*a*x^2 + b ), 
245
 
                //               Coef(exp, x, 0 .. Degree(exp, x)) 
246
 
                // )            
247
 
                //sbPolyCoeffs.append("Prog( Local(exp), exp := ExpandBrackets(");
248
 
                //sbPolyCoeffs.append(MathPiperExp);
249
 
                //sbPolyCoeffs.append("), Coef(exp, x, 0 .. Degree(exp, x)))");
250
290
                        
251
291
                try {
252
292
                        // expand expression and get coefficients of
253
293
                        // "3*a*x^2 + b" in form "{ b, 0, 3*a }" 
254
 
                        result = evaluateMathPiper(sbPolyCoeffs.toString());
255
 
                        
256
 
                        // empty list of coefficients -> return null
257
 
                        if ("{}".equals(result) || "".equals(result) || result == null) 
258
 
                                return null;
259
 
                        
260
 
                        // cache result
261
 
                        //Application.debug("caching result: "+result);         
 
294
                        String tmp = evaluateMPReduce(sbPolyCoeffs.toString());
 
295
                
 
296
                        // no result
 
297
                        if ("{}".equals(tmp) || "".equals(tmp) || tmp == null)  
 
298
                                return null;
 
299
                        
 
300
                        // not a polynomial: result still includes the variable, e.g. "x"
 
301
                        if (tmp.indexOf(variable) >= 0) 
 
302
                                return null;
 
303
                        
 
304
                        // get names of escaped global variables right
 
305
                        // e.g. "ggbcasvara" needs to be changed to "a"
 
306
                        tmp = app.getKernel().removeCASVariablePrefix(tmp);
 
307
 
 
308
                        tmp = tmp.substring(1, tmp.length()-1); // strip '{' and '}'
 
309
                        result = tmp.split(",");
 
310
                        
262
311
                        getPolynomialCoeffsCache.put(getPolynomialCoeffsSB.toString(), result);
263
 
 
264
 
                        //Application.debug(sbPolyCoeffs+"");
265
 
                        //Application.debug(result+"");
266
 
                        
267
 
                        // remove { } to get "b, 0, 3*a"
268
 
                        result = result.substring(1, result.length()-1);
269
 
                        
270
 
                        // split to get coefficients array ["b", "0", "3*a"]
271
 
                        String [] coeffs = result.split(",");                               
272
 
            return coeffs;                                              
 
312
            return result;                                              
273
313
                } 
274
 
                catch(Exception e) {
 
314
                catch(Throwable e) {
275
315
                        Application.debug("GeoGebraCAS.getPolynomialCoeffs(): " + e.getMessage());
276
316
                        //e.printStackTrace();
277
317
                }
278
318
                
279
319
                return null;
280
320
        }
281
 
 
282
 
 
283
 
        /**
284
 
         * Converts all index characters ('_', '{', '}') in the given String
285
 
         * to "unicode" + charactercode + DELIMITER Strings. This is needed because
286
 
         * MathPiper does not handle indices correctly.
287
 
         */
288
 
        private synchronized String replaceIndices(String str) {
289
 
                int len = str.length();
290
 
                sbReplaceIndices.setLength(0);
291
 
                
292
 
                boolean foundIndex = false;
293
 
 
294
 
                // convert every single character and append it to sb
295
 
                for (int i = 0; i < len; i++) {
296
 
                        char c = str.charAt(i);
297
 
                        int code = (int) c;
298
 
                        
299
 
                        boolean replaceCharacter = false;                       
300
 
                        switch (c) {
301
 
                                case '_': // start index
302
 
                                        foundIndex = true;
303
 
                                        replaceCharacter = true;
304
 
                                        break;
305
 
                                                                                
306
 
                                case '{':       
307
 
                                        if (foundIndex) {
308
 
                                                replaceCharacter = true;                                                
309
 
                                        }                                       
310
 
                                        break;                                  
311
 
                                        
312
 
                                case '}':
313
 
                                        if (foundIndex) {
314
 
                                                replaceCharacter = true;
315
 
                                                foundIndex = false; // end of index
316
 
                                        }                                       
317
 
                                        break;
318
 
                                        
319
 
                                default:
320
 
                                        replaceCharacter = false;
321
 
                        }
322
 
                        
323
 
                        if (replaceCharacter) {
324
 
                                sbReplaceIndices.append(ExpressionNode.UNICODE_PREFIX);
325
 
                                sbReplaceIndices.append(code);
326
 
                                sbReplaceIndices.append(ExpressionNode.UNICODE_DELIMITER);
327
 
                        } else {
328
 
                                sbReplaceIndices.append(c);
329
 
                        }
330
 
                }
331
 
                                        
332
 
                return sbReplaceIndices.toString();
333
 
        }
334
 
 
335
 
        /**
336
 
         * Reverse operation of removeSpecialChars().
337
 
         * @see ExpressionNode.operationToString() for XCOORD, YCOORD
338
 
         */
339
 
        private String insertSpecialChars(String str) {
340
 
                int len = str.length();
341
 
                sbInsertSpecial.setLength(0);
342
 
 
343
 
                // convert every single character and append it to sb
344
 
                char prefixStart = ExpressionNode.UNICODE_PREFIX.charAt(0);
345
 
                int prefixLen = ExpressionNode.UNICODE_PREFIX.length();
346
 
                boolean prefixFound;
347
 
                for (int i = 0; i < len; i++) {
348
 
                        char c = str.charAt(i);
349
 
                        prefixFound = false;
350
 
 
351
 
                        // first character of prefix found
352
 
                        if (c == prefixStart) {
353
 
                                prefixFound = true;
354
 
                                // check prefix
355
 
                                int j = i;
356
 
                                for (int k = 0; k < prefixLen; k++, j++) {
357
 
                                        if (ExpressionNode.UNICODE_PREFIX.charAt(k) != str
358
 
                                                        .charAt(j)) {
359
 
                                                prefixFound = false;
360
 
                                                break;
361
 
                                        }
362
 
                                }
363
 
 
364
 
                                if (prefixFound) {
365
 
                                        // try to get the unicode
366
 
                                        int code = 0;
367
 
                                        char digit;
368
 
                                        while (j < len && Character.isDigit(digit = str.charAt(j))) {
369
 
                                                code = 10 * code + (digit - 48);
370
 
                                                j++;
371
 
                                        }
372
 
 
373
 
                                        if (code > 0 && code < 65536) { // valid unicode
374
 
                                                sbInsertSpecial.append((char) code);
375
 
                                                i = j;
376
 
                                        } else { // invalid
377
 
                                                sbInsertSpecial.append(ExpressionNode.UNICODE_PREFIX);
378
 
                                                i += prefixLen;
379
 
                                        }
380
 
                                } else {
381
 
                                        sbInsertSpecial.append(c);
382
 
                                }
383
 
                        } else {
384
 
                                sbInsertSpecial.append(c);
385
 
                        }
386
 
                }
387
 
                return sbInsertSpecial.toString();
388
 
        }
389
 
 
390
 
        
391
 
        /*
392
 
         * public static void main(String [] args) {
393
 
         * 
394
 
         * GeoGebraCAS cas = new GeoGebraCAS();
395
 
         * 
396
 
         * Application.debug("GGBCAS"); // Read/eval/print loop int i=1;
397
 
         * while(true){ Application.debug( "(In"+i+") "); // Prompt try{ String line =
398
 
         * readLine(System.in); //String result = MathPiper.Evaluate(line);
399
 
         * 
400
 
         * String result = cas.evaluateJASYMCA(line);
401
 
         * 
402
 
         * Application.debug( "(Out"+i+") "+result ); i++; }catch(Exception e){
403
 
         * Application.debug("\n"+e); } } }
404
 
         */
405
 
 
 
321
        
 
322
        final private String toString(ExpressionValue ev, boolean symbolic) {
 
323
                if (symbolic)
 
324
                        return ev.toString();
 
325
                else
 
326
                        return ev.toValueString();
 
327
                
 
328
        }
 
329
        
 
330
        /**
 
331
         * Returns the CAS command for the currently set CAS using the given key and command arguments. 
 
332
         * For example, getCASCommand("Expand.1", {"3*(a+b)"}) returns "ExpandBrackets( 3*(a+b) )" when
 
333
         * MathPiper is the currently used CAS.
 
334
         */
 
335
        final synchronized public String getCASCommand(String name, ArrayList args, boolean symbolic) {
 
336
                StringBuilder sbCASCommand = new StringBuilder(80);
 
337
                                
 
338
                // build command key as name + ".N"
 
339
                sbCASCommand.setLength(0);
 
340
                sbCASCommand.append(name);
 
341
                sbCASCommand.append(".N");
 
342
                
 
343
                String translation = getCurrentCAS().getTranslatedCASCommand(sbCASCommand.toString());
 
344
 
 
345
                // check for eg Sum.N=sum(%)
 
346
                if (translation != null) {
 
347
                        sbCASCommand.setLength(0);
 
348
                        for (int i = 0; i < translation.length(); i++) {
 
349
                                char ch = translation.charAt(i);
 
350
                                if (ch == '%') {
 
351
                                        if (args.size() == 1) { // might be a list as the argument
 
352
                                                ExpressionValue ev = (ExpressionValue) args.get(0);
 
353
                                                String str = toString(ev, symbolic);
 
354
                                                if (ev.isListValue()) {
 
355
                                                        // is a list, remove { and }
 
356
                                                        // resp. list( ... ) in mpreduce
 
357
                                                        if (currentCAS==Application.CAS_MPREDUCE)
 
358
                                                                sbCASCommand.append(str.substring(22, str.length() - 2));
 
359
                                                        else
 
360
                                                                sbCASCommand.append(str.substring(1, str.length() - 1));
 
361
                                                } else {
 
362
                                                        // not a list, just append
 
363
                                                        sbCASCommand.append(str);
 
364
                                                }
 
365
                                        }
 
366
                                        else {
 
367
                                                for (int j=0; j < args.size(); j++) {
 
368
                                                ExpressionValue ev = (ExpressionValue) args.get(j);                             
 
369
                                                sbCASCommand.append(toString(ev, symbolic));
 
370
                                                sbCASCommand.append(',');
 
371
                                                }
 
372
                                                // remove last comma
 
373
                                                sbCASCommand.setLength(sbCASCommand.length() - 1);
 
374
                                        }
 
375
                                } else {
 
376
                                        sbCASCommand.append(ch);
 
377
                                }
 
378
                                        
 
379
                        }
 
380
                        
 
381
                        return sbCASCommand.toString();
 
382
                }
 
383
                
 
384
                // build command key as name + "." + args.size()
 
385
                // remove 'N'
 
386
                sbCASCommand.setLength(sbCASCommand.length() - 1);
 
387
                // add eg '3'
 
388
                sbCASCommand.append(args.size());
 
389
                
 
390
                // get translation ggb -> MathPiper/Maxima
 
391
                translation = getCurrentCAS().getTranslatedCASCommand(sbCASCommand.toString());
 
392
                sbCASCommand.setLength(0);              
 
393
                
 
394
                // no translation found: 
 
395
                // use key as function name
 
396
                if (translation == null) {              
 
397
                        
 
398
                        // convert command names x, y, z to xcoord, ycoord, ycoord to protect it in CAS
 
399
                        // see http://www.geogebra.org/trac/ticket/1440
 
400
                        boolean handled = false;
 
401
                        if (name.length() == 1) {
 
402
                                char ch = name.charAt(0);
 
403
                                if (ch == 'x' || ch == 'y' || ch == 'z') {
 
404
                                        sbCASCommand.append(ch);
 
405
                                        sbCASCommand.append("coord");
 
406
                                        handled = true;
 
407
                                }
 
408
                        }
 
409
                                
 
410
                        // standard case: add ggbcasvar prefix to name for CAS
 
411
                        if (!handled)
 
412
                                sbCASCommand.append(app.getKernel().printVariableName(name));
 
413
                        
 
414
                        sbCASCommand.append('(');
 
415
                        for (int i=0; i < args.size(); i++) {
 
416
                                ExpressionValue ev = (ExpressionValue) args.get(i);                             
 
417
                                sbCASCommand.append(toString(ev,symbolic));
 
418
                                sbCASCommand.append(',');
 
419
                        }
 
420
                        sbCASCommand.setCharAt(sbCASCommand.length()-1, ')');
 
421
                }
 
422
                
 
423
                // translation found: 
 
424
                // replace %0, %1, etc. in translation by command arguments
 
425
                else {
 
426
                        for (int i = 0; i < translation.length(); i++) {
 
427
                                char ch = translation.charAt(i);
 
428
                                if (ch == '%') {
 
429
                                        // get number after %
 
430
                                        i++;
 
431
                                        int pos = translation.charAt(i) - '0';
 
432
                                        if (pos >= 0 && pos < args.size()) {
 
433
                                                // success: insert argument(pos)
 
434
                                                ExpressionValue ev = (ExpressionValue) args.get(pos);                           
 
435
                                                if (symbolic)
 
436
                                                        sbCASCommand.append(ev.toString());
 
437
                                                else
 
438
                                                        sbCASCommand.append(ev.toValueString());
 
439
                                        } else {
 
440
                                                // failed
 
441
                                                sbCASCommand.append(ch);
 
442
                                                sbCASCommand.append(translation.charAt(i));
 
443
                                        }
 
444
                                } else {
 
445
                                        sbCASCommand.append(ch);
 
446
                                }
 
447
                        }
 
448
                }
 
449
 
 
450
                return sbCASCommand.toString();
 
451
        }
 
452
        
 
453
        /**
 
454
         * Returns true if the two input expressions are structurally equal. 
 
455
         * For example "2 + 2/3" is structurally equal to "2 + (2/3)"
 
456
         * but unequal to "(2 + 2)/3"
 
457
         * @param internalInput includes internal command names
 
458
         * @param localizedInput includes localized command names
 
459
         */
 
460
        public boolean isStructurallyEqual(ValidExpression inputVE, String localizedInput) {
 
461
                try {
 
462
                        // current input
 
463
                        String input1normalized = casParser.toString(inputVE, ExpressionNode.STRING_TYPE_GEOGEBRA_XML);                 
 
464
                        
 
465
                        // new input
 
466
                        ValidExpression ve2 = casParser.parseGeoGebraCASInputAndResolveDummyVars(localizedInput);
 
467
                        String input2normalized = casParser.toString(ve2, ExpressionNode.STRING_TYPE_GEOGEBRA_XML);
 
468
                        
 
469
                        // compare if the parsed expressions are equal
 
470
                        return input1normalized.equals(input2normalized);
 
471
                } 
 
472
                catch (Throwable th) {
 
473
                        System.err.println("GeoGebraCAS.isStructurallyEqual: " + th.getMessage() );
 
474
                        return false;
 
475
                }
 
476
        }
 
477
        
406
478
}
 
 
b'\\ No newline at end of file'