package org.geogebra.common.kernel.prover; import org.geogebra.common.cas.GeoGebraCAS; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.algos.AlgoAnglePoints; import org.geogebra.common.kernel.algos.AlgoDependentNumber; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.algos.SymbolicParametersBotanaAlgo; import org.geogebra.common.kernel.algos.SymbolicParametersBotanaAlgoAre; import org.geogebra.common.kernel.arithmetic.ExpressionNode; import org.geogebra.common.kernel.arithmetic.ValidExpression; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.geos.GeoAngle; import org.geogebra.common.kernel.geos.GeoBoolean; import org.geogebra.common.kernel.geos.GeoConic; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoLine; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.kernel.geos.GeoSegment; import org.geogebra.common.kernel.prover.polynomial.PPolynomial; import org.geogebra.common.kernel.prover.polynomial.PVariable; /** * Decides if the objects are equal. Can be embedded into the Prove command to * work symbolically. * * @author Simon Weitzhofer 17 May 2012 * @author Zoltan Kovacs <zoltan@geogebra.org> */ public class AlgoAreEqual extends AlgoElement implements SymbolicParametersBotanaAlgoAre { private GeoElement inputElement1; // input private GeoElement inputElement2; // input private GeoBoolean outputBoolean; // output private PPolynomial[][] botanaPolynomials; /** * Tests if two objects are equal * * @param cons * The construction the objects depend on * @param inputElement1 * the first object * @param inputElement2 * the second object */ public AlgoAreEqual(Construction cons, GeoElement inputElement1, GeoElement inputElement2) { super(cons); this.inputElement1 = inputElement1; this.inputElement2 = inputElement2; outputBoolean = new GeoBoolean(cons); setInputOutput(); compute(); } /** * Tests if two objects are equal * * @param cons * The construction the objects depend on * @param label * the label for the AlgoAreEqual object * @param inputElement1 * the first object * @param inputElement2 * the second object */ public AlgoAreEqual(Construction cons, String label, GeoElement inputElement1, GeoElement inputElement2) { this(cons, inputElement1, inputElement2); outputBoolean.setLabel(label); } @Override public Commands getClassName() { return Commands.AreEqual; } @Override protected void setInputOutput() { input = new GeoElement[2]; input[0] = inputElement1; input[1] = inputElement2; super.setOutputLength(1); super.setOutput(0, outputBoolean); setDependencies(); // done by AlgoElement } /** * Gets the result of the test * * @return true if the objects are equal and false otherwise */ public GeoBoolean getResult() { return outputBoolean; } @Override public final void compute() { // Formerly we used this: // outputBoolean.setValue(ExpressionNodeEvaluator.evalEquals(kernel, // inputElement1, inputElement2).getBoolean()); // But this way is more useful eg for segments, polygons // ie compares endpoints NOT just length // #5331 // The formerly used computation is now implemented in AlgoAreCongruent. outputBoolean.setValue(inputElement1.isEqual(inputElement2)); } @Override public PPolynomial[][] getBotanaPolynomials() throws NoSymbolicParametersException { if (botanaPolynomials != null) { return botanaPolynomials; } if (inputElement1 instanceof GeoPoint && inputElement2 instanceof GeoPoint) { botanaPolynomials = new PPolynomial[2][1]; PVariable[] v1 = new PVariable[2]; PVariable[] v2 = new PVariable[2]; v1 = ((GeoPoint) inputElement1).getBotanaVars(inputElement1); // A=(x1,y1) v2 = ((GeoPoint) inputElement2).getBotanaVars(inputElement2); // B=(x2,y2) // We want to prove: 1) x1-x2==0, 2) y1-y2==0 botanaPolynomials[0][0] = new PPolynomial(v1[0]) .subtract(new PPolynomial(v2[0])); botanaPolynomials[1][0] = new PPolynomial(v1[1]) .subtract(new PPolynomial(v2[1])); return botanaPolynomials; } if (inputElement1 instanceof GeoSegment && inputElement2 instanceof GeoSegment) { // currently unimplemented throw new NoSymbolicParametersException(); } if (inputElement1 instanceof GeoLine && inputElement2 instanceof GeoLine) { botanaPolynomials = new PPolynomial[2][1]; PVariable[] v1 = new PVariable[4]; PVariable[] v2 = new PVariable[4]; v1 = ((GeoLine) inputElement1).getBotanaVars(inputElement1); // AB v2 = ((GeoLine) inputElement2).getBotanaVars(inputElement2); // CD // We want to prove: 1) ABC collinear, 2) ABD collinear botanaPolynomials[0][0] = PPolynomial.collinear(v1[0], v1[1], v1[2], v1[3], v2[0], v2[1]); botanaPolynomials[1][0] = PPolynomial.collinear(v1[0], v1[1], v1[2], v1[3], v2[2], v2[3]); return botanaPolynomials; } if (inputElement1 instanceof GeoConic && inputElement2 instanceof GeoConic) { if (((GeoConic) inputElement1).isCircle() && ((GeoConic) inputElement2).isCircle()) { botanaPolynomials = new PPolynomial[2][1]; PVariable[] v1 = new PVariable[4]; PVariable[] v2 = new PVariable[4]; // circle with center A and point B v1 = ((GeoConic) inputElement1).getBotanaVars(inputElement1); // circle with center C and point D v2 = ((GeoConic) inputElement2).getBotanaVars(inputElement2); // We want to prove: 1) |AC|^2 = 0, 2) |AB|^2 = |CD|^2 botanaPolynomials[0][0] = PPolynomial.sqrDistance(v1[0], v1[1], v2[0], v2[1]); botanaPolynomials[1][0] = PPolynomial .sqrDistance(v1[0], v1[1], v1[2], v1[3]) .subtract(PPolynomial.sqrDistance(v2[0], v2[1], v2[2], v2[3])); return botanaPolynomials; } if (((GeoConic) inputElement1).isParabola() && ((GeoConic) inputElement2).isParabola()) { botanaPolynomials = new PPolynomial[4][1]; PVariable[] v1 = new PVariable[10]; PVariable[] v2 = new PVariable[10]; v1 = ((GeoConic) inputElement1).getBotanaVars(inputElement1); v2 = ((GeoConic) inputElement2).getBotanaVars(inputElement2); // We want to prove: 1) A, B, A' coll. 2) A, B, B' coll. 3) F=F' // f1 = f'1 botanaPolynomials[0][0] = new PPolynomial(v1[8]) .subtract(new PPolynomial(v2[8])); // f2 = f'2 botanaPolynomials[1][0] = new PPolynomial(v1[9]) .subtract(new PPolynomial(v2[9])); // A, B, A' botanaPolynomials[2][0] = PPolynomial.collinear(v1[4], v1[5], v1[6], v1[7], v2[4], v2[5]); // A, B, B' botanaPolynomials[3][0] = PPolynomial.collinear(v1[4], v1[5], v1[6], v1[7], v2[6], v2[7]); return botanaPolynomials; } } if (inputElement1 instanceof GeoAngle && inputElement2 instanceof GeoAngle) { AlgoAnglePoints algo1 = (AlgoAnglePoints) inputElement1 .getParentAlgorithm(); // get points of first angle GeoPoint A = (GeoPoint) algo1.input[0]; GeoPoint B = (GeoPoint) algo1.input[1]; GeoPoint C = (GeoPoint) algo1.input[2]; PVariable[] vA = A.getBotanaVars(A); PVariable[] vB = B.getBotanaVars(B); PVariable[] vC = C.getBotanaVars(C); AlgoAnglePoints algo2 = (AlgoAnglePoints) inputElement2 .getParentAlgorithm(); // get points of second angle GeoPoint D = (GeoPoint) algo2.input[0]; GeoPoint E = (GeoPoint) algo2.input[1]; GeoPoint F = (GeoPoint) algo2.input[2]; PVariable[] vD = D.getBotanaVars(D); PVariable[] vE = E.getBotanaVars(E); PVariable[] vF = F.getBotanaVars(F); botanaPolynomials = new PPolynomial[3][1]; // We want to prove: 1) A = D 2) B = E 3) C = F botanaPolynomials[0][0] = PPolynomial.sqrDistance(vA[0], vA[1], vD[0], vD[0]); botanaPolynomials[1][0] = PPolynomial.sqrDistance(vB[0], vB[1], vE[0], vE[1]); botanaPolynomials[2][0] = PPolynomial.sqrDistance(vC[0], vC[1], vF[0], vF[1]); return botanaPolynomials; } // distance between 2 point without segment if (inputElement1 instanceof GeoNumeric && inputElement2 instanceof GeoNumeric && (inputElement1.getParentAlgorithm()) .getRelatedModeID() == EuclidianConstants.MODE_DISTANCE && (inputElement2.getParentAlgorithm()) .getRelatedModeID() == EuclidianConstants.MODE_DISTANCE) { // We check whether their length are equal. botanaPolynomials = new PPolynomial[1][1]; PVariable[] v1 = new PVariable[4]; PVariable[] v2 = new PVariable[4]; // get coordinates of the start and end points v1 = ((SymbolicParametersBotanaAlgo) inputElement1 .getParentAlgorithm()).getBotanaVars(inputElement1); // AB v2 = ((SymbolicParametersBotanaAlgo) inputElement2 .getParentAlgorithm()).getBotanaVars(inputElement2); // CD // We want to prove: d(AB)=d(CD) => // (a1-b1)^2+(a2-b2)^2=(c1-d1)^2+(c2-d2)^2 // => (a1-b1)^2+(a2-b2)^2-(c1-d1)^2-(c2-d2)^2 PPolynomial a1 = new PPolynomial(v1[0]); PPolynomial a2 = new PPolynomial(v1[1]); PPolynomial b1 = new PPolynomial(v1[2]); PPolynomial b2 = new PPolynomial(v1[3]); PPolynomial c1 = new PPolynomial(v2[0]); PPolynomial c2 = new PPolynomial(v2[1]); PPolynomial d1 = new PPolynomial(v2[2]); PPolynomial d2 = new PPolynomial(v2[3]); botanaPolynomials[0][0] = ((PPolynomial.sqr(a1.subtract(b1)) .add(PPolynomial.sqr(a2.subtract(b2)))) .subtract(PPolynomial.sqr(c1.subtract(d1)))) .subtract(PPolynomial.sqr(c2.subtract(d2))); return botanaPolynomials; } /* * Equality of two expressions, one of them is a segment, or both are * expressions. */ if ((inputElement1 instanceof GeoNumeric && inputElement2 instanceof GeoSegment) || (inputElement2 instanceof GeoNumeric && inputElement1 instanceof GeoSegment) || (inputElement1 instanceof GeoNumeric && inputElement2 instanceof GeoNumeric)) { GeoNumeric n1, n2 = null; GeoSegment s = null; if (inputElement1 instanceof GeoNumeric) { n1 = (GeoNumeric) inputElement1; if (inputElement2 instanceof GeoNumeric) { n2 = (GeoNumeric) inputElement2; } else { s = (GeoSegment) inputElement2; } } else { n1 = (GeoNumeric) inputElement2; s = (GeoSegment) inputElement1; } GeoGebraCAS cas = (GeoGebraCAS) kernel.getGeoGebraCAS(); ValidExpression resultVE; if ((inputElement1 instanceof GeoNumeric && inputElement2 instanceof GeoNumeric)) { // Create n1-n2=var as a ValidExpression resultVE = cas.getCASparser() .parseGeoGebraCASInputAndResolveDummyVars( n1.getDefinition() + "-" + n2.getDefinition(), kernel, null); } else { // Create n1-s=var as a ValidExpression resultVE = cas.getCASparser() .parseGeoGebraCASInputAndResolveDummyVars( n1.getDefinition() + "-" + s.getLabelSimple(), kernel, null); } // Convert the ValidExpression to ExpressionNode ExpressionNode en = new ExpressionNode(kernel, resultVE); // Silently create an AlgoDependentNumber from the ExpressionNode AlgoDependentNumber adn = new AlgoDependentNumber( n1.getConstruction(), en, false, null, false, false); // Obtain the polynomials PPolynomial[] result = adn.getBotanaPolynomials(n1); // n1 unused int no = result.length; botanaPolynomials = new PPolynomial[1][no + 1]; for (int i = 0; i < no; ++i) { botanaPolynomials[0][i + 1] = result[i]; } PVariable[] botanaVars = adn.getBotanaVars(n1); // n1 unused // Add the equation var=0 to the polynomial list botanaPolynomials[0][0] = new PPolynomial(botanaVars[0]); // This AlgoDependentNumber is not needed anymore n1.getConstruction().removeFromAlgorithmList(adn); return botanaPolynomials; } // area of two polygons // area of polygon is the sum of areas of triangles in polygon if (inputElement1 instanceof GeoNumeric && inputElement2 instanceof GeoNumeric && (inputElement1.getParentAlgorithm()) .getRelatedModeID() == EuclidianConstants.MODE_AREA && (inputElement2.getParentAlgorithm()) .getRelatedModeID() == EuclidianConstants.MODE_AREA) { // get botanaVars of points of first polygon PVariable[] v1 = ((SymbolicParametersBotanaAlgo) inputElement1 .getParentAlgorithm()).getBotanaVars(inputElement1); // get botanaVars of points of first polygon PVariable[] v2 = ((SymbolicParametersBotanaAlgo) inputElement2 .getParentAlgorithm()).getBotanaVars(inputElement2); // add areas of triangles in first polygon PPolynomial det1sum = PPolynomial.area(v1[0], v1[1], v1[2], v1[3], v1[4], v1[5]); for (int i = 4; i < v1.length - 3; i = i + 2) { det1sum = det1sum.add(PPolynomial.area(v1[0], v1[1], v1[i], v1[i + 1], v1[i + 2], v1[i + 3])); } // add areas of triangles in second polygon PPolynomial det2sum = PPolynomial.area(v2[0], v2[1], v2[2], v2[3], v2[4], v2[5]); for (int i = 4; i < v2.length - 3; i = i + 2) { det2sum = det2sum.add(PPolynomial.area(v2[0], v2[1], v2[i], v2[i + 1], v2[i + 2], v2[i + 3])); } botanaPolynomials = new PPolynomial[1][1]; botanaPolynomials[0][0] = (PPolynomial.sqr(det1sum)) .subtract(PPolynomial.sqr(det2sum)); return botanaPolynomials; } // TODO: Implement circles etc. throw new NoSymbolicParametersException(); } }