package org.geogebra.common.kernel.prover;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.HashSet;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.algos.SymbolicParameters;
import org.geogebra.common.kernel.algos.SymbolicParametersAlgo;
import org.geogebra.common.kernel.algos.SymbolicParametersBotanaAlgoAre;
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.kernel.geos.GeoPoint;
import org.geogebra.common.kernel.prover.polynomial.PPolynomial;
import org.geogebra.common.kernel.prover.polynomial.PVariable;
/**
* Decides if the points are concyclic. Can be embedded into the Prove command
* to work symbolically.
*
* @author Simon Weitzhofer 27th of April 2012
* @author Zoltan Kovacs <zoltan@geogebra.org>
*/
public class AlgoAreConcyclic extends AlgoElement
implements SymbolicParametersAlgo, SymbolicParametersBotanaAlgoAre {
private GeoPoint inputPoint1; // input
private GeoPoint inputPoint2; // input
private GeoPoint inputPoint3; // input
private GeoPoint inputPoint4; // input
private GeoBoolean outputBoolean; // output
private PPolynomial[] polynomials;
private PPolynomial[][] botanaPolynomials;
/**
* Tests if four points are concyclic
*
* @param cons
* The construction the lines depend on
* @param inputPoint1
* the first point
* @param inputPoint2
* the second point
* @param inputPoint3
* the third point
* @param inputPoint4
* the forth point
*/
public AlgoAreConcyclic(Construction cons, GeoPoint inputPoint1,
GeoPoint inputPoint2, GeoPoint inputPoint3, GeoPoint inputPoint4) {
super(cons);
this.inputPoint1 = inputPoint1;
this.inputPoint2 = inputPoint2;
this.inputPoint3 = inputPoint3;
this.inputPoint4 = inputPoint4;
outputBoolean = new GeoBoolean(cons);
setInputOutput();
compute();
}
/**
* Tests if four points are concyclic
*
* @param cons
* The construction the lines depend on
* @param label
* the label for the AlgoAreConcyclic object
* @param inputPoint1
* the first point
* @param inputPoint2
* the second point
* @param inputPoint3
* the third point
* @param inputPoint4
* the forth point
*/
public AlgoAreConcyclic(Construction cons, String label,
GeoPoint inputPoint1, GeoPoint inputPoint2, GeoPoint inputPoint3,
GeoPoint inputPoint4) {
this(cons, inputPoint1, inputPoint2, inputPoint3, inputPoint4);
outputBoolean.setLabel(label);
}
@Override
public Commands getClassName() {
return Commands.AreConcyclic;
}
@Override
protected void setInputOutput() {
input = new GeoElement[4];
input[0] = inputPoint1;
input[1] = inputPoint2;
input[2] = inputPoint3;
input[3] = inputPoint4;
super.setOutputLength(1);
super.setOutput(0, outputBoolean);
setDependencies(); // done by AlgoElement
}
/**
* Gets the result of the test
*
* @return true if the points are concyclic and false otherwise
*/
public GeoBoolean getResult() {
return outputBoolean;
}
@Override
public final void compute() {
outputBoolean.setValue(GeoPoint.concyclic(inputPoint1, inputPoint2,
inputPoint3, inputPoint4));
}
@Override
public SymbolicParameters getSymbolicParameters() {
return new SymbolicParameters(this);
}
@Override
public void getFreeVariables(HashSet<PVariable> variables)
throws NoSymbolicParametersException {
if (inputPoint1 != null && inputPoint2 != null && inputPoint3 != null
&& inputPoint4 != null) {
inputPoint1.getFreeVariables(variables);
inputPoint2.getFreeVariables(variables);
inputPoint3.getFreeVariables(variables);
inputPoint4.getFreeVariables(variables);
return;
}
throw new NoSymbolicParametersException();
}
@Override
public int[] getDegrees() throws NoSymbolicParametersException {
if (inputPoint1 != null && inputPoint2 != null && inputPoint3 != null
&& inputPoint4 != null) {
int[] degree1 = inputPoint1.getDegrees();
int[] degree2 = inputPoint2.getDegrees();
int[] degree3 = inputPoint3.getDegrees();
int[] degree4 = inputPoint4.getDegrees();
int[] degree = new int[1];
int[] list = {
degree1[1] + degree1[2] + degree2[0] + degree2[2]
+ 2 * degree3[0],
degree1[0] + degree1[2] + degree2[1] + degree2[2]
+ 2 * degree3[0],
degree1[1] + degree1[2] + degree2[0] + degree2[2]
+ 2 * degree3[1],
degree1[0] + degree1[2] + degree2[1] + degree2[2]
+ 2 * degree3[1],
degree1[1] + degree1[2] + 2 * degree2[0] + degree3[0]
+ degree3[2],
degree1[1] + degree1[2] + 2 * degree2[1] + degree3[0]
+ degree3[2],
2 * degree1[0] + degree2[1] + degree2[2] + degree3[0]
+ degree3[2],
2 * degree1[1] + degree2[1] + degree2[2] + degree3[0]
+ degree3[2],
2 * degree1[2] + degree2[1] + degree2[2] + degree3[0]
+ degree3[2],
degree1[1] + degree1[2] + 2 * degree2[2] + degree3[0]
+ degree3[2],
degree1[0] + degree1[2] + 2 * degree2[0] + degree3[1]
+ degree3[2],
degree1[0] + degree1[2] + 2 * degree2[1] + degree3[1]
+ degree3[2],
2 * degree1[0] + degree2[0] + degree2[2] + degree3[1]
+ degree3[2],
2 * degree1[1] + degree2[0] + degree2[2] + degree3[1]
+ degree3[2],
2 * degree1[2] + degree2[0] + degree2[2] + degree3[1]
+ degree3[2],
degree1[0] + degree1[2] + 2 * degree2[2] + degree3[1]
+ degree3[2],
degree1[1] + degree1[2] + degree2[0] + degree2[2]
+ 2 * degree3[2],
degree1[0] + degree1[2] + degree2[1] + degree2[2]
+ 2 * degree3[2],
2 * degree4[0],
2 * degree1[2] + degree2[1] + degree2[2] + 2 * degree3[0]
+ degree4[0],
degree1[1] + degree1[2] + 2 * degree2[2] + 2 * degree3[0]
+ degree4[0],
2 * degree1[2] + degree2[1] + degree2[2] + 2 * degree3[1]
+ degree4[0],
degree1[1] + degree1[2] + 2 * degree2[2] + 2 * degree3[1]
+ degree4[0],
2 * degree1[2] + 2 * degree2[0] + degree3[1] + degree3[2]
+ degree4[0],
2 * degree1[2] + 2 * degree2[1] + degree3[1] + degree3[2]
+ degree4[0],
2 * degree1[0] + 2 * degree2[2] + degree3[1] + degree3[2]
+ degree4[0],
2 * degree1[1] + 2 * degree2[2] + degree3[1] + degree3[2]
+ degree4[0],
degree1[1] + degree1[2] + 2 * degree2[0] + 2 * degree3[2]
+ degree4[0],
degree1[1] + degree1[2] + 2 * degree2[1] + 2 * degree3[2]
+ degree4[0],
2 * degree1[0] + degree2[1] + degree2[2] + 2 * degree3[2]
+ degree4[0],
2 * degree1[1] + degree2[1] + degree2[2] + 2 * degree3[2]
+ degree4[0],
2 * degree4[1],
2 * degree1[2] + degree2[0] + degree2[2] + 2 * degree3[0]
+ degree4[1],
degree1[0] + degree1[2] + 2 * degree2[2] + 2 * degree3[0]
+ degree4[1],
2 * degree1[2] + degree2[0] + degree2[2] + 2 * degree3[1]
+ degree4[1],
degree1[0] + degree1[2] + 2 * degree2[2] + 2 * degree3[1]
+ degree4[1],
2 * degree1[2] + 2 * degree2[0] + degree3[0] + degree3[2]
+ degree4[1],
2 * degree1[2] + 2 * degree2[1] + degree3[0] + degree3[2]
+ degree4[1],
2 * degree1[0] + 2 * degree2[2] + degree3[0] + degree3[2]
+ degree4[1],
2 * degree1[1] + 2 * degree2[2] + degree3[0] + degree3[2]
+ degree4[1],
degree1[0] + degree1[2] + 2 * degree2[0] + 2 * degree3[2]
+ degree4[1],
degree1[0] + degree1[2] + 2 * degree2[1] + 2 * degree3[2]
+ degree4[1],
2 * degree1[0] + degree2[0] + degree2[2] + 2 * degree3[2]
+ degree4[1],
2 * degree1[1] + degree2[0] + degree2[2] + 2 * degree3[2]
+ degree4[1],
degree4[2], 2 * degree4[2] };
// find max of list
int max = list[0];
for (int i = 1; i < list.length; i++) {
if (list[i] > max) {
max = list[i];
}
}
degree[0] = max;
return degree;
}
throw new NoSymbolicParametersException();
}
@Override
public BigInteger[] getExactCoordinates(
HashMap<PVariable, BigInteger> values)
throws NoSymbolicParametersException {
if (inputPoint1 != null && inputPoint2 != null && inputPoint3 != null
&& inputPoint4 != null) {
BigInteger[] coords1 = inputPoint1.getExactCoordinates(values);
BigInteger[] coords2 = inputPoint2.getExactCoordinates(values);
BigInteger[] coords3 = inputPoint3.getExactCoordinates(values);
BigInteger[] coords4 = inputPoint4.getExactCoordinates(values);
BigInteger[] coords = new BigInteger[1];
BigInteger[][] matrix = new BigInteger[4][4];
matrix[0][0] = coords1[0].multiply(coords1[2]);
matrix[0][1] = coords1[1].multiply(coords1[2]);
matrix[0][2] = coords1[0].multiply(coords1[0])
.add(coords1[1].multiply(coords1[1]));
matrix[0][3] = coords1[2].multiply(coords1[2]);
matrix[1][0] = coords2[0].multiply(coords2[2]);
matrix[1][1] = coords2[1].multiply(coords2[2]);
matrix[1][2] = coords2[0].multiply(coords2[0])
.add(coords2[1].multiply(coords2[1]));
matrix[1][3] = coords2[2].multiply(coords2[2]);
matrix[2][0] = coords3[0].multiply(coords3[2]);
matrix[2][1] = coords3[1].multiply(coords3[2]);
matrix[2][2] = coords3[0].multiply(coords3[0])
.add(coords3[1].multiply(coords3[1]));
matrix[2][3] = coords3[2].multiply(coords3[2]);
matrix[3][0] = coords4[0].multiply(coords4[2]);
matrix[3][1] = coords4[1].multiply(coords4[2]);
matrix[3][2] = coords4[0].multiply(coords4[0])
.add(coords4[1].multiply(coords4[1]));
matrix[3][3] = coords4[2].multiply(coords4[2]);
coords[0] = SymbolicParameters.det4(matrix);
return coords;
}
throw new NoSymbolicParametersException();
}
@Override
public PPolynomial[] getPolynomials() throws NoSymbolicParametersException {
if (polynomials != null) {
return polynomials;
}
if (inputPoint1 != null && inputPoint2 != null && inputPoint3 != null
&& inputPoint4 != null) {
PPolynomial[] coords1 = inputPoint1.getPolynomials();
PPolynomial[] coords2 = inputPoint2.getPolynomials();
PPolynomial[] coords3 = inputPoint3.getPolynomials();
PPolynomial[] coords4 = inputPoint4.getPolynomials();
polynomials = new PPolynomial[1];
PPolynomial[][] matrix = new PPolynomial[4][4];
matrix[0][0] = coords1[0].multiply(coords1[2]);
matrix[0][1] = coords1[1].multiply(coords1[2]);
matrix[0][2] = coords1[0].multiply(coords1[0])
.add(coords1[1].multiply(coords1[1]));
matrix[0][3] = coords1[2].multiply(coords1[2]);
matrix[1][0] = coords2[0].multiply(coords2[2]);
matrix[1][1] = coords2[1].multiply(coords2[2]);
matrix[1][2] = coords2[0].multiply(coords2[0])
.add(coords2[1].multiply(coords2[1]));
matrix[1][3] = coords2[2].multiply(coords2[2]);
matrix[2][0] = coords3[0].multiply(coords3[2]);
matrix[2][1] = coords3[1].multiply(coords3[2]);
matrix[2][2] = coords3[0].multiply(coords3[0])
.add(coords3[1].multiply(coords3[1]));
matrix[2][3] = coords3[2].multiply(coords3[2]);
matrix[3][0] = coords4[0].multiply(coords4[2]);
matrix[3][1] = coords4[1].multiply(coords4[2]);
matrix[3][2] = coords4[0].multiply(coords4[0])
.add(coords4[1].multiply(coords4[1]));
matrix[3][3] = coords4[2].multiply(coords4[2]);
polynomials[0] = PPolynomial.det4(matrix);
return polynomials;
}
throw new NoSymbolicParametersException();
}
@Override
public PPolynomial[][] getBotanaPolynomials()
throws NoSymbolicParametersException {
if (botanaPolynomials != null) {
return botanaPolynomials;
}
if (inputPoint1 != null && inputPoint2 != null && inputPoint3 != null
&& inputPoint4 != null) {
PVariable[] coords1 = inputPoint1.getBotanaVars(inputPoint1);
PVariable[] coords2 = inputPoint2.getBotanaVars(inputPoint2);
PVariable[] coords3 = inputPoint3.getBotanaVars(inputPoint3);
PVariable[] coords4 = inputPoint4.getBotanaVars(inputPoint4);
botanaPolynomials = new PPolynomial[1][1];
PPolynomial[][] matrix = new PPolynomial[4][4];
matrix[0][0] = new PPolynomial(coords1[0]);
matrix[0][1] = new PPolynomial(coords1[1]);
matrix[0][2] = matrix[0][0].multiply(matrix[0][0])
.add(matrix[0][1].multiply(matrix[0][1]));
matrix[0][3] = new PPolynomial(BigInteger.ONE);
matrix[1][0] = new PPolynomial(coords2[0]);
matrix[1][1] = new PPolynomial(coords2[1]);
matrix[1][2] = matrix[1][0].multiply(matrix[1][0])
.add(matrix[1][1].multiply(matrix[1][1]));
matrix[1][3] = new PPolynomial(BigInteger.ONE);
matrix[2][0] = new PPolynomial(coords3[0]);
matrix[2][1] = new PPolynomial(coords3[1]);
matrix[2][2] = matrix[2][0].multiply(matrix[2][0])
.add(matrix[2][1].multiply(matrix[2][1]));
matrix[2][3] = new PPolynomial(BigInteger.ONE);
matrix[3][0] = new PPolynomial(coords4[0]);
matrix[3][1] = new PPolynomial(coords4[1]);
matrix[3][2] = matrix[3][0].multiply(matrix[3][0])
.add(matrix[3][1].multiply(matrix[3][1]));
matrix[3][3] = new PPolynomial(BigInteger.ONE);
botanaPolynomials[0][0] = PPolynomial.det4(matrix);
return botanaPolynomials;
}
throw new NoSymbolicParametersException();
}
}