001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002 *
003 * Copyright 2000-2014, Michael Meyling <mime@qedeq.org>.
004 *
005 * "Hilbert II" is free software; you can redistribute
006 * it and/or modify it under the terms of the GNU General Public
007 * License as published by the Free Software Foundation; either
008 * version 2 of the License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU General Public License for more details.
014 */
015
016 package org.qedeq.kernel.bo.service.internal;
017
018 import java.util.HashMap;
019 import java.util.Map;
020
021 import org.qedeq.base.utility.StringUtility;
022 import org.qedeq.kernel.bo.common.Element2Latex;
023 import org.qedeq.kernel.bo.logic.common.ExistenceChecker;
024 import org.qedeq.kernel.bo.module.KernelQedeqBo;
025 import org.qedeq.kernel.bo.module.ModuleLabels;
026 import org.qedeq.kernel.se.base.list.Element;
027 import org.qedeq.kernel.se.base.list.ElementList;
028 import org.qedeq.kernel.se.base.module.FunctionDefinition;
029 import org.qedeq.kernel.se.base.module.PredicateDefinition;
030 import org.qedeq.kernel.se.dto.module.FunctionDefinitionVo;
031 import org.qedeq.kernel.se.dto.module.PredicateDefinitionVo;
032
033
034 /**
035 * Transfer a QEDEQ formulas into LaTeX text.
036 *
037 * @author Michael Meyling
038 */
039 public final class Element2LatexImpl implements Element2Latex {
040
041 /** Knows about labels, definitions and external QEDEQ module references. */
042 private ModuleLabels labels;
043
044 /** Maps operator strings to {@link ElementList} to LaTeX mappers. */
045 private final Map elementList2ListType = new HashMap();
046
047 /** For mapping an unknown operator. */
048 private final ListType unknown = new Unknown();
049
050 /** Maps predicate identifiers to {@link PredicateDefinition}s. Contains default definitions
051 * as a fallback.*/
052 private final Map backupPredicateDefinitions = new HashMap();
053
054 /** Maps function identifiers to {@link FunctionDefinition}s. Contains default definitions. */
055 private final Map backupFunctionDefinitions = new HashMap();
056
057 /**
058 * Constructor.
059 *
060 * @param labels Knows about labels, definitions and external QEDEQ module references.
061 */
062 public Element2LatexImpl(final ModuleLabels labels) {
063 this.labels = labels;
064
065 this.elementList2ListType.put("PREDVAR", new Predvar());
066 this.elementList2ListType.put("FUNVAR", new Funvar());
067 this.elementList2ListType.put("PREDCON", new Predcon());
068 this.elementList2ListType.put("FUNCON", new Funcon());
069 this.elementList2ListType.put("VAR", new Var());
070
071 this.elementList2ListType.put("AND", new BinaryLogical("\\land"));
072 this.elementList2ListType.put("OR", new BinaryLogical("\\lor"));
073 this.elementList2ListType.put("IMPL", new BinaryLogical("\\rightarrow"));
074 this.elementList2ListType.put("EQUI", new BinaryLogical("\\leftrightarrow"));
075
076 this.elementList2ListType.put("FORALL", new Quantifier("\\forall"));
077 this.elementList2ListType.put("EXISTS", new Quantifier("\\exists"));
078 this.elementList2ListType.put("EXISTSU", new Quantifier("\\exists!"));
079
080 this.elementList2ListType.put("NOT", new Not());
081 this.elementList2ListType.put("CLASS", new Class());
082 this.elementList2ListType.put("CLASSLIST", new Classlist());
083
084 // // TODO mime 20080126: wrong spelled and not used any longer (?)
085 // this.elementList2ListType.put("QUANTOR_INTERSECTION", new QuantorIntersection());
086 // this.elementList2ListType.put("QUANTOR_UNION", new QuantorUnion());
087
088 fillBackup();
089
090 }
091
092 /**
093 * Fill backup predicate list (if required modules could not be loaded, or the predicate is
094 * not yet defined.
095 */
096 private void fillBackup() {
097 // logical identity operator
098 addBackupPredicate(ExistenceChecker.NAME_EQUAL, "2", "#1 \\ = \\ #2");
099
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 }
|