View Javadoc

1   /* This file is part of the project "Hilbert II" - http://www.qedeq.org" target="alexandria_uri">http://www.qedeq.org
2    *
3    * Copyright 2000-2014,  Michael Meyling <mime@qedeq.org>.
4    *
5    * "Hilbert II" is free software; you can redistribute
6    * it and/or modify it under the terms of the GNU General Public
7    * License as published by the Free Software Foundation; either
8    * version 2 of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU General Public License for more details.
14   */
15  
16  package org.qedeq.kernel.bo.service.internal;
17  
18  import java.util.HashMap;
19  import java.util.Map;
20  
21  import org.qedeq.base.utility.StringUtility;
22  import org.qedeq.kernel.bo.common.Element2Latex;
23  import org.qedeq.kernel.bo.logic.common.ExistenceChecker;
24  import org.qedeq.kernel.bo.module.KernelQedeqBo;
25  import org.qedeq.kernel.bo.module.ModuleLabels;
26  import org.qedeq.kernel.se.base.list.Element;
27  import org.qedeq.kernel.se.base.list.ElementList;
28  import org.qedeq.kernel.se.base.module.FunctionDefinition;
29  import org.qedeq.kernel.se.base.module.PredicateDefinition;
30  import org.qedeq.kernel.se.dto.module.FunctionDefinitionVo;
31  import org.qedeq.kernel.se.dto.module.PredicateDefinitionVo;
32  
33  
34  /**
35   * Transfer a QEDEQ formulas into LaTeX text.
36   *
37   * @author  Michael Meyling
38   */
39  public final class Element2LatexImpl implements Element2Latex {
40  
41      /** Knows about labels, definitions and external QEDEQ module references. */
42      private ModuleLabels labels;
43  
44      /** Maps operator strings to {@link ElementList} to LaTeX mappers. */
45      private final Map elementList2ListType = new HashMap();
46  
47      /** For mapping an unknown operator. */
48      private final ListType unknown = new Unknown();
49  
50      /** Maps predicate identifiers to {@link PredicateDefinition}s. Contains default definitions
51       * as a fallback.*/
52      private final Map backupPredicateDefinitions = new HashMap();
53  
54      /** Maps function identifiers to {@link FunctionDefinition}s. Contains default definitions. */
55      private final Map backupFunctionDefinitions = new HashMap();
56  
57      /**
58       * Constructor.
59       *
60       * @param   labels  Knows about labels, definitions and external QEDEQ module references.
61       */
62      public Element2LatexImpl(final ModuleLabels labels) {
63          this.labels = labels;
64  
65          this.elementList2ListType.put("PREDVAR", new Predvar());
66          this.elementList2ListType.put("FUNVAR", new Funvar());
67          this.elementList2ListType.put("PREDCON", new Predcon());
68          this.elementList2ListType.put("FUNCON", new Funcon());
69          this.elementList2ListType.put("VAR", new Var());
70  
71          this.elementList2ListType.put("AND", new BinaryLogical("\\land"));
72          this.elementList2ListType.put("OR", new BinaryLogical("\\lor"));
73          this.elementList2ListType.put("IMPL", new BinaryLogical("\\rightarrow"));
74          this.elementList2ListType.put("EQUI", new BinaryLogical("\\leftrightarrow"));
75  
76          this.elementList2ListType.put("FORALL", new Quantifier("\\forall"));
77          this.elementList2ListType.put("EXISTS", new Quantifier("\\exists"));
78          this.elementList2ListType.put("EXISTSU", new Quantifier("\\exists!"));
79  
80          this.elementList2ListType.put("NOT", new Not());
81          this.elementList2ListType.put("CLASS", new Class());
82          this.elementList2ListType.put("CLASSLIST", new Classlist());
83  
84  //        // TODO mime 20080126: wrong spelled and not used any longer (?)
85  //        this.elementList2ListType.put("QUANTOR_INTERSECTION", new QuantorIntersection());
86  //        this.elementList2ListType.put("QUANTOR_UNION", new QuantorUnion());
87  
88          fillBackup();
89  
90      }
91  
92      /**
93       * Fill backup predicate list (if required modules could not be loaded, or the predicate is
94       * not yet defined.
95       */
96      private void fillBackup() {
97          // logical identity operator
98          addBackupPredicate(ExistenceChecker.NAME_EQUAL, "2", "#1 \\ = \\ #2");
99  
100         // negation of the logical identity operator
101         addBackupPredicate("notEqual", "2", "#1 \\ \\neq \\ #2");
102 
103         addBackupPredicate("in", "2", "#1 \\in #2");
104         addBackupPredicate("notIn", "2", "#1 \\notin #2");
105         addBackupPredicate("isSet", "1", "\\mathfrak{M}(#1)");
106         addBackupPredicate("subclass", "2", "#1 \\ \\subseteq \\ #2");
107         addBackupPredicate("isOrderedPair", "1", "\\mbox{isOrderedPair}(#1)");
108         addBackupPredicate("isRelation", "1", "\\mathfrak{Rel}(#1)");
109         addBackupPredicate("isFunction", "1", "\\mathfrak{Funct}(#1)");
110 
111         addBackupFunction("RussellClass", "0", "\\mathfrak{Ru}");
112         addBackupFunction("universalClass", "0", "\\mathfrak{V}");
113         addBackupFunction("emptySet", "0", "\\emptyset");
114         addBackupFunction("union", "2", "(#1 \\cup #2)");
115         addBackupFunction("intersection", "2", "(#1 \\cap #2)");
116         addBackupFunction("complement", "1", "\\overline{#1}");
117         addBackupFunction("classList", "1", "\\{ #1 \\}");
118         addBackupFunction("classList", "2", "\\{ #1, #2 \\}");
119         addBackupFunction("setProduct", "1", "\\bigcap \\ #1");
120         addBackupFunction("setSum", "1", "\\bigcup \\ #1");
121         addBackupFunction("power", "1", "\\mathfrak{P}(#1)");
122         addBackupFunction("orderedPair", "2", "\\langle #1, #2 \\rangle");
123         addBackupFunction("cartesianProduct", "2", "( #1 \\times #2)");
124         addBackupFunction("domain", "1", "\\mathfrak{Dom}(#1)");
125         addBackupFunction("range", "1", "\\mathfrak{Rng}(#1)");
126         addBackupFunction("successor", "1", "#1'");
127 
128     }
129 
130     /**
131      * Add predicate to backup list.
132      *
133      * @param   name            Predicate name.
134      * @param   argNumber       Number of arguments.
135      * @param   latexPattern    This is the latex presentation. Variables are marked by "#1", "#2"
136      *                          and so on.
137      */
138     private void addBackupPredicate(final String name, final String argNumber,
139             final String latexPattern) {
140         final String key = name + "_" + argNumber;
141         final PredicateDefinitionVo predicate = new PredicateDefinitionVo();
142         predicate.setArgumentNumber(argNumber);
143         predicate.setName(name);
144         predicate.setLatexPattern(latexPattern);
145         backupPredicateDefinitions.put(key, predicate);
146     }
147 
148     /**
149      * Add function to backup list.
150      *
151      * @param   name            Function name.
152      * @param   argNumber       Number of arguments.
153      * @param   latexPattern    This is the LaTex presentation. Variables are marked by "#1", "#2"
154      *                          and so on.
155      */
156     private void addBackupFunction(final String name, final String argNumber,
157             final String latexPattern) {
158         final String key = name + "_" + argNumber;
159         final FunctionDefinitionVo function = new FunctionDefinitionVo();
160         function.setArgumentNumber(argNumber);
161         function.setName(name);
162         function.setLatexPattern(latexPattern);
163         backupFunctionDefinitions.put(key, function);
164     }
165 
166     public String getLatex(final Element element) {
167         return getLatex(element, true);
168     }
169 
170     /**
171      * Get LaTeX element presentation.
172      *
173      * @param   element Print this element.
174      * @param   first   First level?
175      * @return  LaTeX form of element.
176      */
177     String getLatex(final Element element, final boolean first) {
178         if (element == null) {
179             return "";
180         }
181         if (element.isAtom()) {
182             return element.getAtom().getString();
183         }
184         final ElementList list = element.getList();
185 
186         ListType converter = (ListType) elementList2ListType.get(list.getOperator());
187 
188         if (converter == null) {
189             converter = this.unknown;
190         }
191         return converter.getLatex(list, first);
192 
193     }
194 
195     /**
196      * Get default definition mapping of predicate definitions. Our last hope.
197      *
198      * @return  Mapping of predicate definitions.
199      */
200     Map getBackupPredicateDefinitions() {
201         return this.backupPredicateDefinitions;
202     }
203 
204     /**
205      * Get default definition mapping of function definitions. Our last hope.
206      *
207      * @return  Mapping of predicate definitions.
208      */
209     Map getBackupFunctionDefinitions() {
210         return this.backupFunctionDefinitions;
211     }
212 
213     /**
214      * Describes the interface for an {@link ElementList} to LaTeX converter.
215      */
216     interface ListType {
217 
218         /**
219          * Transform list into LaTeX.
220          *
221          * @param   list    This list shall be transformed.
222          * @param   first   Is the resulting LaTeX formula or term at top level? If so we possibly
223          *                  can omit some brackets.
224          * @return  LaTeX formula or term.
225          */
226         public String getLatex(ElementList list, boolean first);
227     }
228 
229     /**
230      * Transformer for a predicate variable.
231      */
232     class Predvar implements ListType {
233         public String getLatex(final ElementList list, final boolean first) {
234             final StringBuffer buffer = new StringBuffer();
235             final String identifier = list.getElement(0).getAtom().getString();
236             buffer.append(identifier);
237             if (list.size() > 1) {
238                 buffer.append("(");
239                 for (int i = 1; i < list.size(); i++) {
240                     buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
241                     if (i + 1 < list.size()) {
242                         buffer.append(", ");
243                     }
244                 }
245                 buffer.append(")");
246             }
247             return buffer.toString();
248         }
249     }
250 
251     /**
252      * Transformer for a function variable.
253      */
254     class Funvar implements ListType {
255         public String getLatex(final ElementList list, final boolean first) {
256             final StringBuffer buffer = new StringBuffer();
257             final String identifier = list.getElement(0).getAtom().getString();
258             buffer.append(identifier);
259             if (list.size() > 1) {
260                 buffer.append("(");
261                 for (int i = 1; i < list.size(); i++) {
262                     buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
263                     if (i + 1 < list.size()) {
264                         buffer.append(", ");
265                     }
266                 }
267                 buffer.append(")");
268             }
269             return buffer.toString();
270         }
271     }
272 
273     /**
274      * Transformer for a predicate constant.
275      */
276     class Predcon implements ListType {
277         public String getLatex(final ElementList list, final boolean first) {
278             final StringBuffer buffer = new StringBuffer();
279             final String name = list.getElement(0).getAtom().getString();
280             final int arguments = list.size() - 1;
281             String identifier = name + "_" + (arguments);
282             // LATER 20060922 m31: is only working for definition name + argument number
283             //  if argument length is dynamic this dosen't work
284             PredicateDefinition definition = (PredicateDefinition)
285                 Element2LatexImpl.this.labels.getPredicateDefinitions().get(identifier);
286             if (definition == null) {
287                 // try external modules
288                 try {
289                     final int external = name.indexOf(".");
290                     if (external >= 0) {
291                         final String shortName = name.substring(external + 1);
292                         identifier = shortName + "_" + (arguments);
293                         if (Element2LatexImpl.this.labels.getReferences() != null
294                             && Element2LatexImpl.this.labels.getReferences().size() > 0) {
295                             final String label = name.substring(0, external);
296                             final KernelQedeqBo newProp = (KernelQedeqBo)
297                                 Element2LatexImpl.this.labels.getReferences().getQedeqBo(label);
298                             if (newProp != null) {
299                                 if (newProp.getExistenceChecker().predicateExists(shortName,
300                                         arguments)) {
301                                     definition = newProp.getLabels()
302                                         .getPredicate(shortName, arguments);
303                                 }
304                             }
305                         }
306                     }
307                 } catch (Exception e) {
308                     // try failed...
309                 }
310             }
311             // we try our backup
312             if (definition == null) {
313                 definition = (PredicateDefinition) Element2LatexImpl.this.getBackupPredicateDefinitions()
314                     .get(identifier);
315             }
316             if (definition != null) {
317                 final StringBuffer define = new StringBuffer(definition.getLatexPattern());
318                 for (int i = list.size() - 1; i >= 1; i--) {
319                     StringUtility.replace(define, "#" + i, Element2LatexImpl.this.getLatex(
320                         list.getElement(i), false));
321                 }
322                 buffer.append(define);
323             } else {
324                 buffer.append(identifier);
325                 buffer.append("(");
326                 for (int i = 1; i < list.size(); i++) {
327                     buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
328                     if (i + 1 < list.size()) {
329                         buffer.append(", ");
330                     }
331                 }
332                 buffer.append(")");
333             }
334             return buffer.toString();
335         }
336     }
337 
338     /**
339      * Transformer for a function constant.
340      */
341     class Funcon implements ListType {
342 
343         public String getLatex(final ElementList list, final boolean first) {
344             final StringBuffer buffer = new StringBuffer();
345             final String name = list.getElement(0).getAtom().getString();
346             final int arguments = list.size() - 1;
347             String identifier = name + "_" + (arguments);
348             // LATER 20060922 m31: is only working for definition name + argument number
349             //  if argument length is dynamic this dosen't work
350             FunctionDefinition definition = (FunctionDefinition)
351                 Element2LatexImpl.this.labels.getFunctionDefinitions().get(identifier);
352             if (definition == null) {
353                 // try external modules
354                 try {
355                     final int external = name.indexOf(".");
356                     if (external >= 0) {
357                         final String shortName = name.substring(external + 1);
358                         identifier = shortName + "_" + (arguments);
359                         if (Element2LatexImpl.this.labels.getReferences() != null
360                                 && Element2LatexImpl.this.labels.getReferences().size() > 0) {
361                             final String label = name.substring(0, external);
362                             final KernelQedeqBo newProp = (KernelQedeqBo)
363                                 Element2LatexImpl.this.labels.getReferences().getQedeqBo(label);
364                             if (newProp != null) {
365                                 if (newProp.getExistenceChecker().functionExists(shortName,
366                                         arguments)) {
367                                     definition = newProp.getLabels()
368                                         .getFunction(shortName, arguments);
369                                 }
370                             }
371                         }
372                     }
373                 } catch (Exception e) {
374                     // try failed...
375                 }
376             }
377             // we try our backup
378             if (definition == null) {
379                 definition = (FunctionDefinition) Element2LatexImpl.this.getBackupFunctionDefinitions()
380                     .get(identifier);
381             }
382             if (definition != null) {
383                 final StringBuffer define = new StringBuffer(definition.getLatexPattern());
384                 for (int i = list.size() - 1; i >= 1; i--) {
385                     StringUtility.replace(define, "#" + i, Element2LatexImpl.this.
386                         getLatex(list.getElement(i), false));
387                 }
388                 buffer.append(define);
389             } else {
390                 buffer.append(identifier);
391                 buffer.append("(");
392                 for (int i = 1; i < list.size(); i++) {
393                     buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
394                     if (i + 1 < list.size()) {
395                         buffer.append(", ");
396                     }
397                 }
398                 buffer.append(")");
399             }
400             return buffer.toString();
401         }
402     }
403 
404     /**
405      * Transformer for a subject variable.
406      */
407     static class Var implements ListType {
408         public String getLatex(final ElementList list, final boolean first) {
409             final String text = list.getElement(0).getAtom().getString();
410             // interpret variable identifier as number
411             try {
412                 final int index = Integer.parseInt(text);
413                 final String newText = "" + index;
414                 if (!text.equals(newText) || newText.startsWith("-")) {
415                     throw new NumberFormatException("This is no allowed number: " + text);
416                 }
417                 switch (index) {
418                 case 1:
419                     return "x";
420                 case 2:
421                     return "y";
422                 case 3:
423                     return "z";
424                 case 4:
425                     return "u";
426                 case 5:
427                     return "v";
428                 case 6:
429                     return "w";
430                 default:
431                     return "x_" + (index - 6);
432                 }
433             } catch (NumberFormatException e) {
434                 // variable identifier is no number, just take it as it is
435                 return text;
436             }
437         }
438     }
439 
440     /**
441      * Transformer for a binary logical operator written in infix notation.
442      */
443     class BinaryLogical implements ListType {
444 
445         /** LaTeX for operator. */
446         private final String latex;
447 
448         /**
449          * Constructor.
450          *
451          * @param   latex   LaTeX for operator.
452          */
453         BinaryLogical(final String latex) {
454             this.latex = latex;
455         }
456 
457         public String getLatex(final ElementList list, final boolean first) {
458             final StringBuffer buffer = new StringBuffer();
459             final String infix = "\\ " + latex + "\\ ";
460             if (!first) {
461                 buffer.append("(");
462             }
463             // we also handle it if it has not exactly two operands
464             for (int i = 0; i < list.size(); i++) {
465                 buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
466                 if (i + 1 < list.size()) {
467                     buffer.append(infix);
468                 }
469             }
470             if (!first) {
471                 buffer.append(")");
472             }
473             return buffer.toString();
474         }
475     }
476 
477     /**
478      * Transformer for a quantifier operator.
479      */
480     class Quantifier implements ListType {
481 
482         /** LaTeX for quantifier. */
483         private final String latex;
484 
485         /**
486          * Constructor.
487          *
488          * @param   latex   LaTeX for quantifier.
489          */
490         Quantifier(final String latex) {
491             this.latex = latex;
492         }
493 
494         public String getLatex(final ElementList list, final boolean first) {
495             final StringBuffer buffer = new StringBuffer();
496             buffer.append(latex + " ");
497             for (int i = 0; i < list.size(); i++) {
498                 if (i != 0 || (i == 0 && list.size() <= 2)) {
499                     buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
500                 }
501                 if (i + 1 < list.size()) {
502                     buffer.append("\\ ");
503                 }
504                 if (list.size() > 2 && i == 1) {
505                     buffer.append("\\ ");
506                 }
507             }
508             return buffer.toString();
509         }
510     }
511 
512     /**
513      * Transformer for negation.
514      */
515     class Not implements ListType {
516         public String getLatex(final ElementList list, final boolean first) {
517             final StringBuffer buffer = new StringBuffer();
518             final String prefix = "\\neg ";
519             buffer.append(prefix);
520             for (int i = 0; i < list.size(); i++) {
521                 buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
522             }
523             return buffer.toString();
524         }
525     }
526 
527     /**
528      * Transformer for a class operator.
529      */
530     class Class implements ListType {
531         public String getLatex(final ElementList list, final boolean first) {
532             final StringBuffer buffer = new StringBuffer();
533             final String prefix = "\\{ ";
534             buffer.append(prefix);
535             for (int i = 0; i < list.size(); i++) {
536                 buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
537                 if (i + 1 < list.size()) {
538                     buffer.append(" \\ | \\ ");
539                 }
540             }
541             buffer.append(" \\} ");
542             return buffer.toString();
543         }
544     }
545 
546     /**
547      * Transformer for class list operator.
548      */
549     class Classlist implements ListType {
550         public String getLatex(final ElementList list, final boolean first) {
551             final StringBuffer buffer = new StringBuffer();
552             final String prefix = "\\{ ";
553             buffer.append(prefix);
554             for (int i = 0; i < list.size(); i++) {
555                 buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
556                 if (i + 1 < list.size()) {
557                     buffer.append(", \\ ");
558                 }
559             }
560             buffer.append(" \\} ");
561             return buffer.toString();
562         }
563     }
564 
565 //    /**
566 //     * Transformer for a quantifier intersection.
567 //     */
568 //    class QuantorIntersection implements ListType {
569 //        public String getLatex(final ElementList list, final boolean first) {
570 //            final StringBuffer buffer = new StringBuffer();
571 //            final String prefix = "\\bigcap";
572 //            buffer.append(prefix);
573 //            if (0 < list.size()) {
574 //                buffer.append("{").append(Element2LatexImpl.this.getLatex(list.getElement(0), false))
575 //                .append("}");
576 //            }
577 //            for (int i = 1; i < list.size(); i++) {
578 //                buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
579 //                if (i + 1 < list.size()) {
580 //                    buffer.append(" \\ \\ ");
581 //                }
582 //            }
583 //            buffer.append(" \\} ");
584 //            return buffer.toString();
585 //        }
586 //    }
587 //
588 //    /**
589 //     * LATER mime 20080126: needed?
590 //     */
591 //    class QuantorUnion implements ListType {
592 //        public String getLatex(final ElementList list, final boolean first) {
593 //            final StringBuffer buffer = new StringBuffer();
594 //            final String prefix = "\\bigcup";
595 //            buffer.append(prefix);
596 //            if (0 < list.size()) {
597 //                buffer.append("{").append(Element2LatexImpl.this.getLatex(list.getElement(0), false))
598 //                .append("}");
599 //            }
600 //            for (int i = 1; i < list.size(); i++) {
601 //                buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
602 //                if (i + 1 < list.size()) {
603 //                    buffer.append(" \\ \\ ");
604 //                }
605 //            }
606 //            buffer.append(" \\} ");
607 //            return buffer.toString();
608 //        }
609 //    }
610 //
611     /**
612      * If we don't now what kind of type we have we do this.
613      */
614     class Unknown implements ListType {
615         public String getLatex(final ElementList list, final boolean first) {
616             final StringBuffer buffer = new StringBuffer();
617             buffer.append(list.getOperator());
618             buffer.append("(");
619             for (int i = 0; i < list.size(); i++) {
620                 buffer.append(Element2LatexImpl.this.getLatex(list.getElement(i), false));
621                 if (i + 1 < list.size()) {
622                     buffer.append(", ");
623                 }
624             }
625             buffer.append(")");
626             return buffer.toString();
627         }
628     }
629 
630 
631 }