/*
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.algos;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import org.geogebra.common.cas.GeoGebraCAS;
import org.geogebra.common.euclidian.EuclidianConstants;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Path;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.arithmetic.BooleanValue;
import org.geogebra.common.kernel.arithmetic.ExpressionNode;
import org.geogebra.common.kernel.arithmetic.ExpressionValue;
import org.geogebra.common.kernel.arithmetic.MyDouble;
import org.geogebra.common.kernel.arithmetic.MySpecialDouble;
import org.geogebra.common.kernel.arithmetic.Traversing.GeoNumericLabelCollector;
import org.geogebra.common.kernel.arithmetic.Traversing.GeoNumericReplacer;
import org.geogebra.common.kernel.arithmetic.ValidExpression;
import org.geogebra.common.kernel.geos.GeoBoolean;
import org.geogebra.common.kernel.geos.GeoDummyVariable;
import org.geogebra.common.kernel.geos.GeoElement;
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.AlgoAreCongruent;
import org.geogebra.common.kernel.prover.AlgoAreEqual;
import org.geogebra.common.kernel.prover.AlgoAreParallel;
import org.geogebra.common.kernel.prover.AlgoArePerpendicular;
import org.geogebra.common.kernel.prover.AlgoIsOnPath;
import org.geogebra.common.kernel.prover.NoSymbolicParametersException;
import org.geogebra.common.kernel.prover.PolynomialNode;
import org.geogebra.common.kernel.prover.polynomial.PPolynomial;
import org.geogebra.common.kernel.prover.polynomial.PTerm;
import org.geogebra.common.kernel.prover.polynomial.PVariable;
import org.geogebra.common.plugin.Operation;
import org.geogebra.common.util.debug.Log;
/**
*
* @author Markus
*/
public class AlgoDependentBoolean extends AlgoElement implements
SymbolicParametersAlgo, SymbolicParametersBotanaAlgoAre, DependentAlgo {
private Set<GeoSegment> allSegmentsFromExpression = new HashSet<GeoSegment>();
private PVariable[] botanaVars;
private ArrayList<PPolynomial> extraPolys = new ArrayList<PPolynomial>();
private int nrOfMaxDecimals;
// substitution list of segments with variables
private ArrayList<Map.Entry<GeoElement, PVariable>> varSubstListOfSegs;
private GeoBoolean bool; // output
private boolean substNeeded = false;
private boolean leftWasDist = false, rightWasDist = false;
/**
* @param cons
* construction
* @param root
* defining expression
*/
public AlgoDependentBoolean(Construction cons, ExpressionNode root) {
super(cons);
bool = new GeoBoolean(cons);
bool.setDefinition(root);
setInputOutput(); // for AlgoElement
// compute value of dependent number
compute();
}
@Override
public Algos getClassName() {
return Algos.Expression;
}
// for AlgoElement
@Override
protected void setInputOutput() {
input = bool.getDefinition().getGeoElementVariables();
super.setOutputLength(1);
super.setOutput(0, bool);
setDependencies(); // done by AlgoElement
}
/**
* @return the resulting boolean
*/
public GeoBoolean getGeoBoolean() {
return bool;
}
// calc the current value of the arithmetic tree
@Override
public final void compute() {
ExpressionValue ev;
try {
ev = bool.getDefinition().evaluate(StringTemplate.defaultTemplate);
} catch (Exception e) {
ev = null;
}
ExpressionNode root = bool.getDefinition();
if (ev instanceof BooleanValue) {
bool.setValue(((BooleanValue) ev).getBoolean());
} else {
bool.setUndefined();
}
bool.setDefinition(root);
}
@Override
final public String toString(StringTemplate tpl) {
// was defined as e.g. c = a & b
return bool.getDefinition().toString(tpl);
}
@Override
public SymbolicParameters getSymbolicParameters() {
return new SymbolicParameters(this);
}
@Override
public void getFreeVariables(HashSet<PVariable> variables)
throws NoSymbolicParametersException {
SymbolicParametersAlgo algo = getRootAlgo();
if (algo != null) {
algo.getFreeVariables(variables);
algo.remove();
return;
}
throw new NoSymbolicParametersException();
}
@Override
public int[] getDegrees() throws NoSymbolicParametersException {
SymbolicParametersAlgo algo = getRootAlgo();
if (algo != null) {
int[] ret = algo.getDegrees();
algo.remove();
return ret;
}
throw new NoSymbolicParametersException();
}
@Override
public BigInteger[] getExactCoordinates(
HashMap<PVariable, BigInteger> values)
throws NoSymbolicParametersException {
SymbolicParametersAlgo algo = getRootAlgo();
if (algo != null) {
BigInteger[] ret = algo.getExactCoordinates(values);
algo.remove();
return ret;
}
throw new NoSymbolicParametersException();
}
@Override
public PPolynomial[] getPolynomials() throws NoSymbolicParametersException {
SymbolicParametersAlgo algo = getRootAlgo();
if (algo != null) {
PPolynomial[] ret = algo.getPolynomials();
algo.remove();
return ret;
}
throw new NoSymbolicParametersException();
}
private SymbolicParametersAlgo getRootAlgo()
throws NoSymbolicParametersException {
ExpressionNode root = bool.getDefinition();
if (!root.getLeft().isGeoElement() || !root.getRight().isGeoElement()) {
throw new NoSymbolicParametersException();
}
GeoElement left = (GeoElement) root.getLeft();
GeoElement right = (GeoElement) root.getRight();
if (root.getOperation().equals(Operation.PERPENDICULAR)) {
AlgoArePerpendicular algo = new AlgoArePerpendicular(cons, left,
right);
return algo;
}
if (root.getOperation().equals(Operation.PARALLEL)) {
AlgoAreParallel algo = new AlgoAreParallel(cons, left, right);
return algo;
}
if (root.getOperation().equals(Operation.EQUAL_BOOLEAN)) {
AlgoAreCongruent algo = new AlgoAreCongruent(cons, left, right);
return algo;
}
return null;
}
/**
* fill the polynomial tree
*
* @param expNode
* - expression node
* @param polyNode
* - polynomial node
* @throws NoSymbolicParametersException
* - unhandled operations
*/
public void expressionNodeToPolynomial(ExpressionNode expNode,
PolynomialNode polyNode) throws NoSymbolicParametersException {
if (polyNode.getPoly() != null) {
return;
}
if (polyNode.getLeft().getPoly() != null
&& polyNode.getRight().getPoly() != null) {
PPolynomial leftPoly = polyNode.getLeft().getPoly();
PPolynomial rightPoly = polyNode.getRight().getPoly();
switch (polyNode.getOperation()) {
case PLUS:
polyNode.setPoly(leftPoly.add(rightPoly));
break;
case MINUS:
polyNode.setPoly(leftPoly.subtract(rightPoly));
break;
case MULTIPLY:
polyNode.setPoly(leftPoly.multiply(rightPoly));
break;
case POWER:
/* It must fit in Long. If not, it will take forever. */
Long pow = polyNode.getRight().evaluateLong();
if (pow != null) {
PPolynomial poly = leftPoly;
for (Integer i = 1; i < pow; i++) {
poly = poly.multiply(leftPoly);
}
polyNode.setPoly(poly);
}
break;
default:
throw new NoSymbolicParametersException();
}
}
if (expNode.getLeft().isExpressionNode()
&& polyNode.getLeft().getPoly() == null) {
expressionNodeToPolynomial((ExpressionNode) expNode.getLeft(),
polyNode.getLeft());
}
if (expNode.getRight().isExpressionNode()
&& polyNode.getRight().getPoly() == null) {
expressionNodeToPolynomial((ExpressionNode) expNode.getRight(),
polyNode.getRight());
}
if (expNode.getLeft() instanceof MyDouble
&& polyNode.getLeft().getPoly() == null) {
BigInteger coeff = new BigDecimal(
expNode.getLeft().evaluateDouble()).toBigInteger();
polyNode.getLeft().setPoly(new PPolynomial(coeff));
}
if (expNode.getRight() instanceof MyDouble
&& polyNode.getRight().getPoly() == null) {
BigInteger coeff = new BigDecimal(
expNode.getRight().evaluateDouble()).toBigInteger();
polyNode.getRight().setPoly(new PPolynomial(coeff));
}
if (expNode.getLeft() instanceof MyDouble
&& expNode.getRight() instanceof GeoDummyVariable) {
BigInteger coeff = new BigDecimal(
expNode.getLeft().evaluateDouble()).toBigInteger();
PVariable v = getVariable(expNode.getRight()
.toString(StringTemplate.defaultTemplate));
if (v != null) {
PTerm t = new PTerm(v);
polyNode.setPoly(new PPolynomial(coeff, t));
return;
}
}
}
// get Variable with given name
private PVariable getVariable(String varStr) {
if (botanaVars != null) {
for (int i = 0; i < botanaVars.length; i++) {
if (varStr.equals(botanaVars[i].getName())) {
return botanaVars[i];
}
}
}
return null;
}
/**
* build a Polynomial tree from ExpressionNode
*
* @param expNode
* - expression node
* @param polyNode
* - polynomial node
* @throws NoSymbolicParametersException
* - unhandled operations
*/
public void buildPolynomialTree(ExpressionNode expNode,
PolynomialNode polyNode) throws NoSymbolicParametersException {
if (expNode == null) {
return;
}
// simplify polynomial if the left and right sides are numbers
if (expNode.getLeft() instanceof MyDouble
&& expNode.getRight() instanceof MyDouble) {
double d1 = expNode.getLeft().evaluateDouble();
double d2 = expNode.getRight().evaluateDouble();
Double d;
switch (expNode.getOperation()) {
case PLUS:
d = d1 + d2;
break;
case MINUS:
d = d1 - d2;
break;
case MULTIPLY:
d = d1 * d2;
break;
case POWER:
d = Math.pow(d1, d2);
break;
case DIVIDE:
d = (double) 1;
break;
default:
throw new NoSymbolicParametersException();
}
BigInteger i;
// if in the expression exists rational number with n decimals
// (if there's more than one rational number, then n is the max of
// decimal numbers)
// than multiply the coefficient with 10^n
if (nrOfMaxDecimals != 0) {
i = new BigDecimal(d * Math.pow(10, nrOfMaxDecimals))
.toBigInteger();
Log.error(
"Possible numerical error in converting formula coefficients to integer");
/* TODO: check if this conversion is really correct */
} else {
i = new BigDecimal(d).toBigInteger();
}
polyNode.setPoly(new PPolynomial(i));
return;
}
polyNode.setOperation(expNode.getOperation());
if (expNode.getLeft() != null) {
polyNode.setLeft(new PolynomialNode());
if (expNode.getLeft().isExpressionNode()) {
buildPolynomialTree((ExpressionNode) expNode.getLeft(),
polyNode.getLeft());
} else {
if (expNode.getLeft() instanceof GeoDummyVariable) {
polyNode.getLeft()
.setPoly(new PPolynomial(
getBotanaVar(expNode.getLeft().toString(
StringTemplate.defaultTemplate))));
}
if (expNode.getLeft() instanceof MySpecialDouble) {
Double d = expNode.getLeft().evaluateDouble();
int i;
// if in the expression exists rational number with n
// decimals
// (if there's more than one rational number, then n is the
// max of decimal numbers)
// than multiply the coefficient with 10^n
if (nrOfMaxDecimals != 0) {
i = (int) (d * Math.pow(10, nrOfMaxDecimals));
} else {
i = d.intValue();
}
polyNode.getLeft().setPoly(new PPolynomial(i));
}
}
}
if (expNode.getRight() != null) {
polyNode.setRight(new PolynomialNode());
if (expNode.getRight().isExpressionNode()) {
buildPolynomialTree((ExpressionNode) expNode.getRight(),
polyNode.getRight());
} else {
if (expNode.getRight() instanceof GeoDummyVariable) {
try {
polyNode.getRight().setPoly(new PPolynomial(
getBotanaVar(expNode.getRight().toString(
StringTemplate.defaultTemplate))));
} catch (Exception e) {
throw new NoSymbolicParametersException();
}
}
if (expNode.getRight() instanceof MySpecialDouble) {
double d = expNode.getRight().evaluateDouble();
BigInteger i;
// simplify the polynomial if in expression is product of
// numbers
if (polyNode.getLeft().getPoly() != null
&& polyNode.getLeft().getPoly().isConstant()) {
switch (polyNode.getOperation()) {
case MULTIPLY:
i = polyNode.getLeft().getPoly()
.getConstant().multiply(new BigInteger(Long.toString((long) d)));
break;
case DIVIDE:
i = BigInteger.ONE;
break;
default:
throw new NoSymbolicParametersException();
}
polyNode.setPoly(new PPolynomial(i));
return;
}
// if in the expression exists rational number with n
// decimals
// (if there's more than one rational number, then n is the
// max of decimal numbers)
// than multiply the coefficient with 10^n
if (nrOfMaxDecimals != 0
&& expNode.getOperation() != Operation.POWER) {
i = new BigInteger(Long.toString(((long) (d * Math.pow(10, nrOfMaxDecimals)))));
} else {
i = new BigInteger(Long.toString(((long) d)));
}
polyNode.getRight().setPoly(new PPolynomial(i));
}
}
}
}
private PVariable getBotanaVar(String str) {
for (PVariable variable : botanaVars) {
if (variable.getName().equals(str)) {
return variable;
}
}
return null;
}
// procedure to traverse inorder the expression
private void traverseExpression(ExpressionNode node)
throws NoSymbolicParametersException {
if (node.getLeft() != null && node.getLeft().isGeoElement()
&& node.getLeft() instanceof GeoSegment) {
// if segment was given with command, eg. Segment[A,B]
// set new name for segment (which giac will use later)
if (((GeoSegment) node.getLeft()).getLabelSimple() == null) {
((GeoSegment) node.getLeft())
.setLabel(new PVariable(kernel).toString());
}
allSegmentsFromExpression.add((GeoSegment) node.getLeft());
}
if (node.getRight() != null && node.getRight().isGeoElement()
&& node.getRight() instanceof GeoSegment) {
// if segment was given with command, eg. Segment[A,B]
// set new name for segment (which giac will use later)
if (((GeoSegment) node.getRight()).getLabelSimple() == null) {
((GeoSegment) node.getRight())
.setLabel(new PVariable(kernel).toString());
}
allSegmentsFromExpression.add((GeoSegment) node.getRight());
}
if (node.getLeft() != null && node.getLeft().isExpressionNode()) {
traverseExpression((ExpressionNode) node.getLeft());
}
if (node.getRight() != null && node.getRight().isExpressionNode()) {
traverseExpression((ExpressionNode) node.getRight());
}
if (node.getLeft() != null && node.getLeft().isExpressionNode()
&& node.getRight().isExpressionNode()) {
return;
}
// case number with segment, eg. 2*a^2
if (node.getLeft() instanceof MyDouble
&& node.getRight().isExpressionNode()
&& (node.getOperation() == Operation.DIVIDE
|| node.getOperation() == Operation.MULTIPLY)) {
return;
}
// case segment with number, eg. a^2*1,5
if (node.getRight() instanceof MyDouble
&& node.getLeft().isExpressionNode()) {
return;
}
}
@Override
public PPolynomial[][] getBotanaPolynomials()
throws NoSymbolicParametersException {
ExpressionNode root = bool.getDefinition();
// replace Distance[A,B] with geoSegment
if (!(root.getLeft().isExpressionNode())
&& root.getLeft() instanceof GeoNumeric) {
AlgoElement algo = ((GeoElement) root.getLeft())
.getParentAlgorithm();
if (algo instanceof AlgoDistancePoints) {
GeoSegment geo = cons.getSegmentFromAlgoList(
(GeoPoint) algo.getInput(0),
(GeoPoint) algo.getInput(1));
if (geo != null) {
root.setLeft(geo);
} else {
geo = new GeoSegment(cons, (GeoPoint) algo.input[0],
(GeoPoint) algo.input[1]);
geo.setParentAlgorithm(algo);
root.setLeft(geo);
leftWasDist = true;
}
}
}
if (!(root.getRight().isExpressionNode())
&& root.getRight() instanceof GeoNumeric) {
AlgoElement algo = ((GeoElement) root.getRight())
.getParentAlgorithm();
if (algo instanceof AlgoDistancePoints) {
GeoSegment geo = cons.getSegmentFromAlgoList(
(GeoPoint) algo.getInput(0),
(GeoPoint) algo.getInput(1));
if (geo != null) {
root.setRight(geo);
} else {
geo = new GeoSegment(cons, (GeoPoint) algo.input[0],
(GeoPoint) algo.input[1]);
geo.setParentAlgorithm(algo);
root.setRight(geo);
rightWasDist = true;
}
}
}
// Easy cases: both sides are GeoElements:
if (root.getLeft().isGeoElement()
&& (!(root.getLeft() instanceof GeoNumeric)
|| ((GeoElement) root.getLeft()).getParentAlgorithm()
.getRelatedModeID() == EuclidianConstants.MODE_AREA)
&& root.getRight().isGeoElement()
&& (!(root.getRight() instanceof GeoNumeric)
|| ((GeoElement) root.getRight()).getParentAlgorithm()
.getRelatedModeID() == EuclidianConstants.MODE_AREA)) {
GeoElement left = (GeoElement) root.getLeft();
GeoElement right = (GeoElement) root.getRight();
if (root.getOperation().equals(Operation.PERPENDICULAR)) {
AlgoArePerpendicular algo = new AlgoArePerpendicular(cons, left,
right);
PPolynomial[][] ret = algo.getBotanaPolynomials();
cons.removeFromConstructionList(algo);
return ret;
}
if (root.getOperation().equals(Operation.PARALLEL)) {
AlgoAreParallel algo = new AlgoAreParallel(cons, left, right);
PPolynomial[][] ret = algo.getBotanaPolynomials();
cons.removeFromConstructionList(algo);
return ret;
}
if (root.getOperation().equals(Operation.EQUAL_BOOLEAN)) {
if (root.getLeft() instanceof GeoNumeric
&& ((GeoElement) root.getLeft()).getParentAlgorithm()
.getRelatedModeID() == EuclidianConstants.MODE_AREA
&& root.getRight() instanceof GeoNumeric
&& ((GeoElement) root.getLeft()).getParentAlgorithm()
.getRelatedModeID() == EuclidianConstants.MODE_AREA) {
AlgoAreEqual algo = new AlgoAreEqual(cons, left, right);
PPolynomial[][] ret = algo.getBotanaPolynomials();
cons.removeFromConstructionList(algo);
algo.setProtectedInput(true);
if (leftWasDist) {
left.getParentAlgorithm().setProtectedInput(true);
left.doRemove();
}
if (rightWasDist) {
right.getParentAlgorithm().setProtectedInput(true);
right.doRemove();
}
return ret;
}
AlgoAreCongruent algo = new AlgoAreCongruent(cons, left, right);
PPolynomial[][] ret = algo.getBotanaPolynomials();
cons.removeFromConstructionList(algo);
algo.setProtectedInput(true);
if (leftWasDist) {
left.getParentAlgorithm().setProtectedInput(true);
left.doRemove();
}
if (rightWasDist) {
right.getParentAlgorithm().setProtectedInput(true);
right.doRemove();
}
return ret;
}
if (root.getOperation().equals(Operation.IS_ELEMENT_OF)) {
AlgoIsOnPath algo = new AlgoIsOnPath(cons, (GeoPoint) left,
(Path) right);
PPolynomial[][] ret = algo.getBotanaPolynomials();
cons.removeFromConstructionList(algo);
return ret;
}
}
// handle special case, when left expression is given by another algo
if (!(root.getLeft().isExpressionNode())
&& !(root.getLeft() instanceof MyDouble)) {
AlgoElement algo = ((GeoElement) root.getLeft())
.getParentAlgorithm();
if (algo instanceof AlgoDependentNumber) {
root.setLeft(((AlgoDependentNumber) algo).getExpression());
}
}
// handle special case, when right expression is given by another algo
if (!(root.getRight().isExpressionNode())
&& !(root.getRight() instanceof MyDouble)) {
AlgoElement algo = ((GeoElement) root.getRight())
.getParentAlgorithm();
if (algo instanceof AlgoDependentNumber) {
root.setRight(((AlgoDependentNumber) algo).getExpression());
}
}
// More difficult cases: sides are expressions:
if (((root.getLeft().isExpressionNode()
|| root.getRight().isExpressionNode())
&& root.getOperation().equals(Operation.EQUAL_BOOLEAN))
|| (root.getLeft() instanceof GeoElement
&& root.getRight() instanceof MyDouble
&& root.getOperation()
.equals(Operation.EQUAL_BOOLEAN))) {
traverseExpression(root);
// try to check substituted and expanded expression
ExpressionNode rootCopy = root.deepCopy(kernel);
// collect all labels of GeoNumerics from expression
Set<String> setOfGeoNumLabels = new TreeSet<String>();
rootCopy.traverse(
GeoNumericLabelCollector.getCollector(setOfGeoNumLabels));
if (!setOfGeoNumLabels.isEmpty()) {
substNeeded = true;
}
Iterator<String> it = setOfGeoNumLabels.iterator();
while (it.hasNext()) {
String varStr = it.next();
// get GeoNumeric from construction with given label
GeoNumeric geo = (GeoNumeric) cons.geoTableVarLookup(varStr);
// get substitute formula of GeoNumeric
ExpressionNode replExp = ((AlgoDependentNumber) geo
.getParentAlgorithm()).getExpression();
GeoNumericReplacer repl = GeoNumericReplacer.getReplacer(geo,
replExp, kernel);
// replace GeoNumeric with formula expression
rootCopy.traverse(repl);
}
// traverse substituted expression to collect segments
traverseExpression(rootCopy);
if (((rootCopy.getLeft() instanceof GeoSegment
&& rootCopy.getRight() instanceof MyDouble)
|| (rootCopy.getRight() instanceof GeoSegment
&& rootCopy.getLeft() instanceof MyDouble))
&& rootCopy.getOperation()
.equals(Operation.EQUAL_BOOLEAN)) {
PPolynomial[][] ret = null;
return ret;
}
GeoGebraCAS cas = (GeoGebraCAS) kernel.getGeoGebraCAS();
try {
// get expanded expression of root
String expandGiacOutput = cas.getCurrentCAS()
.evaluateRaw(
"expand("
+ rootCopy.getLeftTree().toString(
StringTemplate.giacTemplate)
+ ")");
if (!expandGiacOutput.contains("?")
&& !"{}".equals(expandGiacOutput)) {
// parse expanded string into expression
ValidExpression expandValidExp = (kernel.getGeoGebraCAS())
.getCASparser()
.parseGeoGebraCASInputAndResolveDummyVars(
expandGiacOutput, kernel, null);
traverseExpression((ExpressionNode) expandValidExp);
}
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
PPolynomial[][] ret = null;
return ret;
}
throw new NoSymbolicParametersException(); // unhandled expression
}
/**
* @return input expression
*/
@Override
public ExpressionNode getExpression() {
return bool.getDefinition();
}
/**
* @return input operation
*/
public Operation getOperation() {
return bool.getDefinition().getOperation();
}
/**
* @return string for giac from input expression
* @throws NoSymbolicParametersException
* when no polynomials can be obtained
*/
public String getStrForGiac() throws NoSymbolicParametersException {
String[] labels = new String[allSegmentsFromExpression.size()];
extraPolys.clear();
if (botanaVars == null) {
botanaVars = new PVariable[allSegmentsFromExpression.size()];
}
if (varSubstListOfSegs == null) {
varSubstListOfSegs = new ArrayList<Entry<GeoElement, PVariable>>();
}
int index = 0;
for (GeoSegment segment : allSegmentsFromExpression) {
labels[index] = segment.getLabel(StringTemplate.giacTemplate);
if (botanaVars[index] == null) {
botanaVars[index] = new PVariable(kernel);
}
// collect substitution of segments with variables
Entry<GeoElement, PVariable> subst = new AbstractMap.SimpleEntry<GeoElement, PVariable>(
segment, botanaVars[index]);
if (!varSubstListOfSegs.isEmpty()) {
Iterator<Entry<GeoElement, PVariable>> it = varSubstListOfSegs
.iterator();
int k = 0;
while (it.hasNext()) {
Entry<GeoElement, PVariable> curr = it.next();
if (curr.getKey().equals(segment)
&& curr.getValue().equals(botanaVars[index])) {
break;
}
k++;
}
if (k == varSubstListOfSegs.size()) {
varSubstListOfSegs.add(subst);
}
} else {
varSubstListOfSegs.add(subst);
}
PVariable[] thisSegBotanaVars = segment.getBotanaVars(segment);
PPolynomial s = new PPolynomial(botanaVars[index]);
PPolynomial currPoly = s.multiply(s)
.subtract(PPolynomial.sqrDistance(thisSegBotanaVars[0],
thisSegBotanaVars[1], thisSegBotanaVars[2],
thisSegBotanaVars[3]));
extraPolys.add(currPoly);
index++;
}
String rootStr;
// make sure we use substituted expression
// if substitution was made in root
if (substNeeded) {
ExpressionNode rootCopy = bool.getDefinition().deepCopy(kernel);
// collect all labels of GeoNumerics from expression
Set<String> setOfGeoNumLabels = new TreeSet<String>();
rootCopy.traverse(
GeoNumericLabelCollector.getCollector(setOfGeoNumLabels));
Iterator<String> it = setOfGeoNumLabels.iterator();
while (it.hasNext()) {
String varStr = it.next();
// get GeoNumeric from construction with given label
GeoNumeric geo = (GeoNumeric) cons.geoTableVarLookup(varStr);
// get substitute formula of GeoNumeric
ExpressionNode replExp = ((AlgoDependentNumber) geo
.getParentAlgorithm()).getExpression();
GeoNumericReplacer repl = GeoNumericReplacer.getReplacer(geo,
replExp, kernel);
// replace GeoNumeric with formula expression
rootCopy.traverse(repl);
}
rootStr = rootCopy.toString(StringTemplate.giacTemplate);
} else {
rootStr = bool.getDefinition()
.toString(StringTemplate.giacTemplate);
}
String[] splitedStr = rootStr.split(",");
/*
* This 24 is hardcoded, it is the length of "[when(ggbIsZero(simplify"
* which is the beginning of rootStr. FIXME
*/
rootStr = splitedStr[0].substring(24, splitedStr[0].length() - 2);
StringBuilder strForGiac = new StringBuilder();
strForGiac.append("eliminate([");
strForGiac.append(rootStr);
strForGiac.append("=0");
StringBuilder labelsStr = new StringBuilder();
for (int i = 0; i < labels.length; i++) {
if (i == 0) {
labelsStr.append(labels[i]);
} else {
labelsStr.append(",");
labelsStr.append(labels[i]);
}
strForGiac.append(",");
strForGiac.append(labels[i]);
strForGiac.append("^2=");
strForGiac.append(botanaVars[i]);
strForGiac.append("^2");
}
strForGiac.append("],[");
strForGiac.append(labelsStr);
strForGiac.append("])");
Log.debug(strForGiac.toString());
return strForGiac.toString();
}
/**
* @return string for giac
*/
public String getUserGiacString() {
String[] labels = new String[allSegmentsFromExpression.size()];
int index = 0;
for (GeoSegment segment : allSegmentsFromExpression) {
labels[index] = segment.getLabel(StringTemplate.giacTemplate);
index++;
}
String rootStr;
// make sure we use substituted expression
// if substitution was made in root
if (substNeeded) {
ExpressionNode rootCopy = bool.getDefinition().deepCopy(kernel);
// collect all labels of GeoNumerics from expression
Set<String> setOfGeoNumLabels = new TreeSet<String>();
rootCopy.traverse(
GeoNumericLabelCollector.getCollector(setOfGeoNumLabels));
Iterator<String> it = setOfGeoNumLabels.iterator();
while (it.hasNext()) {
String varStr = it.next();
// get GeoNumeric from construction with given label
GeoNumeric geo = (GeoNumeric) cons.geoTableVarLookup(varStr);
// get substitute formula of GeoNumeric
ExpressionNode replExp = ((AlgoDependentNumber) geo
.getParentAlgorithm()).getExpression();
GeoNumericReplacer repl = GeoNumericReplacer.getReplacer(geo,
replExp, kernel);
// replace GeoNumeric with formula expression
rootCopy.traverse(repl);
}
rootStr = rootCopy.toString(StringTemplate.giacTemplate);
} else {
rootStr = bool.getDefinition()
.toString(StringTemplate.giacTemplate);
}
String[] splitedStr = rootStr.split(",");
/*
* This 24 is hardcoded, it is the length of "[when(ggbIsZero(simplify"
* which is the beginning of rootStr. FIXME
*/
rootStr = splitedStr[0].substring(24, splitedStr[0].length() - 2);
StringBuilder strForGiac = new StringBuilder();
strForGiac.append("eliminate([");
strForGiac.append(rootStr);
strForGiac.append("=0");
StringBuilder labelsStr = new StringBuilder();
for (int i = 0; i < labels.length; i++) {
if (i == 0) {
labelsStr.append(labels[i]);
} else {
labelsStr.append(",");
labelsStr.append(labels[i]);
}
strForGiac.append("," + labels[i] + "=" + botanaVars[i]);
}
strForGiac.append("],[");
strForGiac.append(labelsStr);
strForGiac.append("])");
return strForGiac.toString();
}
/**
* @return distance polynomials
*/
public ArrayList<PPolynomial> getExtraPolys() {
return extraPolys;
}
/**
* @return substitution list of segments with variables
*/
public ArrayList<Entry<GeoElement, PVariable>> getVarSubstListOfSegs() {
return varSubstListOfSegs;
}
}