001: package JSci.io;
002:
003: import java.util.Set;
004: import java.util.HashSet;
005: import JSci.maths.*;
006: import JSci.maths.matrices.*;
007: import JSci.maths.vectors.*;
008: import JSci.maths.fields.*;
009: import org.w3c.dom.*;
010: import org.w3c.dom.mathml.*;
011: import org.xml.sax.SAXNotRecognizedException;
012: import org.xml.sax.SAXNotSupportedException;
013: import org.apache.xerces.parsers.DOMParser;
014:
015: /**
016: * The MathMLParser class will parse a MathML document into JSci objects.
017: * @version 0.9
018: * @author Mark Hale
019: */
020: public final class MathMLParser extends DOMParser {
021: /**
022: * Constructs a MathMLParser.
023: */
024: public MathMLParser() {
025: try {
026: setProperty(
027: "http://apache.org/xml/properties/dom/document-class-name",
028: "JSci.mathml.MathMLDocumentImpl");
029: } catch (SAXNotRecognizedException e) {
030: e.printStackTrace();
031: } catch (SAXNotSupportedException e) {
032: e.printStackTrace();
033: }
034: }
035:
036: /**
037: * Translates the document into JSci objects.
038: */
039: public Object[] translateToJSciObjects() {
040: return translateToJSciObjects(getDocument()
041: .getDocumentElement());
042: }
043:
044: public static Object[] translateToJSciObjects(Node root) {
045: Translator translator = new JSciObjectTranslator();
046: return translator.translate(root);
047: }
048:
049: /**
050: * Translates the document into JSci code.
051: */
052: public Object[] translateToJSciCode() {
053: return translateToJSciCode(getDocument().getDocumentElement());
054: }
055:
056: public static Object[] translateToJSciCode(Node root) {
057: Translator translator = new JSciCodeTranslator();
058: return translator.translate(root);
059: }
060:
061: /**
062: * Translator.
063: */
064: static abstract class Translator extends Object {
065: public Translator() {
066: }
067:
068: public Object[] translate(Node root) {
069: return parseMATH(root);
070: }
071:
072: /**
073: * Parses the <math> node.
074: */
075: private Object[] parseMATH(Node n) {
076: int len = 0;
077: final NodeList nl = n.getChildNodes();
078: final Object objList[] = new Object[nl.getLength()];
079: Object obj;
080: for (int i = 0; i < objList.length; i++) {
081: obj = processNode(nl.item(i));
082: if (obj != null) {
083: objList[len] = obj;
084: len++;
085: }
086: }
087: final Object parseList[] = new Object[len];
088: System.arraycopy(objList, 0, parseList, 0, len);
089: return parseList;
090: }
091:
092: /**
093: * Processes a node.
094: */
095: protected Object processNode(Node n) {
096: final String nodeName = n.getNodeName();
097: if (n instanceof MathMLApplyElement
098: || nodeName.equals("reln"))
099: return parseAPPLY((MathMLContentContainer) n);
100: else if (n instanceof MathMLCnElement)
101: return parseCN((MathMLCnElement) n);
102: else if (n instanceof MathMLCiElement)
103: return parseCI((MathMLCiElement) n);
104: else if (n instanceof MathMLPredefinedSymbol)
105: return parsePredefinedSymbol((MathMLPredefinedSymbol) n);
106: else if (n instanceof MathMLVectorElement)
107: return parseVECTOR((MathMLVectorElement) n);
108: else if (n instanceof MathMLMatrixElement)
109: return parseMATRIX((MathMLMatrixElement) n);
110: else if (n instanceof MathMLSetElement)
111: return parseSET((MathMLSetElement) n);
112: else if (n instanceof MathMLStringLitElement)
113: return parseMS((MathMLStringLitElement) n);
114: else if (nodeName.equals("mtext"))
115: return parseMTEXT((MathMLPresentationToken) n);
116: else
117: return null;
118: }
119:
120: protected abstract Object parseAPPLY(MathMLContentContainer n);
121:
122: protected abstract Object parseCN(MathMLCnElement n);
123:
124: protected abstract Object parseCI(MathMLCiElement n);
125:
126: protected abstract Object parseVECTOR(MathMLVectorElement n);
127:
128: protected abstract Object parseMATRIX(MathMLMatrixElement n);
129:
130: protected abstract Object parseSET(MathMLSetElement n);
131:
132: protected abstract Object parseMS(MathMLStringLitElement n);
133:
134: protected abstract Object parseMTEXT(MathMLPresentationToken n);
135:
136: protected abstract Object parsePredefinedSymbol(
137: MathMLPredefinedSymbol n);
138: }
139:
140: /**
141: * JSci object translator.
142: */
143: static class JSciObjectTranslator extends Translator {
144: private final int INTEGER = 0;
145: private final int DOUBLE = 1;
146: private final int COMPLEX = 2;
147: private int setID = 1;
148:
149: public JSciObjectTranslator() {
150: }
151:
152: /**
153: * Parses <apply> tags.
154: * @return MathMLExpression.
155: */
156: protected Object parseAPPLY(MathMLContentContainer n) {
157: final MathMLExpression expr = new MathMLExpression();
158: final NodeList nl = n.getChildNodes();
159: Object obj;
160: int i;
161: for (i = 0; nl.item(i).getNodeType() == Node.TEXT_NODE; i++)
162: ;
163: expr.setOperation(nl.item(i).getNodeName());
164: for (; i < nl.getLength(); i++) {
165: obj = processNode(nl.item(i));
166: if (obj != null)
167: expr.addArgument(obj);
168: }
169: return expr;
170: }
171:
172: /**
173: * Parses <cn> tags.
174: * @return Ring.Member.
175: */
176: protected Object parseCN(MathMLCnElement n) {
177: return parseNumber(n);
178: }
179:
180: private Ring.Member parseNumber(MathMLCnElement n) {
181: // support only base 10
182: if (!n.getBase().equals("10"))
183: return null;
184: final String attrType = n.getType();
185: if (attrType.equals("real")) {
186: return new MathDouble(n.getFirstChild().getNodeValue());
187: } else if (attrType.equals("integer")) {
188: return new MathInteger(n.getFirstChild().getNodeValue());
189: } else if (attrType.equals("rational")) {
190: final Node num = n.getArgument(1);
191: final Node denom = n.getArgument(2);
192: return new MathDouble(num.getNodeValue())
193: .divide(new MathDouble(denom.getNodeValue()));
194: } else if (attrType.equals("complex-cartesian")) {
195: final Node re = n.getArgument(1);
196: final Node im = n.getArgument(2);
197: return new Complex(new Double(re.getNodeValue())
198: .doubleValue(), new Double(im.getNodeValue())
199: .doubleValue());
200: } else if (attrType.equals("complex-polar")) {
201: final Node mod = n.getArgument(1);
202: final Node arg = n.getArgument(2);
203: return Complex.polar(new Double(mod.getNodeValue())
204: .doubleValue(), new Double(arg.getNodeValue())
205: .doubleValue());
206: } else if (attrType.equals("constant")) {
207: final String value = n.getFirstChild().getNodeValue();
208: if (value.equals("π"))
209: return RealField.PI;
210: else if (value.equals("ⅇ")
211: || value.equals("ⅇ"))
212: return RealField.E;
213: else if (value.equals("ⅈ")
214: || value.equals("ⅈ"))
215: return ComplexField.I;
216: else if (value.equals("γ"))
217: return RealField.GAMMA;
218: else if (value.equals("&infty;")
219: || value.equals("∞"))
220: return RealField.INFINITY;
221: else if (value.equals("&NaN;")
222: || value.equals("&NotANumber;"))
223: return RealField.NaN;
224: /*
225: else if(value.equals("&true;"))
226: return MathBoolean.TRUE;
227: else if(value.equals("&false;"))
228: return MathBoolean.FALSE;
229: */
230: else
231: return null;
232: } else
233: return null;
234: }
235:
236: protected Object parsePredefinedSymbol(MathMLPredefinedSymbol n) {
237: String nodeName = n.getNodeName();
238: if (nodeName.equals("pi"))
239: return RealField.PI;
240: else if (nodeName.equals("exponentiale"))
241: return RealField.E;
242: else if (nodeName.equals("imaginaryi"))
243: return ComplexField.I;
244: else if (nodeName.equals("eulergamma"))
245: return RealField.GAMMA;
246: else if (nodeName.equals("infinity"))
247: return RealField.INFINITY;
248: else if (nodeName.equals("notanumber"))
249: return RealField.NaN;
250: /*
251: else if(nodeName.equals("true"))
252: return MathBoolean.TRUE;
253: else if(nodeName.equals("false"))
254: return MathBoolean.FALSE;
255: */
256: else
257: return null;
258: }
259:
260: /**
261: * Parses <ci> tags.
262: * @return String.
263: */
264: protected Object parseCI(MathMLCiElement n) {
265: return n.getFirstChild().getNodeValue();
266: }
267:
268: /**
269: * Parses <vector> tags.
270: * @return MathVector.
271: */
272: protected Object parseVECTOR(MathMLVectorElement n) {
273: int len = 0, type = INTEGER;
274: final Ring.Member num[] = new Ring.Member[n
275: .getNcomponents()];
276: for (int i = 0; i < num.length; i++) {
277: MathMLContentElement elem = n.getComponent(i + 1);
278: if (elem instanceof MathMLCnElement) {
279: num[len] = parseNumber((MathMLCnElement) elem);
280: if (num[len] != null) {
281: // work out number format needed
282: if (num[len] instanceof MathDouble
283: && type < DOUBLE)
284: type = DOUBLE;
285: else if (num[len] instanceof Complex
286: && type < COMPLEX)
287: type = COMPLEX;
288: len++;
289: }
290: }
291: }
292: // output to JSci objects
293: if (type == INTEGER) {
294: final int array[] = new int[len];
295: for (int i = 0; i < array.length; i++)
296: array[i] = ((MathInteger) num[i]).value();
297: return new IntegerVector(array);
298: } else if (type == DOUBLE) {
299: final double array[] = new double[len];
300: for (int i = 0; i < array.length; i++) {
301: if (num[i] instanceof MathInteger)
302: array[i] = ((MathInteger) num[i]).value();
303: else
304: array[i] = ((MathDouble) num[i]).value();
305: }
306: return new DoubleVector(array);
307: } else {
308: final Complex array[] = new Complex[len];
309: for (int i = 0; i < array.length; i++) {
310: if (num[i] instanceof MathInteger)
311: array[i] = new Complex(((MathInteger) num[i])
312: .value(), 0.0);
313: else if (num[i] instanceof MathDouble)
314: array[i] = new Complex(((MathDouble) num[i])
315: .value(), 0.0);
316: else
317: array[i] = (Complex) num[i];
318: }
319: return new ComplexVector(array);
320: }
321: }
322:
323: /**
324: * Parses <matrix> tags.
325: * @return Matrix.
326: */
327: protected Object parseMATRIX(MathMLMatrixElement n) {
328: int rows = 0, cols = Integer.MAX_VALUE;
329: final Ring.Member num[][] = new Ring.Member[n.getNrows()][];
330: for (int i = 0; i < num.length; i++) {
331: num[rows] = parseMatrixRow(n.getRow(i + 1));
332: if (num[rows].length < cols)
333: cols = num[rows].length;
334: rows++;
335: }
336: // work out number format needed
337: int type = INTEGER;
338: for (int j, i = 0; i < rows; i++) {
339: for (j = 0; j < cols; j++) {
340: if (num[i][j] instanceof MathDouble
341: && type < DOUBLE)
342: type = DOUBLE;
343: else if (num[i][j] instanceof Complex
344: && type < COMPLEX)
345: type = COMPLEX;
346: }
347: }
348: // output to JSci objects
349: if (type == INTEGER) {
350: final int array[][] = new int[rows][cols];
351: for (int j, i = 0; i < rows; i++) {
352: for (j = 0; j < cols; j++)
353: array[i][j] = ((MathInteger) num[i][j]).value();
354: }
355: if (rows == cols)
356: return new IntegerSquareMatrix(array);
357: else
358: return new IntegerMatrix(array);
359: } else if (type == DOUBLE) {
360: final double array[][] = new double[rows][cols];
361: for (int j, i = 0; i < rows; i++) {
362: for (j = 0; j < cols; j++) {
363: if (num[i][j] instanceof MathInteger)
364: array[i][j] = ((MathInteger) num[i][j])
365: .value();
366: else
367: array[i][j] = ((MathDouble) num[i][j])
368: .value();
369: }
370: }
371: if (rows == cols)
372: return new DoubleSquareMatrix(array);
373: else
374: return new DoubleMatrix(array);
375: } else {
376: final Complex array[][] = new Complex[rows][cols];
377: for (int j, i = 0; i < rows; i++) {
378: for (j = 0; j < cols; j++) {
379: if (num[i][j] instanceof MathInteger)
380: array[i][j] = new Complex(
381: ((MathInteger) num[i][j]).value(),
382: 0.0);
383: else if (num[i][j] instanceof MathDouble)
384: array[i][j] = new Complex(
385: ((MathDouble) num[i][j]).value(),
386: 0.0);
387: else
388: array[i][j] = (Complex) num[i][j];
389: }
390: }
391: if (rows == cols)
392: return new ComplexSquareMatrix(array);
393: else
394: return new ComplexMatrix(array);
395: }
396: }
397:
398: /**
399: * Parses <matrixrow> tags.
400: */
401: private Ring.Member[] parseMatrixRow(MathMLMatrixrowElement n) {
402: int len = 0;
403: final Ring.Member num[] = new Ring.Member[n.getNEntries()];
404: for (int i = 0; i < num.length; i++) {
405: MathMLContentElement elem = n.getEntry(i + 1);
406: if (elem instanceof MathMLCnElement) {
407: num[len] = parseNumber((MathMLCnElement) elem);
408: if (num[len] != null)
409: len++;
410: }
411: }
412: final Ring.Member row[] = new Ring.Member[len];
413: System.arraycopy(num, 0, row, 0, len);
414: return row;
415: }
416:
417: /**
418: * Parses <set> tags.
419: * @return FiniteSet.
420: */
421: protected Object parseSET(MathMLSetElement n) {
422: final NodeList nl = n.getChildNodes();
423: final Set elements = new HashSet(nl.getLength());
424: for (int i = 0; i < nl.getLength(); i++) {
425: Node child = nl.item(i);
426: if (child instanceof MathMLCiElement)
427: elements.add(parseCI((MathMLCiElement) child));
428: }
429: // output to JSci objects
430: return new FiniteSet(elements);
431: }
432:
433: /**
434: * Parses <ms> tags.
435: * @return String.
436: */
437: protected Object parseMS(MathMLStringLitElement n) {
438: return n.getFirstChild().getNodeValue();
439: }
440:
441: /**
442: * Parses <mtext> tags.
443: * @return String.
444: */
445: protected Object parseMTEXT(MathMLPresentationToken n) {
446: return n.getFirstChild().getNodeValue();
447: }
448: }
449:
450: /**
451: * JSci code translator.
452: */
453: static class JSciCodeTranslator extends Translator {
454: public JSciCodeTranslator() {
455: }
456:
457: /**
458: * Parses <apply> tags.
459: * @return String.
460: */
461: protected Object parseAPPLY(MathMLContentContainer n) {
462: final StringBuffer buf = new StringBuffer();
463: final NodeList nl = n.getChildNodes();
464: Object obj;
465: int i;
466: for (i = 0; nl.item(i).getNodeType() == Node.TEXT_NODE; i++)
467: ;
468: String op = nl.item(i).getNodeName();
469: if (op.equals("plus"))
470: op = "add";
471: else if (op.equals("minus"))
472: op = "subtract";
473: else if (op.equals("times"))
474: op = "multiply";
475: boolean isFirst = true;
476: for (; i < nl.getLength(); i++) {
477: obj = processNode(nl.item(i));
478: if (obj != null) {
479: if (isFirst) {
480: buf.append(obj);
481: isFirst = false;
482: } else
483: buf.append('.').append(op).append('(').append(
484: obj).append(')');
485: }
486: }
487: return buf;
488: }
489:
490: /**
491: * Parses <cn> tags.
492: * @return String.
493: */
494: protected Object parseCN(MathMLCnElement n) {
495: // support only base 10
496: if (!n.getBase().equals("10"))
497: return null;
498: final String attrType = n.getType();
499: if (attrType.equals("real")) {
500: return "new MathDouble("
501: + n.getFirstChild().getNodeValue() + ')';
502: } else if (attrType.equals("integer")) {
503: return "new MathInteger("
504: + n.getFirstChild().getNodeValue() + ')';
505: } else if (attrType.equals("rational")) {
506: final Node num = n.getArgument(1);
507: final Node denom = n.getArgument(2);
508: return "new MathDouble(" + num.getNodeValue() + '/'
509: + denom.getNodeValue() + ')';
510: } else if (attrType.equals("complex-cartesian")) {
511: final Node re = n.getArgument(1);
512: final Node im = n.getArgument(2);
513: return "new Complex(" + re.getNodeValue() + ','
514: + im.getNodeValue() + ')';
515: } else if (attrType.equals("complex-polar")) {
516: final Node mod = n.getArgument(1);
517: final Node arg = n.getArgument(2);
518: return "Complex.polar(" + mod.getNodeValue() + ','
519: + arg.getNodeValue() + ')';
520: } else if (attrType.equals("constant")) {
521: final String value = n.getFirstChild().getNodeValue();
522: if (value.equals("π"))
523: return "RealField.PI";
524: else if (value.equals("ⅇ")
525: || value.equals("ⅇ"))
526: return "RealField.E";
527: else if (value.equals("ⅈ")
528: || value.equals("ⅈ"))
529: return "ComplexField.I";
530: else if (value.equals("γ"))
531: return "RealField.GAMMA";
532: else if (value.equals("&infty;")
533: || value.equals("∞"))
534: return "RealField.INFINITY";
535: else if (value.equals("&NaN;")
536: || value.equals("&NotANumber;"))
537: return "RealField.NaN";
538: else
539: return null;
540: } else
541: return null;
542: }
543:
544: /**
545: * Parses <ci> tags.
546: * @return String.
547: */
548: protected Object parseCI(MathMLCiElement n) {
549: return n.getFirstChild().getNodeValue();
550: }
551:
552: /**
553: * Parses <vector> tags.
554: * @return String.
555: */
556: protected Object parseVECTOR(MathMLVectorElement n) {
557: return null;
558: }
559:
560: /**
561: * Parses <matrix> tags.
562: * @return String.
563: */
564: protected Object parseMATRIX(MathMLMatrixElement n) {
565: return null;
566: }
567:
568: /**
569: * Parses <set> tags.
570: * @return String.
571: */
572: protected Object parseSET(MathMLSetElement n) {
573: return null;
574: }
575:
576: /**
577: * Parses <ms> tags.
578: * @return String.
579: */
580: protected Object parseMS(MathMLStringLitElement n) {
581: return n.getFirstChild().getNodeValue();
582: }
583:
584: /**
585: * Parses <mtext> tags.
586: * @return String.
587: */
588: protected Object parseMTEXT(MathMLPresentationToken n) {
589: return "/*\n" + n.getFirstChild().getNodeValue() + "\n*/";
590: }
591:
592: protected Object parsePredefinedSymbol(MathMLPredefinedSymbol n) {
593: return null;
594: }
595: }
596: }
|