DynamicHeuristicCheckerExecutor.java
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.heuristic;
017 
018 import org.qedeq.base.io.Parameters;
019 import org.qedeq.base.trace.Trace;
020 import org.qedeq.kernel.bo.log.QedeqLog;
021 import org.qedeq.kernel.bo.logic.common.Operators;
022 import org.qedeq.kernel.bo.logic.model.DynamicDirectInterpreter;
023 import org.qedeq.kernel.bo.logic.model.DynamicModel;
024 import org.qedeq.kernel.bo.logic.model.FourDynamicModel;
025 import org.qedeq.kernel.bo.logic.model.HeuristicErrorCodes;
026 import org.qedeq.kernel.bo.logic.model.HeuristicException;
027 import org.qedeq.kernel.bo.logic.model.ModelFunctionConstant;
028 import org.qedeq.kernel.bo.logic.model.ModelPredicateConstant;
029 import org.qedeq.kernel.bo.module.InternalModuleServiceCall;
030 import org.qedeq.kernel.bo.module.KernelQedeqBo;
031 import org.qedeq.kernel.bo.service.basis.ControlVisitor;
032 import org.qedeq.kernel.bo.service.basis.ModuleServicePlugin;
033 import org.qedeq.kernel.bo.service.basis.ModuleServicePluginExecutor;
034 import org.qedeq.kernel.se.base.list.Element;
035 import org.qedeq.kernel.se.base.module.Axiom;
036 import org.qedeq.kernel.se.base.module.ConditionalProof;
037 import org.qedeq.kernel.se.base.module.FormalProofLine;
038 import org.qedeq.kernel.se.base.module.FunctionDefinition;
039 import org.qedeq.kernel.se.base.module.InitialFunctionDefinition;
040 import org.qedeq.kernel.se.base.module.InitialPredicateDefinition;
041 import org.qedeq.kernel.se.base.module.Node;
042 import org.qedeq.kernel.se.base.module.PredicateDefinition;
043 import org.qedeq.kernel.se.base.module.Proposition;
044 import org.qedeq.kernel.se.base.module.Rule;
045 import org.qedeq.kernel.se.common.ModuleContext;
046 import org.qedeq.kernel.se.common.ModuleDataException;
047 import org.qedeq.kernel.se.common.ModuleService;
048 import org.qedeq.kernel.se.common.SourceFileExceptionList;
049 import org.qedeq.kernel.se.dto.list.DefaultElementList;
050 
051 
052 /**
053  * Check if formulas are valid in our model.
054  *
055  @author  Michael Meyling
056  */
057 public final class DynamicHeuristicCheckerExecutor extends ControlVisitor implements ModuleServicePluginExecutor {
058 
059     /** This class. */
060     private static final Class CLASS = DynamicHeuristicCheckerExecutor.class;
061 
062     /** Interpretation for variables. */
063     private final DynamicDirectInterpreter interpreter;
064 
065     /** Current condition. */
066     private DefaultElementList condition;
067 
068     /**
069      * Constructor.
070      *
071      @param   plugin      This plugin we work for.
072      @param   qedeq       QEDEQ module object.
073      @param   parameters  Execution parameters.
074      */
075     DynamicHeuristicCheckerExecutor(final ModuleServicePlugin plugin, final KernelQedeqBo qedeq,
076             final Parameters parameters) {
077         super(plugin, qedeq);
078         final String method = "DynamicHeuristicChecker(PluginBo, QedeqBo, Map)";
079         final String modelClass = parameters.getString("model");
080         DynamicModel model = null;
081         if (modelClass != null && modelClass.length() 0) {
082             try {
083                 Class cl = Class.forName(modelClass);
084                 model = (DynamicModelcl.newInstance();
085             catch (ClassNotFoundException e) {
086                 Trace.fatal(CLASS, this, method, "Model class not in class path: "
087                     + modelClass, e);
088             catch (InstantiationException e) {
089                 Trace.fatal(CLASS, this, method, "Model class could not be instanciated: "
090                     + modelClass, e);
091             catch (IllegalAccessException e) {
092                 Trace.fatal(CLASS, this, method,
093                     "Programming error, access for instantiation failed for model: "
094                     + modelClass, e);
095             catch (RuntimeException e) {
096                 Trace.fatal(CLASS, this, method,
097                     "Programming error, instantiation failed for model: " + modelClass, e);
098             }
099         }
100         // fallback is the default model
101         if (model == null) {
102             model = new FourDynamicModel();
103         }
104         this.interpreter = new DynamicDirectInterpreter(qedeq, model);
105     }
106 
107     private ModuleService getPlugin() {
108         return (ModuleServicegetService();
109     }
110 
111     public Object executePlugin(final InternalModuleServiceCall call, final Object data) {
112         final String method = "executePlugin()";
113         try {
114             QedeqLog.getInstance().logRequest("Dynamic heuristic test", getKernelQedeqBo().getUrl());
115             // first we try to get more information about required modules and their predicates..
116             try {
117                 getServices().checkWellFormedness(call.getInternalServiceProcess(), getKernelQedeqBo());
118             catch (Exception e) {
119                 // we continue and ignore external predicates
120                 Trace.trace(CLASS, method, e);
121             }
122             condition = new DefaultElementList(Operators.CONJUNCTION_OPERATOR);
123             traverse(call.getInternalServiceProcess());
124             QedeqLog.getInstance().logSuccessfulReply(
125                 "Heuristic test succesfull", getKernelQedeqBo().getUrl());
126         catch (final SourceFileExceptionList e) {
127             final String msg = "Test failed";
128             Trace.fatal(CLASS, this, method, msg, e);
129             QedeqLog.getInstance().logFailureReply(msg, getKernelQedeqBo().getUrl(), e.getMessage());
130         catch (final RuntimeException e) {
131             Trace.fatal(CLASS, this, method, "unexpected problem", e);
132             QedeqLog.getInstance().logFailureReply(
133                 "Test failed", getKernelQedeqBo().getUrl()"unexpected problem: "
134                 (e.getMessage() != null ? e.getMessage() : e.toString()));
135         finally {
136             getKernelQedeqBo().addPluginErrorsAndWarnings(getPlugin(), getErrorList(), getWarningList());
137         }
138         return null;
139     }
140 
141     /**
142      * Check truth value in our model. If it is no tautology an warning is added.
143      * This also happens if our model doesn't support an operator found in the formula.
144      *
145      @param   test            Test formula.
146      */
147     private void test(final Element test) {
148         boolean useCondition = condition.size() 0//Assume that we start with an implication,
149                             // but the real context begins after skipping ".getList().getElement(1)"
150         try {
151             Element toast = test;
152             if (condition.size() 0) {
153                 final DefaultElementList withCondition = new DefaultElementList(Operators.IMPLICATION_OPERATOR);
154                 withCondition.add(condition);
155                 withCondition.add(test);
156                 toast = withCondition;
157             }
158             if (!isTautology(getCurrentContext(), toast)) {
159                 addWarning(new HeuristicException(HeuristicErrorCodes.EVALUATED_NOT_TRUE_CODE,
160                     HeuristicErrorCodes.EVALUATED_NOT_TRUE_TEXT + " (\""
161                         + interpreter.getModel().getName() "\")", getCurrentContext()));
162             }
163         catch (HeuristicException h) {
164             // TODO 20101015 m31: better exception handling would be better!
165             final String begin = getCurrentContext().getLocationWithinModule();
166             // is the error context at the same location? if not we have a problem with a referenced
167             // predicate or function constant and we take the currrent context instead
168             if (!getCurrentContext().getModuleLocation().equals(h.getContext().getModuleLocation())
169                     || !h.getContext().getLocationWithinModule().startsWith(begin)) {
170                 addWarning(new HeuristicException(h.getErrorCode(), h.getMessage(),
171                         getCurrentContext()));
172             else {
173                 String further = h.getContext().getLocationWithinModule().substring(begin.length());
174                 if (useCondition) {
175                     if (further.startsWith(".getList().getElement(1)")) {
176                         further = further.substring(".getList().getElement(1)".length());
177                         addWarning(new HeuristicException(h.getErrorCode(), h.getMessage(),
178                             new ModuleContext(h.getContext().getModuleLocation(), begin + further)));
179                     else {    // must be an error in the condition and for that we have no context
180                         addWarning(new HeuristicException(h.getErrorCode(), h.getMessage(),
181                                 getCurrentContext()));
182                     }
183                 else {
184                     addWarning(h);
185                 }
186             }
187         catch (RuntimeException e) {
188             Trace.fatal(CLASS, this, "test(Element)""unexpected runtime exception", e);
189             if (e.getCause() != null && e.getCause() instanceof HeuristicException) {
190                 // TODO 20101015 m31: better exception handling would be better!
191                 HeuristicException h = (HeuristicExceptione.getCause();
192                 addWarning(new HeuristicException(h.getErrorCode(), h.getMessage(),
193                     getCurrentContext()));
194             else {
195                 addWarning(new HeuristicException(HeuristicErrorCodes.RUNTIME_EXCEPTION_CODE,
196                     HeuristicErrorCodes.RUNTIME_EXCEPTION_TEXT + e, getCurrentContext()));
197             }
198         }
199     }
200 
201     /**
202      * Test if given formula is a tautology. This is done by checking a model and
203      * iterating through variable values.
204      *
205      @param   moduleContext   Here we are within a module.
206      @param   formula         Formula.
207      @return  Is this formula a tautology according to our tests.
208      @throws  HeuristicException  Evaluation failed.
209      */
210     private boolean isTautology(final ModuleContext moduleContext, final Element formula)
211             throws HeuristicException {
212         boolean result = true;
213         ModuleContext context = moduleContext;
214         try {
215             do {
216                 result &= interpreter.calculateValue(new ModuleContext(context), formula);
217     //            System.out.println(interpreter.toString());
218             while (result && interpreter.next());
219 //        if (!result) {
220 //            System.out.println(interpreter);
221 //        }
222 //        System.out.println("interpretation finished - and result is = " + result);
223         finally {
224             interpreter.clearVariables();
225         }
226         return result;
227     }
228 
229 
230     public void visitEnter(final Axiom axiomthrows ModuleDataException {
231         if (axiom == null) {
232             return;
233         }
234         final String context = getCurrentContext().getLocationWithinModule();
235         QedeqLog.getInstance().logMessageState("\ttesting axiom", getKernelQedeqBo().getUrl());
236         if (axiom.getFormula() != null) {
237             setLocationWithinModule(context + ".getFormula().getElement()");
238             final Element test = axiom.getFormula().getElement();
239             test(test);
240         }
241         setLocationWithinModule(context);
242         setBlocked(true);
243     }
244 
245     public void visitLeave(final Axiom axiom) {
246         setBlocked(false);
247     }
248 
249     public void visitEnter(final InitialPredicateDefinition definition)
250             throws ModuleDataException {
251         final String method = "visitEnter(InitialPredicateDefinition)";
252         if (definition == null) {
253             return;
254         }
255         QedeqLog.getInstance().logMessageState("\ttesting initial predicate definition",
256             getKernelQedeqBo().getUrl());
257         final String context = getCurrentContext().getLocationWithinModule();
258         try {
259             ModelPredicateConstant predicate = new ModelPredicateConstant(
260                     definition.getName(), Integer.parseInt(definition
261                             .getArgumentNumber()));
262             // check if model contains predicate
263             if (!interpreter.hasPredicateConstant(predicate)) {
264                 setLocationWithinModule(context + ".getName()");
265                 addWarning(new HeuristicException(
266                         HeuristicErrorCodes.UNKNOWN_PREDICATE_CONSTANT_CODE,
267                         HeuristicErrorCodes.UNKNOWN_PREDICATE_CONSTANT_TEXT
268                                 + predicate, getCurrentContext()));
269             }
270         catch (NumberFormatException e) {
271             Trace.fatal(CLASS, this, method, "not suported argument number: "
272                     + definition.getArgumentNumber(), e);
273             setLocationWithinModule(context + ".getArgumentNumber()");
274             addWarning(new HeuristicException(
275                     HeuristicErrorCodes.UNKNOWN_ARGUMENT_FORMAT_CODE,
276                     HeuristicErrorCodes.UNKNOWN_ARGUMENT_FORMAT_TEXT
277                             + definition.getArgumentNumber(),
278                     getCurrentContext()));
279         }
280         setLocationWithinModule(context);
281         setBlocked(true);
282     }
283 
284     public void visitLeave(final InitialPredicateDefinition definition) {
285         setBlocked(false);
286     }
287 
288     public void visitEnter(final PredicateDefinition definition)
289             throws ModuleDataException {
290         final String method = "visitEnter(PredicateDefinition)";
291         if (definition == null) {
292             return;
293         }
294         QedeqLog.getInstance().logMessageState("\ttesting predicate definition",
295             getKernelQedeqBo().getUrl());
296         final String context = getCurrentContext().getLocationWithinModule();
297         try {
298             // test new predicate constant: must always be successful otherwise there
299             // must be a programming error or the predicate definition is not formal correct
300             setLocationWithinModule(context + ".getFormula().getElement()");
301             test(definition.getFormula().getElement());
302         catch (NumberFormatException e) {
303             Trace.fatal(CLASS, this, method, "not suported argument number: "
304                 + definition.getArgumentNumber(), e);
305             setLocationWithinModule(context + ".getArgumentNumber()");
306             addWarning(new HeuristicException(HeuristicErrorCodes.UNKNOWN_ARGUMENT_FORMAT_CODE,
307                 HeuristicErrorCodes.UNKNOWN_ARGUMENT_FORMAT_TEXT + definition.getArgumentNumber(),
308                 getCurrentContext()));
309         }
310         setLocationWithinModule(context);
311         setBlocked(true);
312     }
313 
314     public void visitLeave(final PredicateDefinition definition) {
315         setBlocked(false);
316     }
317 
318     public void visitEnter(final InitialFunctionDefinition definition)
319             throws ModuleDataException {
320         final String method = "visitEnter(InitialFunctionDefinition)";
321         if (definition == null) {
322             return;
323         }
324         QedeqLog.getInstance().logMessageState("\ttesting initial function definition",
325             getKernelQedeqBo().getUrl());
326         final String context = getCurrentContext().getLocationWithinModule();
327         try {
328             ModelFunctionConstant function = new ModelFunctionConstant(definition.getName(),
329                     Integer.parseInt(definition.getArgumentNumber()));
330             if (!interpreter.hasFunctionConstant(function)) {
331                 // check if model contains predicate
332                 setLocationWithinModule(context + ".getName()");
333                 addWarning(new HeuristicException(
334                         HeuristicErrorCodes.UNKNOWN_FUNCTION_CONSTANT_CODE,
335                         HeuristicErrorCodes.UNKNOWN_FUNCTION_CONSTANT_TEXT
336                                 + function, getCurrentContext()));
337             }
338         catch (NumberFormatException e) {
339             Trace.fatal(CLASS, this, method, "not suported argument number: "
340                     + definition.getArgumentNumber(), e);
341             setLocationWithinModule(context + ".getArgumentNumber()");
342             addWarning(new HeuristicException(
343                     HeuristicErrorCodes.UNKNOWN_ARGUMENT_FORMAT_CODE,
344                     HeuristicErrorCodes.UNKNOWN_ARGUMENT_FORMAT_TEXT
345                             + definition.getArgumentNumber(),
346                     getCurrentContext()));
347         }
348         setLocationWithinModule(context);
349         setBlocked(true);
350     }
351 
352     public void visitLeave(final InitialFunctionDefinition definition) {
353         setBlocked(false);
354     }
355 
356     public void visitEnter(final FunctionDefinition definition)
357             throws ModuleDataException {
358         if (definition == null) {
359             return;
360         }
361         QedeqLog.getInstance().logMessageState("\ttesting function definition",
362             getKernelQedeqBo().getUrl());
363         final String context = getCurrentContext().getLocationWithinModule();
364         // test new predicate constant: must always be successful otherwise there
365         // must be a programming error or the predicate definition is not formal correct
366         setLocationWithinModule(context + ".getFormula().getElement()");
367         test(definition.getFormula().getElement());
368         setLocationWithinModule(context);
369         setBlocked(true);
370     }
371 
372     public void visitLeave(final FunctionDefinition definition) {
373         setBlocked(false);
374     }
375 
376     public void visitEnter(final Node node) {
377         QedeqLog.getInstance().logMessageState(super.getLocationDescription(),
378             getKernelQedeqBo().getUrl());
379     }
380 
381     public void visitEnter(final Proposition proposition)
382             throws ModuleDataException {
383         if (proposition == null) {
384             return;
385         }
386         QedeqLog.getInstance().logMessageState("\ttesting proposition", getKernelQedeqBo().getUrl());
387         final String context = getCurrentContext().getLocationWithinModule();
388         if (proposition.getFormula() != null) {
389             setLocationWithinModule(context + ".getFormula().getElement()");
390             final Element test = proposition.getFormula().getElement();
391             test(test);
392         }
393         setLocationWithinModule(context);
394     }
395 
396     public void visitLeave(final Proposition definition) {
397         // nothing to do
398     }
399 
400     public void visitEnter(final FormalProofLine line)
401             throws ModuleDataException {
402         if (line == null) {
403             return;
404         }
405         QedeqLog.getInstance().logMessageState("\t\ttesting line " + line.getLabel(),
406             getKernelQedeqBo().getUrl());
407         final String context = getCurrentContext().getLocationWithinModule();
408         if (line.getFormula() != null) {
409             setLocationWithinModule(context + ".getFormula().getElement()");
410             test(line.getFormula().getElement());
411         }
412         setLocationWithinModule(context);
413         setBlocked(true);
414     }
415 
416     public void visitLeave(final FormalProofLine line) {
417         setBlocked(false);
418     }
419 
420     public void visitEnter(final ConditionalProof line)
421             throws ModuleDataException {
422         if (line == null) {
423             return;
424         }
425         // add hypothesis to list of conditions
426         if (line.getHypothesis() != null && line.getHypothesis().getFormula() != null
427                 && line.getHypothesis().getFormula().getElement() != null) {
428             condition.add(line.getHypothesis().getFormula().getElement());
429             QedeqLog.getInstance().logMessageState("\t\tadd condit. "
430                 + line.getHypothesis().getLabel(), getKernelQedeqBo().getUrl());
431         }
432     }
433 
434     public void visitLeave(final ConditionalProof line) {
435         if (line == null) {
436             return;
437         }
438         // remove hypothesis of list of conditions
439         if (line.getHypothesis() != null && line.getHypothesis().getFormula() != null
440                 && line.getHypothesis().getFormula().getElement() != null) {
441             condition.remove(condition.size() 1);
442         }
443         QedeqLog.getInstance().logMessageState("\t\ttesting line "
444             + line.getConclusion().getLabel(), getKernelQedeqBo().getUrl());
445         final String context = getCurrentContext().getLocationWithinModule();
446         if (line.getConclusion().getFormula() != null) {
447             setLocationWithinModule(context + ".getConclusion().getFormula().getElement()");
448             final Element test = line.getConclusion().getFormula().getElement();
449             test(test);
450         }
451     }
452 
453     public void visitEnter(final Rule rulethrows ModuleDataException {
454         setBlocked(true);
455     }
456 
457     public void visitLeave(final Rule rule) {
458         setBlocked(false);
459     }
460 
461     public String getLocationDescription() {
462         return super.getLocationDescription() "\n" + interpreter.toString();
463     }
464 
465 }