/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ package org.geogebra.common.kernel.prover; import org.geogebra.common.factories.UtilFactory; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.cas.UsesCAS; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.geos.GeoBoolean; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.main.ProverSettings; import org.geogebra.common.util.Prover; import org.geogebra.common.util.Prover.ProofResult; import org.geogebra.common.util.Prover.ProverEngine; import org.geogebra.common.util.debug.Log; /** * Algo for the Prove command. * * @author Zoltan Kovacs <zoltan@geogebra.org> */ public class AlgoProve extends AlgoElement implements UsesCAS { private GeoElement root; // input private GeoBoolean bool; // output private String inputFingerprint; /** * Proves the given statement and gives a yes/no answer (boolean) * * @param cons * The construction * @param label * Label for the output * @param root * Input statement */ public AlgoProve(Construction cons, String label, GeoElement root) { super(cons); cons.addCASAlgo(this); this.root = root; bool = new GeoBoolean(cons); setInputOutput(); // for AlgoElement // compute value of dependent number initialCompute(); compute(); bool.setLabel(label); } @Override public Commands getClassName() { return Commands.Prove; } // for AlgoElement @Override protected void setInputOutput() { input = new GeoElement[1]; input[0] = root; super.setOutputLength(1); super.setOutput(0, bool); setDependencies(); // done by AlgoElement inputFingerprint = fingerprint(root); } /** * Returns the output for the Prove command * * @return A boolean: true/false */ public GeoBoolean getGeoBoolean() { return bool; } /** * Heavy computation of the proof. */ public final void initialCompute() { ProverSettings proverSettings = ProverSettings.get(); // Create and initialize the prover Prover p = UtilFactory.getPrototype().newProver(); if ("OpenGeoProver".equalsIgnoreCase(proverSettings.proverEngine)) { if ("Wu".equalsIgnoreCase(proverSettings.proverMethod)) { p.setProverEngine(ProverEngine.OPENGEOPROVER_WU); } else if ("Area".equalsIgnoreCase(proverSettings.proverMethod)) { p.setProverEngine(ProverEngine.OPENGEOPROVER_AREA); } } else if ("Botana".equalsIgnoreCase(proverSettings.proverEngine)) { p.setProverEngine(ProverEngine.BOTANAS_PROVER); } else if ("Recio".equalsIgnoreCase(proverSettings.proverEngine)) { p.setProverEngine(ProverEngine.RECIOS_PROVER); } else if ("PureSymbolic".equalsIgnoreCase(proverSettings.proverEngine)) { p.setProverEngine(ProverEngine.PURE_SYMBOLIC_PROVER); } else if ("Auto".equalsIgnoreCase(proverSettings.proverEngine)) { p.setProverEngine(ProverEngine.AUTO); } p.setTimeout(proverSettings.proverTimeout); p.setConstruction(cons); p.setStatement(root); // Don't compute extra NDG's: p.setReturnExtraNDGs(false); // Adding benchmarking: double startTime = cons.getApplication().getMillisecondTime(); p.compute(); // the computation of the proof int elapsedTime = (int) (cons.getApplication().getMillisecondTime() - startTime); /* * Don't remove this. It is needed for automated testing. (String match * is assumed.) */ Log.debug("Benchmarking: " + elapsedTime + " ms"); ProofResult result = p.getProofResult(); Log.debug("STATEMENT IS " + result); if (result != null) { if (result == ProofResult.UNKNOWN || result == ProofResult.PROCESSING) { bool.setUndefinedProverOnly(); return; } bool.setDefined(); if (result == ProofResult.TRUE || result == ProofResult.TRUE_COMPONENT) { bool.setValue(true); } if (result == ProofResult.FALSE) { bool.setValue(false); } } /* * Don't remove this. It is needed for testing the web platform. (String * match is assumed.) */ Log.debug("OUTPUT for Prove: " + bool); } @Override // Not sure how to do this hack normally. final public String getDefinitionName(StringTemplate tpl) { return "Prove"; } @Override public void compute() { if (!kernel.getGeoGebraCAS().getCurrentCAS().isLoaded()) { inputFingerprint = null; return; } String inputFingerprintPrev = inputFingerprint; setInputOutput(); /* * Not really sure if this is needed, but it cleans up the list of algos * and constructions: */ do { cons.removeFromAlgorithmList(this); } while (cons.getAlgoList().contains(this)); // Adding this again: cons.addToAlgorithmList(this); cons.removeFromConstructionList(this); // Adding this again: cons.addToConstructionList(this, true); // TODO: consider moving setInputOutput() out from compute() if (inputFingerprintPrev == null || !inputFingerprintPrev.equals(inputFingerprint)) { Log.trace(inputFingerprintPrev + " -> " + inputFingerprint); initialCompute(); } } /* * We use a very hacky way to avoid recomputing proof when the input is not * changed. To achieve that, we create a fingerprint of the current input. * The fingerprint function should eventually be improved. Here we assume * that the input objects are always in the same order (that seems sensible) * and the obtained algebraic description changes iff the object does. This * may not be the case if rounding/precision is not as presumed. */ private static String fingerprint(GeoElement statement) { return Prover.getTextFormat(statement); } }