package org.geogebra.common.kernel;
import java.util.ArrayList;
import java.util.Arrays;
import org.geogebra.common.kernel.arithmetic.MyDouble;
/**
* Class for solving system of equations a1 x^2 + b1 xy + c1 y^2 + d1 x + e1 y +
* d1 = 0 a2 x^2 + b2 xy + c2 y^2 + d2 x + e2 y + d2 = 0
*
* @author ddrakulic
*
*/
public class SystemOfEquationsSolver {
private double epsilon = Kernel.STANDARD_PRECISION;
private EquationSolverInterface eqnSolver;
/**
* Creates new solver for systems of equations
*
* @param eqnSolver
* equation solver
*/
public SystemOfEquationsSolver(EquationSolverInterface eqnSolver) {
this.eqnSolver = eqnSolver;
}
/**
* Set precision
*
* @param eps
* precision
*/
void setEpsilon(double eps) {
epsilon = eps;
}
/**
* Solves of system of equations whose coefficients in arrays eqn1 and eqn2
* and places result in two-dimensional array res.
*
* Equations are represented by equations eqn1[0]*x^2 + eqn1[1]*xy +
* eqn1[2]*y^2 + eqn1[3]*x + eqn1[4]*y + eqn1[5] = 0 eqn2[0]*x^2 +
* eqn2[1]*xy + eqn2[2]*y^2 + eqn2[3]*x + eqn2[4]*y + eqn2[5] = 0
*
* @param eqn1
* coefficients in first equation
* @param eqn2
* coefficients in second equation
* @param res
* array to store result
* @param eps
* precision
*
* @return Number of real roots or -1 if equations are equal or coefficients
* are invalid
*
*/
final public int solveSystemOfQuadraticEquations(double eqn1[],
double eqn2[], double[][] res, double eps) {
ArrayList<Double> xs = new ArrayList<Double>();
ArrayList<Double> ys = new ArrayList<Double>();
if (eqn1[0] == 0 || eqn2[0] == 0 || eqn1[2] == 0 || eqn2[2] == 0) {
return -1;
}
double a20 = 1;
double a11 = eqn1[1] / eqn1[0];
double a02 = eqn1[2] / eqn1[0];
double a10 = eqn1[3] / eqn1[0];
double a01 = eqn1[4] / eqn1[0];
double a00 = eqn1[5] / eqn1[0];
double b20 = 1;
double b11 = eqn2[1] / eqn2[0];
double b02 = eqn2[2] / eqn2[0];
double b10 = eqn2[3] / eqn2[0];
double b01 = eqn2[4] / eqn2[0];
double b00 = eqn2[5] / eqn2[0];
if (MyDouble.exactEqual(a11, b11) && MyDouble.exactEqual(a02, b02)
&& MyDouble.exactEqual(a10, b10)
&& MyDouble.exactEqual(a01, b01)
&& MyDouble.exactEqual(a00, b00)) {
return -1;
}
double d00 = a20 * b10 - b20 * a10;
double d01 = a20 * b11 - b20 * a11;
double d10 = a10 * b00 - b10 * a00;
double d11 = a11 * b00 + a10 * b01 - b11 * a00 - b10 * a01;
double d12 = a11 * b01 + a10 * b02 - b11 * a01 - b10 * a02;
double d13 = a11 * b02 - b11 * a02;
double d20 = a20 * b00 - b20 * a00;
double d21 = a20 * b01 - b20 * a01;
double d22 = a20 * b02 - b20 * a02;
double quarticParams[] = new double[5];
quarticParams[0] = d00 * d10 - d20 * d20;
quarticParams[1] = d01 * d10 + d00 * d11 - 2 * d20 * d21;
quarticParams[2] = d01 * d11 + d00 * d12 - d21 * d21 - 2 * d20 * d22;
quarticParams[3] = d01 * d12 + d00 * d13 - 2 * d21 * d22;
quarticParams[4] = d01 * d13 - d22 * d22;
double[] quarticRoots = new double[4];
// finding candidates for y
int solnr = eqnSolver.solveQuartic(quarticParams, quarticRoots, eps);
Arrays.sort(quarticRoots, 0, solnr);
for (int i = 0; i < solnr; i++) {
double[] quadraticParams = new double[3];
quadraticParams[2] = a20;
quadraticParams[1] = a11 * quarticRoots[i] + a10;
quadraticParams[0] = a02 * quarticRoots[i] * quarticRoots[i]
+ a01 * quarticRoots[i] + a00;
double[] quadraticRoots = new double[3];
// finding candidates for x
int solnr2 = eqnSolver.solveQuadratic(quadraticParams,
quadraticRoots, eps);
Arrays.sort(quadraticRoots, 0, solnr2);
for (int j = 0; j < solnr2; j++) { // checking pairs (x, y)
double x = quadraticRoots[j];
double y = quarticRoots[i];
double result = b02 * y * y + b11 * x * y + b20 * x * x
+ b01 * y + b10 * x + b00;
if (Math.abs(result) < epsilon) {
xs.add(x);
ys.add(y);
}
}
}
for (int i = 0; i < xs.size(); i++) {
for (int j = i + 1; j < xs.size(); j++) {
// removing duplicates, pairs where x==y
if (Math.abs(xs.get(i) - xs.get(j)) < epsilon
&& Math.abs(ys.get(i) - ys.get(j)) < epsilon) {
xs.remove(j);
ys.remove(j);
j--;
}
}
}
if (xs.size() > res.length) {
return 0;
}
for (int i = 0; i < xs.size(); i++) {
res[i][0] = xs.get(i);
res[i][1] = ys.get(i);
}
return xs.size();
}
}