package org.geogebra.common.gui.view.probcalculator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.TreeSet;
import org.geogebra.common.awt.GColor;
import org.geogebra.common.euclidian.EuclidianView;
import org.geogebra.common.gui.SetLabels;
import org.geogebra.common.gui.view.data.PlotSettings;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.ModeSetter;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.View;
import org.geogebra.common.kernel.algos.AlgoBarChart;
import org.geogebra.common.kernel.algos.AlgoDependentNumber;
import org.geogebra.common.kernel.algos.AlgoDependentPoint;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.algos.AlgoJoinPointsSegment;
import org.geogebra.common.kernel.algos.AlgoListElement;
import org.geogebra.common.kernel.algos.AlgoMax;
import org.geogebra.common.kernel.algos.AlgoMin;
import org.geogebra.common.kernel.algos.AlgoPointOnPath;
import org.geogebra.common.kernel.algos.AlgoPolyLine;
import org.geogebra.common.kernel.algos.AlgoRayPointVector;
import org.geogebra.common.kernel.algos.AlgoSequence;
import org.geogebra.common.kernel.algos.AlgoStepGraph;
import org.geogebra.common.kernel.algos.AlgoStickGraph;
import org.geogebra.common.kernel.algos.AlgoTake;
import org.geogebra.common.kernel.arithmetic.ExpressionNode;
import org.geogebra.common.kernel.arithmetic.ExpressionNodeConstants.StringType;
import org.geogebra.common.kernel.arithmetic.MyDouble;
import org.geogebra.common.kernel.arithmetic.MyVecNode;
import org.geogebra.common.kernel.cas.AlgoIntegralDefinite;
import org.geogebra.common.kernel.geos.GProperty;
import org.geogebra.common.kernel.geos.GeoAxis;
import org.geogebra.common.kernel.geos.GeoBoolean;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.geos.GeoLine;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.geos.GeoNumberValue;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.geos.GeoPoint;
import org.geogebra.common.kernel.geos.GeoVector;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.kernel.statistics.AlgoBinomialDist;
import org.geogebra.common.kernel.statistics.AlgoCauchyDF;
import org.geogebra.common.kernel.statistics.AlgoChiSquaredDF;
import org.geogebra.common.kernel.statistics.AlgoDistributionDF;
import org.geogebra.common.kernel.statistics.AlgoExponentialDF;
import org.geogebra.common.kernel.statistics.AlgoFDistributionDF;
import org.geogebra.common.kernel.statistics.AlgoGammaDF;
import org.geogebra.common.kernel.statistics.AlgoHyperGeometric;
import org.geogebra.common.kernel.statistics.AlgoInversePascal;
import org.geogebra.common.kernel.statistics.AlgoInversePoisson;
import org.geogebra.common.kernel.statistics.AlgoLogNormalDF;
import org.geogebra.common.kernel.statistics.AlgoLogisticDF;
import org.geogebra.common.kernel.statistics.AlgoNormalDF;
import org.geogebra.common.kernel.statistics.AlgoPascal;
import org.geogebra.common.kernel.statistics.AlgoPoisson;
import org.geogebra.common.kernel.statistics.AlgoTDistributionDF;
import org.geogebra.common.kernel.statistics.AlgoWeibullDF;
import org.geogebra.common.main.App;
import org.geogebra.common.main.GeoGebraColorConstants;
import org.geogebra.common.main.Localization;
import org.geogebra.common.main.settings.AbstractSettings;
import org.geogebra.common.main.settings.ProbabilityCalculatorSettings;
import org.geogebra.common.main.settings.ProbabilityCalculatorSettings.DIST;
import org.geogebra.common.main.settings.SettingListener;
import org.geogebra.common.plugin.EuclidianStyleConstants;
import org.geogebra.common.plugin.Operation;
import org.geogebra.common.util.debug.Log;
import org.geogebra.common.util.lang.Unicode;
/**
* @author gabor
*
* Commmon view for ProbabilityCalculator
*
*/
public abstract class ProbabilityCalculatorView
implements View, SettingListener, SetLabels {
/**
* Application
*/
protected App app;
/**
* Kernel
*/
protected Kernel kernel;
/**
* Localization
*/
protected Localization loc;
/**
* Construction
*/
protected Construction cons;
// colors
private static final GColor colorPDF() {
return GeoGebraColorConstants.DARKBLUE;
}
private static final GColor COLOR_NORMAL_OVERLAY = GColor.RED;
private static final GColor COLOR_PDF_FILL = GColor.BLUE;
private static final GColor COLOR_POINT = GColor.BLACK;
private EuclidianView plotPanel;
private ProbabilityTable table;
/** enable/disable integral ---- use for testing */
protected boolean hasIntegral = true;
/** selected distribution mode */
protected DIST selectedDist = DIST.NORMAL; // default: startup with normal
// distribution
// distribution fields
private String[][] parameterLabels;
/**
* maximum number of parameters allowed for a distribution
*/
protected final static int maxParameterCount = 3;
protected double[] parameters;
protected boolean isCumulative = false;
// maps for the distribution ComboBox
private HashMap<DIST, String> distributionMap;
private HashMap<String, DIST> reverseDistributionMap;
// GeoElements
protected ArrayList<GeoElementND> plotGeoList;
protected GeoPoint lowPoint, highPoint, curvePoint;
protected GeoElement densityCurve, integral, ySegment, xSegment,
discreteIntervalGraph, normalOverlay;
protected GeoElementND discreteGraph;
protected GeoList discreteValueList, discreteProbList, intervalProbList,
intervalValueList;
// private GeoList parmList;
protected ArrayList<GeoElement> pointList;
// initing
protected boolean isIniting;
protected boolean isSettingAxisPoints = false;
// probability calculation modes
public static final int PROB_INTERVAL = 0;
public static final int PROB_LEFT = 1;
public static final int PROB_RIGHT = 2;
protected int probMode = PROB_INTERVAL;
// interval values
private double low = 0;
private double high = 1;
// current probability result
protected double probability;
// rounding
protected int printDecimals = 4, printFigures = -1;
// flags
protected boolean showProbGeos = true;
protected boolean showNormalOverlay = false;
private static final double opacityIntegral = 0.5f;
private static final double opacityDiscrete = 0.0f; // entire bar chart
private static final double opacityDiscreteInterval = 0.5f; // bar chart
// interval
private static final int thicknessCurve = 4;
private static final int thicknessBarChart = 3;
protected boolean removeFromConstruction = true;
protected static final double nearlyOne = 1 - 1E-6;
// discrete graph types
public static final int GRAPH_BAR = 0;
public static final int GRAPH_LINE = 1;
public static final int GRAPH_STEP = 2;
protected int graphTypePDF = GRAPH_BAR;
protected int graphTypeCDF = GRAPH_STEP;
protected int graphType = GRAPH_BAR;
protected PlotSettings plotSettings;
protected ProbabilityManager probManager;
protected GeoFunction pdfCurve;
public ProbabilityCalculatorView(App app) {
isIniting = true;
this.app = app;
this.loc = app.getLocalization();
kernel = app.getKernel();
cons = kernel.getConstruction();
// Initialize settings and register listener
app.getSettings().getProbCalcSettings().addListener(this);
probManager = new ProbabilityManager(app, this);
plotSettings = new PlotSettings();
plotGeoList = new ArrayList<GeoElementND>();
}
protected void setLabelArrays() {
distributionMap = probManager.getDistributionMap();
reverseDistributionMap = probManager.getReverseDistributionMap();
parameterLabels = ProbabilityManager
.getParameterLabelArray(app.getLocalization());
}
/**
* Returns the maximum value in the discrete value list.
*
* @return maximum value in the discrete value list.
*/
public int getDiscreteXMax() {
if (discreteValueList != null) {
GeoNumeric geo = (GeoNumeric) discreteValueList
.get(discreteValueList.size() - 1);
return (int) geo.getDouble();
}
return -1;
}
/**
* Returns the minimum value in the discrete value list.
*
* @return minimum value in the discrete value list.
*/
public int getDiscreteXMin() {
if (discreteValueList != null) {
GeoNumeric geo = (GeoNumeric) discreteValueList.get(0);
return (int) geo.getDouble();
}
return -1;
}
public void setGraphType(int type) {
if (graphType == type) {
return;
}
graphType = type;
if (isCumulative) {
graphTypeCDF = type;
} else {
graphTypePDF = type;
}
updateAll();
}
public final void setCumulative(boolean isCumulative) {
if (this.isCumulative == isCumulative) {
return;
}
this.isCumulative = isCumulative;
// in cumulative mode only left-sided intervals are allowed
setProbabilityComboBoxMenu();
if (!isCumulative) {
// make sure left-sided is still selected when reverting to
// non-cumulative mode
setTypeSelectedIndex(PROB_LEFT);
}
if (isCumulative) {
graphType = graphTypeCDF;
} else {
graphType = graphTypePDF;
}
updateAll();
}
protected abstract void setProbabilityComboBoxMenu();
protected abstract void setTypeSelectedIndex(int probLeft);
public int getGraphType() {
return graphType;
}
public int getPrintDecimals() {
return printDecimals;
}
public int getPrintFigures() {
return printFigures;
}
public void setProbabilityCalculator(DIST distributionType,
double[] parameters, boolean isCumulative) {
this.selectedDist = distributionType;
this.isCumulative = isCumulative;
this.parameters = parameters;
if (parameters == null) {
this.parameters = ProbabilityManager
.getDefaultParameters(selectedDist);
}
updateAll();
}
public PlotSettings getPlotSettings() {
return plotSettings;
}
public void setPlotSettings(PlotSettings plotSettings) {
this.plotSettings = plotSettings;
}
public boolean isShowNormalOverlay() {
return showNormalOverlay;
}
public void setShowNormalOverlay(boolean showNormalOverlay) {
this.showNormalOverlay = showNormalOverlay;
}
public abstract void updateAll();
// =================================================
// Getters/Setters
// =================================================
public DIST getSelectedDist() {
return selectedDist;
}
public double getLow() {
return low;
}
public double getHigh() {
return high;
}
public int getProbMode() {
return probMode;
}
public boolean isCumulative() {
return isCumulative;
}
// =================================================
// Plotting
// =================================================
/**
* Creates the required GeoElements for the currently selected distribution
* type and parameters.
*/
protected void createGeoElements() {
this.removeGeos();
// create low point
GeoAxis path = (GeoAxis) kernel.lookupLabel(loc.getPlain("xAxis"));
AlgoPointOnPath algoLow = new AlgoPointOnPath(cons, path, 0d, 0d);
cons.removeFromConstructionList(algoLow);
lowPoint = (GeoPoint) algoLow.getOutput(0);
lowPoint.setObjColor(COLOR_POINT);
lowPoint.setPointSize(4);
lowPoint.setPointStyle(
EuclidianStyleConstants.POINT_STYLE_TRIANGLE_NORTH);
lowPoint.setLayer(5);
plotGeoList.add(lowPoint);
// create high point
AlgoPointOnPath algoHigh = new AlgoPointOnPath(cons, path, 0d, 0d);
cons.removeFromConstructionList(algoHigh);
highPoint = (GeoPoint) algoHigh.getOutput(0);
highPoint.setObjColor(COLOR_POINT);
highPoint.setPointSize(4);
highPoint.setPointStyle(
EuclidianStyleConstants.POINT_STYLE_TRIANGLE_NORTH);
highPoint.setLayer(5);
plotGeoList.add(highPoint);
pointList = new ArrayList<GeoElement>();
pointList.add(lowPoint);
pointList.add(highPoint);
// Set the axis points so they are not equal. This needs to be done
// before the integral geo is created.
setXAxisPoints();
if (probManager.isDiscrete(selectedDist)) {
// discrete distribution
// ====================================================
// create discrete bar graph and associated lists
createDiscreteLists();
// create discrete graph
// ============================
if (graphType == GRAPH_STEP) {
GeoBoolean t = new GeoBoolean(cons);
t.setValue(true);
AlgoStepGraph algoStepGraph = new AlgoStepGraph(cons,
discreteValueList, discreteProbList, t);
cons.removeFromConstructionList(algoStepGraph);
discreteGraph = algoStepGraph.getOutput(0);
} else {
AlgoBarChart algoBarChart;
if (graphType == GRAPH_LINE) {
GeoNumberValue zeroWidth = new GeoNumeric(cons, 0);
algoBarChart = new AlgoBarChart(cons, discreteValueList,
discreteProbList, zeroWidth);
} else {
GeoNumberValue oneWidth = new GeoNumeric(cons, 1);
algoBarChart = new AlgoBarChart(cons, discreteValueList,
discreteProbList, oneWidth);
}
cons.removeFromConstructionList(algoBarChart);
discreteGraph = algoBarChart.getOutput(0);
}
discreteGraph.setObjColor(colorPDF());
discreteGraph.setAlphaValue(opacityDiscrete);
discreteGraph.setLineThickness(thicknessBarChart);
discreteGraph.setLayer(1);
discreteGraph.setFixed(true);
discreteGraph.setSelectionAllowed(false);
discreteGraph.setEuclidianVisible(true);
plotGeoList.add(discreteGraph);
// ============================
// create lists for the discrete interval graph
// Use Take[] to create a subset of the full discrete graph:
// Take[discreteList, x(lowPoint) + offset, x(highPoint) + offset]
//
// The offset accounts for Sequence[] starting its count at 1 and
// the starting value of the discrete x list. Thus,
// offset = 1 - lowest discrete x value
double firstX = ((GeoNumeric) discreteValueList.get(0)).getDouble();
MyDouble offset = new MyDouble(kernel, 1d - firstX + 0.5);
ExpressionNode low1 = new ExpressionNode(kernel, lowPoint,
Operation.XCOORD, null);
ExpressionNode high1 = new ExpressionNode(kernel, highPoint,
Operation.XCOORD, null);
ExpressionNode lowPlusOffset = new ExpressionNode(kernel, low1,
Operation.PLUS, offset);
ExpressionNode highPlusOffset = new ExpressionNode(kernel, high1,
Operation.PLUS, offset);
AlgoDependentNumber xLow;
AlgoElement xMin;
AlgoElement xMax;
AlgoDependentNumber xHigh = new AlgoDependentNumber(cons,
highPlusOffset, false);
cons.removeFromConstructionList(xHigh);
if (isCumulative) {
// for cumulative bar graphs we only show a single bar
xLow = new AlgoDependentNumber(cons, highPlusOffset, false);
xMin = xLow;
xMax = xLow;
} else {
xLow = new AlgoDependentNumber(cons, lowPlusOffset, false);
xMin = new AlgoMin(cons, xLow.getNumber(), xHigh.getNumber());
xMax = new AlgoMax(cons, xLow.getNumber(), xHigh.getNumber());
}
cons.removeFromConstructionList(xLow);
AlgoTake take = new AlgoTake(cons, discreteValueList,
(GeoNumeric) xMin.getOutput(0),
(GeoNumeric) xMax.getOutput(0));
cons.removeFromConstructionList(take);
intervalValueList = (GeoList) take.getOutput(0);
AlgoTake take2 = new AlgoTake(cons, discreteProbList,
(GeoNumeric) xMin.getOutput(0),
(GeoNumeric) xMax.getOutput(0));
cons.removeFromConstructionList(take2);
intervalProbList = (GeoList) take2.getOutput(0);
// ============================
// create the interval graph
if (isCumulative) {
GeoBoolean t = new GeoBoolean(cons);
t.setValue(true);
AlgoStickGraph algoStickGraph = new AlgoStickGraph(cons,
intervalValueList, intervalProbList, t);
cons.removeFromConstructionList(algoStickGraph);
discreteIntervalGraph = algoStickGraph.getOutput(0);
}
else if (graphType == GRAPH_STEP) {
GeoBoolean t = new GeoBoolean(cons);
t.setValue(true);
AlgoStepGraph algoStepGraph2 = new AlgoStepGraph(cons,
intervalValueList, intervalProbList, t);
cons.removeFromConstructionList(algoStepGraph2);
discreteIntervalGraph = algoStepGraph2.getOutput(0);
} else {
AlgoBarChart barChart;
if (graphType == GRAPH_LINE) {
GeoNumberValue zeroWidth2 = new GeoNumeric(cons, 0d);
barChart = new AlgoBarChart(cons, intervalValueList,
intervalProbList, zeroWidth2);
} else {
GeoNumberValue oneWidth2 = new GeoNumeric(cons, 1);
barChart = new AlgoBarChart(cons, intervalValueList,
intervalProbList, oneWidth2);
}
discreteIntervalGraph = barChart.getOutput(0);
cons.removeFromConstructionList(barChart);
}
if (isCumulative) {
discreteIntervalGraph.setObjColor(GColor.RED);
discreteIntervalGraph.setLineThickness(3);
discreteIntervalGraph
.setLineType(EuclidianStyleConstants.LINE_TYPE_FULL);
} else if (graphType == GRAPH_LINE || graphType == GRAPH_STEP) {
discreteIntervalGraph.setObjColor(COLOR_PDF_FILL);
discreteIntervalGraph.setLineThickness(thicknessBarChart + 2);
} else {
discreteIntervalGraph.setObjColor(COLOR_PDF_FILL);
discreteIntervalGraph.setAlphaValue(opacityDiscreteInterval);
discreteIntervalGraph.setLineThickness(thicknessBarChart);
}
discreteIntervalGraph.setEuclidianVisible(showProbGeos);
discreteIntervalGraph.setLayer(discreteGraph.getLayer() + 1);
discreteIntervalGraph.setFixed(true);
discreteIntervalGraph.setSelectionAllowed(false);
discreteIntervalGraph.updateCascade();
plotGeoList.add(discreteIntervalGraph);
GeoLine axis = new GeoLine(cons);
axis.setCoords(0, 1, 0);
axis.setLayer(4);
axis.setObjColor(app.getEuclidianView1().getAxesColor());
axis.setLineThickness(discreteIntervalGraph.getLineThickness());
axis.setFixed(true);
axis.setSelectionAllowed(false);
axis.updateCascade();
plotGeoList.add(axis);
} else {
// continuous distribution
// ====================================================
// create density curve
densityCurve = buildDensityCurveExpression(selectedDist,
isCumulative);
if (isCumulative && (selectedDist == DIST.F
|| selectedDist == DIST.EXPONENTIAL)) {
pdfCurve = buildDensityCurveExpression(selectedDist, false);
cons.removeFromConstructionList(pdfCurve);
}
densityCurve.setObjColor(colorPDF());
densityCurve.setLineThickness(thicknessCurve);
densityCurve.setFixed(true);
densityCurve.setSelectionAllowed(false);
densityCurve.setEuclidianVisible(true);
plotGeoList.add(densityCurve);
if (hasIntegral) {
GeoBoolean f = new GeoBoolean(cons);
f.setValue(false);
ExpressionNode low1 = new ExpressionNode(kernel, lowPoint,
Operation.XCOORD, null);
ExpressionNode high1 = new ExpressionNode(kernel, highPoint,
Operation.XCOORD, null);
AlgoDependentNumber xLow = new AlgoDependentNumber(cons, low1,
false);
cons.removeFromConstructionList(xLow);
AlgoDependentNumber xHigh = new AlgoDependentNumber(cons, high1,
false);
cons.removeFromConstructionList(xHigh);
AlgoIntegralDefinite algoIntegral = new AlgoIntegralDefinite(
cons, (GeoFunction) densityCurve,
(GeoNumberValue) xLow.getOutput(0),
(GeoNumberValue) xHigh.getOutput(0), f);
cons.removeFromConstructionList(algoIntegral);
integral = algoIntegral.getOutput(0);
integral.setObjColor(COLOR_PDF_FILL);
integral.setAlphaValue(opacityIntegral);
integral.setEuclidianVisible(showProbGeos);
// make sure doesn't interfere with dragging of point
integral.setSelectionAllowed(false);
plotGeoList.add(integral);
}
if (isCumulative) {
// point on curve
GeoFunction f = (GeoFunction) densityCurve;
ExpressionNode highPointX = new ExpressionNode(kernel,
highPoint, Operation.XCOORD, null);
ExpressionNode curveY = new ExpressionNode(kernel, f,
Operation.FUNCTION, highPointX);
MyVecNode curveVec = new MyVecNode(kernel, highPointX, curveY);
ExpressionNode curvePointNode = new ExpressionNode(kernel,
curveVec, Operation.NO_OPERATION, null);
curvePointNode.setForcePoint();
AlgoDependentPoint pAlgo = new AlgoDependentPoint(cons,
curvePointNode, false);
cons.removeFromConstructionList(pAlgo);
curvePoint = (GeoPoint) pAlgo.getOutput(0);
curvePoint.setObjColor(COLOR_POINT);
curvePoint.setPointSize(4);
curvePoint.setLayer(f.getLayer() + 1);
curvePoint.setSelectionAllowed(false);
plotGeoList.add(curvePoint);
// create vertical line segment
ExpressionNode xcoord = new ExpressionNode(kernel, curvePoint,
Operation.XCOORD, null);
MyVecNode vec = new MyVecNode(kernel, xcoord,
new MyDouble(kernel, 0.0));
ExpressionNode point = new ExpressionNode(kernel, vec,
Operation.NO_OPERATION, null);
point.setForcePoint();
AlgoDependentPoint pointAlgo = new AlgoDependentPoint(cons,
point, false);
cons.removeFromConstructionList(pointAlgo);
AlgoJoinPointsSegment seg1 = new AlgoJoinPointsSegment(cons,
curvePoint, (GeoPoint) pointAlgo.getOutput(0), null,
false);
// cons.removeFromConstructionList(seg1);
xSegment = seg1.getOutput(0);
xSegment.setObjColor(GColor.BLUE);
xSegment.setLineThickness(3);
xSegment.setLineType(
EuclidianStyleConstants.LINE_TYPE_DASHED_SHORT);
xSegment.setEuclidianVisible(showProbGeos);
xSegment.setFixed(true);
xSegment.setSelectionAllowed(false);
plotGeoList.add(xSegment);
// create horizontal ray
ExpressionNode ycoord = new ExpressionNode(kernel, curvePoint,
Operation.YCOORD, null);
MyVecNode vecy = new MyVecNode(kernel,
new MyDouble(kernel, 0.0), ycoord);
ExpressionNode pointy = new ExpressionNode(kernel, vecy,
Operation.NO_OPERATION, null);
pointy.setForcePoint();
GeoVector v = new GeoVector(cons);
v.setCoords(-1d, 0d, 1d);
AlgoRayPointVector seg2 = new AlgoRayPointVector(cons,
curvePoint, v);
cons.removeFromConstructionList(seg2);
ySegment = seg2.getOutput(0);
ySegment.setObjColor(GColor.RED);
ySegment.setLineThickness(3);
ySegment.setLineType(EuclidianStyleConstants.LINE_TYPE_FULL);
ySegment.setEuclidianVisible(showProbGeos);
ySegment.setFixed(true);
ySegment.setSelectionAllowed(false);
plotGeoList.add(ySegment);
}
}
if (showNormalOverlay) {
Double[] m = probManager.getDistributionMeasures(selectedDist,
parameters);
if (m[0] != null && m[1] != null) {
normalOverlay = createNormalCurveOverlay(m[0], m[1]);
plotGeoList.add(normalOverlay);
}
}
hideAllGeosFromViews();
// labelAllGeos();
hideToolTips();
}
// =================================================
// Geo Handlers
// =================================================
private GeoElementND createGeoFromString(String text,
boolean suppressLabelCreation) {
try {
// create the geo
// ================================
boolean oldSuppressLabelMode = cons.isSuppressLabelsActive();
if (suppressLabelCreation) {
cons.setSuppressLabelCreation(true);
}
// workaround for eg CmdNormal -> always creates undo point
boolean oldEnableUndo = cons.isUndoEnabled();
cons.setUndoEnabled(false);
GeoElementND[] geos = kernel.getAlgebraProcessor()
.processAlgebraCommandNoExceptions(text, false);
cons.setUndoEnabled(oldEnableUndo);
if (suppressLabelCreation) {
cons.setSuppressLabelCreation(oldSuppressLabelMode);
}
return geos[0];
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private void hideAllGeosFromViews() {
for (GeoElementND geo : plotGeoList) {
hideGeoFromViews(geo.toGeoElement());
}
}
private void hideGeoFromViews(GeoElement geo) {
// add the geo to our view and remove it from EV
geo.addView(getPlotPanel().getViewID());
getPlotPanel().add(geo);
geo.removeView(App.VIEW_EUCLIDIAN);
app.getEuclidianView1().remove(geo);
}
private void hideToolTips() {
for (GeoElementND geo : plotGeoList) {
geo.setTooltipMode(GeoElement.TOOLTIP_OFF);
}
}
/**
* Creates a step function for a discrete distribution.
*
* @param xList
* list with x values
* @param probList
* list with y = P(x) values
* @return AlgoPolyLine implementation of a step function
*/
public AlgoPolyLine createStepFunction(GeoList xList, GeoList probList) {
// Extract x/y coordinates from the lists.
double[] xCoords = new double[xList.size()];
double yCoords[] = new double[probList.size()];
int n = yCoords.length;
for (int i = 0; i < n; i++) {
xCoords[i] = ((GeoNumeric) xList.get(i)).getDouble();
yCoords[i] = ((GeoNumeric) probList.get(i)).getDouble();
}
// Create the PolyLine as:
// (x0, P(x0)),
// (x1, P(x0)), (x1, P(x1)),
// (x2, P(x1)), (x2, P(x2)),
// ...
// (xn-1, P(xn-2), (xn-1, P(xn-1))
GeoPointND[] points = new GeoPoint[2 * n - 1];
boolean suppressLabelCreation = cons.isSuppressLabelsActive();
cons.setSuppressLabelCreation(true);
// first point is special
points[0] = new GeoPoint(cons, null, xCoords[0], yCoords[0], 1.0);
// remaining points
for (int i = 1; i < n; i++) {
points[2 * i - 1] = new GeoPoint(cons, null, xCoords[i],
yCoords[i - 1], 1.0);
points[2 * i] = new GeoPoint(cons, null, xCoords[i], yCoords[i],
1.0);
}
cons.setSuppressLabelCreation(suppressLabelCreation);
// System.out.println("===============================================");
// System.out.println("left border: " + Arrays.toString(xCoords));
// System.out.println("yval: " + Arrays.toString(yCoords));
// System.out.println("polyline points: " + Arrays.toString(points));
AlgoPolyLine polyLine = new AlgoPolyLine(cons, points);
return polyLine;
}
public GeoElement createNormalCurveOverlay(double mean, double sigma) {
AlgoNormalDF algo = new AlgoNormalDF(cons, new GeoNumeric(cons, mean),
new GeoNumeric(cons, sigma),
new GeoBoolean(cons, isCumulative));
cons.removeFromConstructionList(algo);
GeoElement geo = algo.getResult();
geo.setObjColor(COLOR_NORMAL_OVERLAY);
geo.setLineThickness(thicknessCurve - 1);
geo.setEuclidianVisible(true);
geo.setFixed(true);
geo.setSelectionAllowed(false);
return geo;
}
/**
* Returns the appropriate plot dimensions for a given distribution and
* parameter set. Plot dimensions are returned as an array of double: {xMin,
* xMax, yMin, yMax}
*/
protected double[] getPlotDimensions() {
return probManager.getPlotDimensions(selectedDist, parameters,
pdfCurve == null ? densityCurve : pdfCurve, isCumulative);
}
// ============================================================
// Number Format
// ============================================================
/**
* Formats a number string using local format settings.
*/
public String format(double x) {
StringTemplate highPrecision;
// override the default decimal place setting
if (printDecimals >= 0) {
int d = printDecimals < 4 ? 4 : printDecimals;
highPrecision = StringTemplate.printDecimals(StringType.GEOGEBRA, d,
false);
} else {
highPrecision = StringTemplate.printFigures(StringType.GEOGEBRA,
printFigures, false);
}
// get the formatted string
String result = kernel.format(x, highPrecision);
return result;
}
/**
* Calculates and sets the plot dimensions, the axes intervals and the point
* capture style for the the currently selected distribution.
*/
public void updatePlotSettings() {
double xMin, xMax, yMin, yMax;
// get the plot window dimensions
double[] d = getPlotDimensions();
xMin = d[0];
xMax = d[1];
yMin = d[2];
yMax = d[3];
// System.out.println(d[0] + "," + d[1] + "," + d[2] + "," + d[3]);
if (plotSettings == null) {
plotSettings = new PlotSettings();
}
plotSettings.xMin = xMin;
plotSettings.xMax = xMax;
plotSettings.yMin = yMin;
plotSettings.yMax = yMax;
// axes
// plotSettings.showYAxis = probManager.isDiscrete(selectedDist);
plotSettings.showYAxis = isCumulative();
plotSettings.isEdgeAxis[0] = false;
plotSettings.isEdgeAxis[1] = true;
plotSettings.forceXAxisBuffer = true;
if (probManager.isDiscrete(selectedDist)) {
// discrete axis points should jump from point to point
plotSettings.pointCaptureStyle = EuclidianStyleConstants.POINT_CAPTURING_ON_GRID;
// TODO --- need an adaptive setting here for when we have too many
// intervals
plotSettings.gridInterval[0] = 1;
plotSettings.gridIntervalAuto = false;
plotSettings.xAxesIntervalAuto = true;
} else {
plotSettings.pointCaptureStyle = EuclidianStyleConstants.POINT_CAPTURING_OFF;
plotSettings.xAxesIntervalAuto = true;
plotPanelUpdateSettings(plotSettings);
}
plotPanelUpdateSettings(plotSettings);
}
/**
* updates plot panel in subclasses
*/
protected abstract void plotPanelUpdateSettings(PlotSettings settings);
/**
* Adjusts the interval control points to match the current low and high
* values. The low and high values are changeable from the input fields, so
* this method is called after a field change.
*/
public void setXAxisPoints() {
isSettingAxisPoints = true;
lowPoint.setCoords(getLow(), 0.0, 1.0);
highPoint.setCoords(getHigh(), 0.0, 1.0);
getPlotPanel().repaint();
GeoElement.updateCascade(pointList, getTempSet(), false);
tempSet.clear();
if (probManager.isDiscrete(selectedDist)) {
getTable().setSelectionByRowValue((int) getLow(), (int) getHigh());
}
isSettingAxisPoints = false;
}
public void removeGeos() {
if (pointList != null) {
pointList.clear();
}
clearPlotGeoList();
getPlotPanel().clearView();
}
/**
* Creates two GeoLists: discreteProbList and discreteValueList. These store
* the probabilities and values of the currently selected discrete
* distribution.
*/
private void createDiscreteLists() {
ExpressionNode nPlusOne;
AlgoDependentNumber plusOneAlgo;
switch (selectedDist) {
default:
case BINOMIAL:
/*
* n = "Element[" + parmList.getLabel() + ",1]"; p = "Element[" +
* parmList.getLabel() + ",2]";
*
* expr = "Sequence[k,k,0," + n + "]"; discreteValueList = (GeoList)
* createGeoFromString(expr);
*
* expr = "Sequence[BinomialDist[" + n + "," + p + ","; expr +=
* "Element[" + discreteValueList.getLabel() + ",k]," +
* isCumulative; expr += "],k,1," + n + "+ 1 ]";
*
* //System.out.println(expr); discreteProbList = (GeoList)
* createGeoFromString(expr);
*/
GeoNumeric k = new GeoNumeric(cons);
GeoNumeric k2 = new GeoNumeric(cons);
GeoNumeric nGeo = new GeoNumeric(cons, parameters[0]);
GeoNumeric nPlusOneGeo = new GeoNumeric(cons, parameters[0] + 1);
GeoNumeric pGeo = new GeoNumeric(cons, parameters[1]);
AlgoSequence algoSeq = new AlgoSequence(cons, k2, k2,
new GeoNumeric(cons, 0.0), nGeo, null);
discreteValueList = (GeoList) algoSeq.getOutput(0);
AlgoListElement algo = new AlgoListElement(cons, discreteValueList,
k);
cons.removeFromConstructionList(algo);
AlgoBinomialDist algo2 = new AlgoBinomialDist(cons, nGeo, pGeo,
(GeoNumberValue) algo.getOutput(0),
new GeoBoolean(cons, isCumulative));
cons.removeFromConstructionList(algo2);
AlgoSequence algoSeq2 = new AlgoSequence(cons, algo2.getOutput(0),
k, new GeoNumeric(cons, 1.0), nPlusOneGeo, null);
cons.removeFromConstructionList(algoSeq2);
discreteProbList = (GeoList) algoSeq2.getOutput(0);
break;
case PASCAL:
nGeo = new GeoNumeric(cons, parameters[0]);
pGeo = new GeoNumeric(cons, parameters[1]);
k = new GeoNumeric(cons);
k2 = new GeoNumeric(cons);
AlgoInversePascal n2 = new AlgoInversePascal(cons, nGeo, pGeo,
new GeoNumeric(cons, nearlyOne));
cons.removeFromConstructionList(n2);
GeoElementND n2Geo = n2.getOutput(0);
algoSeq = new AlgoSequence(cons, k, k, new GeoNumeric(cons, 0.0),
(GeoNumberValue) n2Geo, null);
removeFromAlgorithmList(algoSeq);
discreteValueList = (GeoList) algoSeq.getOutput(0);
algo = new AlgoListElement(cons, discreteValueList, k2);
cons.removeFromConstructionList(algo);
AlgoPascal algoPascal = new AlgoPascal(cons, nGeo, pGeo,
(GeoNumberValue) algo.getOutput(0),
new GeoBoolean(cons, isCumulative));
cons.removeFromConstructionList(algoPascal);
nPlusOne = new ExpressionNode(kernel, n2Geo, Operation.PLUS,
new MyDouble(kernel, 1.0));
plusOneAlgo = new AlgoDependentNumber(cons, nPlusOne, false);
cons.removeFromConstructionList(plusOneAlgo);
algoSeq2 = new AlgoSequence(cons, algoPascal.getOutput(0), k2,
new GeoNumeric(cons, 1.0),
(GeoNumberValue) plusOneAlgo.getOutput(0), null);
cons.removeFromConstructionList(algoSeq2);
discreteProbList = (GeoList) algoSeq2.getOutput(0);
break;
case POISSON:
GeoNumeric meanGeo = new GeoNumeric(cons, parameters[0]);
k = new GeoNumeric(cons);
k2 = new GeoNumeric(cons);
AlgoInversePoisson maxSequenceValue = new AlgoInversePoisson(cons,
meanGeo, new GeoNumeric(cons, nearlyOne));
cons.removeFromConstructionList(maxSequenceValue);
GeoElement maxDiscreteGeo = maxSequenceValue.getOutput(0);
algoSeq = new AlgoSequence(cons, k, k, new GeoNumeric(cons, 0.0),
(GeoNumberValue) maxDiscreteGeo, null);
removeFromAlgorithmList(algoSeq);
discreteValueList = (GeoList) algoSeq.getOutput(0);
algo = new AlgoListElement(cons, discreteValueList, k2);
cons.removeFromConstructionList(algo);
AlgoPoisson poisson = new AlgoPoisson(cons, meanGeo,
(GeoNumberValue) algo.getOutput(0),
new GeoBoolean(cons, isCumulative));
cons.removeFromConstructionList(poisson);
nPlusOne = new ExpressionNode(kernel, maxDiscreteGeo,
Operation.PLUS, new MyDouble(kernel, 1.0));
plusOneAlgo = new AlgoDependentNumber(cons, nPlusOne, false);
cons.removeFromConstructionList(plusOneAlgo);
algoSeq2 = new AlgoSequence(cons, poisson.getOutput(0), k2,
new GeoNumeric(cons, 1.0),
(GeoNumberValue) plusOneAlgo.getOutput(0), null);
cons.removeFromConstructionList(algoSeq2);
discreteProbList = (GeoList) algoSeq2.getOutput(0);
break;
case HYPERGEOMETRIC:
/*
* p = "" + parameters[0]; // population size n = "" +
* parameters[1]; // n s = "" + parameters[2]; // sample size
*
* expr = "Sequence[k,k,0," + n + "]"; discreteValueList = (GeoList)
* createGeoFromString(expr);
*
* expr = "Sequence[HyperGeometric[" + p + "," + n + "," + s + ",";
* expr += "Element[" + discreteValueList.getLabel() + ",k]," +
* isCumulative; expr += "],k,1," + n + "+ 1 ]";
*
* //System.out.println(expr); discreteProbList = (GeoList)
* createGeoFromString(expr);
*/
double p = parameters[0]; // population size
double n = parameters[1]; // n
double s = parameters[2]; // sample size
// ================================================
// interval bounds:
// [ max(0, n + s - p) , min(n, s) ]
// =================================================
double lowBound = Math.max(0, n + s - p);
double highBound = Math.min(n, s);
double length = highBound - lowBound + 1;
GeoNumeric lowGeo = new GeoNumeric(cons, lowBound);
GeoNumeric highGeo = new GeoNumeric(cons, highBound);
GeoNumeric lengthGeo = new GeoNumeric(cons, length);
pGeo = new GeoNumeric(cons, p);
nGeo = new GeoNumeric(cons, n);
GeoNumeric sGeo = new GeoNumeric(cons, s);
k = new GeoNumeric(cons);
k2 = new GeoNumeric(cons);
algoSeq = new AlgoSequence(cons, k, k, lowGeo, highGeo, null);
removeFromAlgorithmList(algoSeq);
discreteValueList = (GeoList) algoSeq.getOutput(0);
algo = new AlgoListElement(cons, discreteValueList, k2);
cons.removeFromConstructionList(algo);
AlgoHyperGeometric hyperGeometric = new AlgoHyperGeometric(cons,
pGeo, nGeo, sGeo, (GeoNumberValue) algo.getOutput(0),
new GeoBoolean(cons, isCumulative));
cons.removeFromConstructionList(hyperGeometric);
algoSeq2 = new AlgoSequence(cons, hyperGeometric.getOutput(0), k2,
new GeoNumeric(cons, 1.0), lengthGeo, null);
cons.removeFromConstructionList(algoSeq2);
discreteProbList = (GeoList) algoSeq2.getOutput(0);
break;
}
plotGeoList.add(discreteProbList);
discreteProbList.setEuclidianVisible(true);
discreteProbList.setAuxiliaryObject(true);
discreteProbList.setLabelVisible(false);
discreteProbList.setFixed(true);
discreteProbList.setSelectionAllowed(false);
}
private void clearPlotGeoList() {
for (GeoElementND geo : plotGeoList) {
if (geo != null) {
geo.setFixed(false);
geo.remove();
}
}
plotGeoList.clear();
}
private TreeSet<AlgoElement> tempSet;
private TreeSet<AlgoElement> getTempSet() {
if (tempSet == null) {
tempSet = new TreeSet<AlgoElement>();
}
return tempSet;
}
/**
* Exports all GeoElements that are currently displayed in this panel to a
* target EuclidianView.
*
* @param euclidianViewID
* viewID of the target EuclidianView
*/
public void exportGeosToEV(int euclidianViewID) {
app.setWaitCursor();
ArrayList<GeoElementND> newGeoList = new ArrayList<GeoElementND>();
String expr;
try {
app.storeUndoInfo();
// some commented out code removed 2012-3-1
// create low point
expr = "Point[" + loc.getPlain("xAxis") + "]";
GeoPoint lowPointCopy = (GeoPoint) createGeoFromString(expr, false);
lowPointCopy.setVisualStyle(lowPoint);
lowPointCopy.setLabelVisible(false);
lowPointCopy.setCoords(getLow(), 0, 1);
lowPointCopy.setLabel(null);
newGeoList.add(lowPointCopy);
// create high point
GeoPoint highPointCopy = (GeoPoint) createGeoFromString(expr,
false);
highPointCopy.setVisualStyle(lowPoint);
highPointCopy.setLabelVisible(false);
highPointCopy.setCoords(getHigh(), 0, 1);
highPointCopy.setLabel(null);
newGeoList.add(highPointCopy);
StringTemplate tpl = StringTemplate.maxPrecision;
// create discrete bar charts and associated lists
if (probManager.isDiscrete(selectedDist)) {
// create full bar chart
// ============================
GeoElement discreteProbListCopy = discreteProbList.copy();
newGeoList.add(discreteProbListCopy);
GeoElement discreteValueListCopy = discreteValueList.copy();
newGeoList.add(discreteValueList);
if (graphType == GRAPH_LINE) {
expr = "BarChart["
+ discreteValueListCopy
.getLabel(StringTemplate.maxPrecision)
+ "," + discreteProbListCopy.getLabel(
StringTemplate.maxPrecision)
+ ",0]";
} else if (graphType == GRAPH_BAR) {
expr = "BarChart["
+ discreteValueListCopy
.getLabel(StringTemplate.maxPrecision)
+ "," + discreteProbListCopy.getLabel(
StringTemplate.maxPrecision)
+ ",1]";
} else if (graphType == GRAPH_STEP) {
expr = "StepGraph["
+ discreteValueListCopy
.getLabel(StringTemplate.maxPrecision)
+ "," + discreteProbListCopy.getLabel(
StringTemplate.maxPrecision)
+ ",true]";
}
GeoElementND discreteGraphCopy = createGeoFromString(expr,
false);
discreteGraphCopy.setLabel(null);
discreteGraphCopy.setVisualStyle(discreteGraph.toGeoElement());
newGeoList.add(discreteGraphCopy);
// create interval bar chart
// ============================
double offset = 1
- ((GeoNumeric) discreteValueList.get(0)).getDouble()
+ 0.5;
expr = "Take[" + discreteProbListCopy.getLabel(tpl) + ", x("
+ lowPointCopy.getLabel(tpl) + ")+" + offset + ", x("
+ highPointCopy.getLabel(tpl) + ")+" + offset + "]";
GeoElementND intervalProbList1 = createGeoFromString(expr,
false);
newGeoList.add(intervalProbList1);
expr = "Take[" + discreteValueListCopy.getLabel(tpl) + ", x("
+ lowPointCopy.getLabel(tpl) + ")+" + offset + ", x("
+ highPointCopy.getLabel(tpl) + ")+" + offset + "]";
GeoElementND intervalValueList1 = createGeoFromString(expr,
false);
newGeoList.add(intervalValueList1);
if (graphType == GRAPH_LINE) {
expr = "BarChart[" + intervalValueList1.getLabel(tpl) + ","
+ intervalProbList1.getLabel(tpl) + ",0]";
} else if (graphType == GRAPH_STEP) {
expr = "StepGraph[" + intervalValueList1.getLabel(tpl) + ","
+ intervalProbList1.getLabel(tpl) + ",true]";
} else {
expr = "BarChart[" + intervalValueList1.getLabel(tpl) + ","
+ intervalProbList1.getLabel(tpl) + ",1]";
}
GeoElementND discreteIntervalGraphCopy = createGeoFromString(
expr, false);
discreteIntervalGraphCopy.setLabel(null);
discreteIntervalGraphCopy.setVisualStyle(discreteIntervalGraph);
newGeoList.add(discreteIntervalGraphCopy);
}
// create density curve and integral
else {
// density curve
GeoElement densityCurveCopy = densityCurve.copyInternal(cons);
densityCurveCopy.setLabel(null);
densityCurveCopy.setVisualStyle(densityCurve);
newGeoList.add(densityCurveCopy);
// integral
if (!isCumulative) {
expr = "Integral[" + densityCurveCopy.getLabel(tpl) + ", x("
+ lowPointCopy.getLabel(tpl) + "), x("
+ highPointCopy.getLabel(tpl) + ") , true ]";
GeoElementND integralCopy = createGeoFromString(expr,
false);
integralCopy.setVisualStyle(integral);
integralCopy.setLabel(null);
newGeoList.add(integralCopy);
}
}
// normal overlay
if (showNormalOverlay) {
GeoElement normalOverlayCopy = normalOverlay.copyInternal(cons);
normalOverlayCopy.setLabel(null);
normalOverlayCopy.setVisualStyle(normalOverlay);
newGeoList.add(normalOverlayCopy);
}
// set the EV location and auxiliary = false for all of the new geos
for (GeoElementND geo : newGeoList) {
geo.setAuxiliaryObject(false);
if (euclidianViewID == App.VIEW_EUCLIDIAN) {
geo.addView(App.VIEW_EUCLIDIAN);
geo.removeView(App.VIEW_EUCLIDIAN2);
geo.update();
} else if (euclidianViewID == App.VIEW_EUCLIDIAN2) {
geo.addView(App.VIEW_EUCLIDIAN2);
geo.removeView(App.VIEW_EUCLIDIAN);
geo.update();
}
}
// set the window dimensions of the target EV to match the prob calc
// dimensions
EuclidianView ev = (EuclidianView) app.getView(euclidianViewID);
ev.setRealWorldCoordSystem(plotSettings.xMin, plotSettings.xMax,
plotSettings.yMin, plotSettings.yMax);
ev.setAutomaticAxesNumberingDistance(plotSettings.xAxesIntervalAuto,
0);
ev.setAutomaticAxesNumberingDistance(plotSettings.yAxesIntervalAuto,
1);
if (!plotSettings.xAxesIntervalAuto) {
ev.setAxesNumberingDistance(
new GeoNumeric(cons, plotSettings.xAxesInterval), 0);
}
if (!plotSettings.yAxesIntervalAuto) {
ev.setAxesNumberingDistance(
new GeoNumeric(cons, plotSettings.yAxesInterval), 1);
}
ev.updateBackground();
// remove the new geos from our temporary list
newGeoList.clear();
} catch (Exception e) {
e.printStackTrace();
app.setDefaultCursor();
}
app.setDefaultCursor();
}
@Override
public int getViewID() {
return App.VIEW_PROBABILITY_CALCULATOR;
}
@Override
public void settingsChanged(AbstractSettings settings) {
ProbabilityCalculatorSettings pcSettings = (ProbabilityCalculatorSettings) settings;
setProbabilityCalculator(pcSettings.getDistributionType(),
pcSettings.getParameters(), pcSettings.isCumulative());
if (pcSettings.isIntervalSet()) {
this.probMode = pcSettings.getProbMode();
this.setInterval(pcSettings.getLow(), pcSettings.getHigh());
}
}
protected abstract void setInterval(double low2, double high2);
@Override
public void add(GeoElement geo) {
// view dows not handle external geos
}
@Override
public void updatePreviewFromInputBar(GeoElement[] geos) {
// view dows not handle external geos
}
@Override
public void remove(GeoElement geo) {
// view dows not handle external geos
}
@Override
public void rename(GeoElement geo) {
// view dows not handle external geos
}
// Handles user point changes in the EV plot panel
@Override
public void update(GeoElement geo) {
if (!isSettingAxisPoints && !isIniting) {
if (lowPoint != null && highPoint != null
&& lowPoint.getInhomX() > highPoint.getInhomX()) {
GeoPoint swap = lowPoint;
lowPoint = highPoint;
highPoint = swap;
}
if (geo.equals(lowPoint)) {
if (isValidInterval(probMode, lowPoint.getInhomX(),
getHigh())) {
setLow(lowPoint.getInhomX());
updateIntervalProbability();
updateGUI();
if (probManager.isDiscrete(selectedDist)) {
getTable().setSelectionByRowValue((int) getLow(),
(int) getHigh());
}
} else {
setXAxisPoints();
}
}
if (geo.equals(highPoint)) {
if (isValidInterval(probMode, getLow(),
highPoint.getInhomX())) {
setHigh(highPoint.getInhomX());
updateIntervalProbability();
updateGUI();
if (probManager.isDiscrete(selectedDist)) {
getTable().setSelectionByRowValue((int) getLow(),
(int) getHigh());
}
} else {
setXAxisPoints();
}
}
updateRounding();
}
// statCalculator.updateResult();
}
/**
* Returns an interval probability for the currently selected distribution
* and probability mode. If mode == PROB_INTERVAL then P(low <= X <= high)
* is returned. If mode == PROB_LEFT then P(low <= X) is returned. If mode
* == PROB_RIGHT then P(X <= high) is returned.
*/
protected double intervalProbability() {
return probManager.intervalProbability(getLow(), getHigh(),
selectedDist, parameters, probMode);
}
/**
* Returns an inverse probability for a selected distribution.
*
* @param prob
*/
protected double inverseProbability(double prob) {
return probManager.inverseProbability(selectedDist, prob, parameters);
}
/**
* @return probability formatted as String
*/
protected String getProbabilityText() {
return probability >= 0 ? format(probability) : "?";
}
protected void updateIntervalProbability() {
probability = intervalProbability();
if (probmanagerIsDiscrete()) {
this.discreteIntervalGraph.updateCascade();
} else if (hasIntegral) {
this.integral.updateCascade();
}
}
protected boolean isValidInterval(int probMode, double xLow, double xHigh) {
if (probMode == PROB_INTERVAL && xHigh < xLow) {
return false;
}
// don't allow non-integer bounds for discrete dist.
if (probManager.isDiscrete(selectedDist)
&& (Math.floor(xLow) != xLow || Math.floor(xHigh) != xHigh)) {
return false;
}
boolean isValid = true;
switch (selectedDist) {
default:
Log.debug("Unknown distribution.");
return true;
case NORMAL:
return true;
case BINOMIAL:
case HYPERGEOMETRIC:
isValid = xLow >= getDiscreteXMin() && xHigh <= getDiscreteXMax();
break;
case POISSON:
case PASCAL:
isValid = xLow >= getDiscreteXMin();
break;
case CHISQUARE:
case EXPONENTIAL:
if (probMode != PROB_LEFT) {
isValid = xLow >= 0;
}
break;
case F:
if (probMode != PROB_LEFT) {
isValid = xLow > 0;
}
break;
}
return isValid;
}
protected boolean isValidParameter(double parameter, int index) {
boolean[] isValid = { true, true, true };
switch (selectedDist) {
default:
Log.debug("Unknown distribution");
return true;
case NORMAL:
return true;
case F:
case STUDENT:
case EXPONENTIAL:
case WEIBULL:
case POISSON:
if (index == 0) {
// all parameters must be positive
isValid[0] = parameter > 0;
}
break;
case CAUCHY:
case LOGISTIC:
if (index == 1) {
// scale must be positive
isValid[1] = index == 1 && parameter > 0;
}
break;
case CHISQUARE:
if (index == 0) {
// df >= 1, integer
isValid[0] = Math.floor(parameter) == parameter
&& parameter >= 1;
}
break;
case BINOMIAL:
if (index == 0) {
// n >= 0, integer
isValid[0] = Math.floor(parameter) == parameter
&& parameter >= 0;
} else if (index == 1) {
// p is probability value
isValid[1] = parameter >= 0 && parameter <= 1;
}
break;
case PASCAL:
if (index == 0) {
// n >= 1, integer
isValid[0] = Math.floor(parameter) == parameter
&& parameter >= 1;
} else if (index == 1) {
// p is probability value
isValid[1] = index == 1 && parameter >= 0 && parameter <= 1;
}
break;
case HYPERGEOMETRIC:
if (index == 0) {
// population size: N >= 1, integer
isValid[0] = index == 0 && Math.floor(parameter) == parameter
&& parameter >= 1;
} else if (index == 1) {
// successes in the population: n >= 0 and <= N, integer
isValid[1] = index == 1 && Math.floor(parameter) == parameter
&& parameter >= 0 && parameter <= parameters[0];
} else if (index == 2) {
// sample size: s>= 1 and s<= N, integer
isValid[2] = index == 2 && Math.floor(parameter) == parameter
&& parameter >= 1 && parameter <= parameters[0];
}
break;
// these distributions have no parameter restrictions
// case DIST.NORMAL:
// case DIST.LOGNORMAL:
}
return isValid[0] && isValid[1] && isValid[2];
}
/**
* Adjust local rounding constants to match global rounding constants and
* update GUI when needed
*/
private void updateRounding() {
if (kernel.useSignificantFigures) {
if (printFigures != kernel.getPrintFigures()) {
printFigures = kernel.getPrintFigures();
printDecimals = -1;
updateDiscreteTable();
updateGUI();
}
} else if (printDecimals != kernel.getPrintDecimals()) {
printDecimals = kernel.getPrintDecimals();
updateDiscreteTable();
updateGUI();
}
}
protected abstract void updateDiscreteTable();
protected abstract void updateGUI();
protected boolean probmanagerIsDiscrete() {
return probManager.isDiscrete(selectedDist);
}
protected int[] generateFirstXLastXCommon() {
int firstXLastX[] = new int[2];
if (discreteValueList == null) {
this.createDiscreteLists();
}
firstXLastX[0] = (int) ((GeoNumeric) discreteValueList.get(0))
.getDouble();
firstXLastX[1] = (int) ((GeoNumeric) discreteValueList
.get(discreteValueList.size() - 1)).getDouble();
return firstXLastX;
}
@Override
final public void updateVisualStyle(GeoElement geo, GProperty prop) {
update(geo);
}
public void attachView() {
// clearView();
// kernel.notifyAddAll(this);
kernel.attach(this);
}
public void detachView() {
removeGeos();
kernel.detach(this);
// plotPanel.detachView();
// clearView();
// kernel.notifyRemoveAll(this);
}
@Override
public void updateAuxiliaryObject(GeoElement geo) {
// not needed for prob. calc
}
@Override
public void repaintView() {
// not needed for prob. calc
}
@Override
public void reset() {
// not needed for prob. calc
}
@Override
public void clearView() {
// TODO Auto-generated method stub
}
@Override
public void setMode(int mode, ModeSetter m) {
// not needed for prob. calc
}
@Override
public boolean hasFocus() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isShowing() {
return app.showView(App.VIEW_PROBABILITY_CALCULATOR);
}
public boolean doRemoveFromConstruction() {
return removeFromConstruction;
}
public void setRemoveFromConstruction(boolean removeFromConstruction) {
this.removeFromConstruction = removeFromConstruction;
}
private void removeFromAlgorithmList(AlgoElement algo) {
if (removeFromConstruction) {
cons.removeFromAlgorithmList(algo);
}
}
/**
* Builds a string that can be used by the algebra processor to create a
* GeoFunction representation of a given density curve.
*
* @param distType
* @param parms
* @return
*/
private GeoFunction buildDensityCurveExpression(DIST type,
boolean cumulative) {
GeoNumeric param1 = null, param2 = null;
if (parameters.length > 0) {
param1 = new GeoNumeric(cons, parameters[0]);
}
if (parameters.length > 1) {
param2 = new GeoNumeric(cons, parameters[1]);
}
AlgoDistributionDF ret = null;
GeoBoolean cumulativeGeo = new GeoBoolean(cons, cumulative);
switch (type) {
case NORMAL:
ret = new AlgoNormalDF(cons, param1, param2, cumulativeGeo);
break;
case STUDENT:
ret = new AlgoTDistributionDF(cons, param1, cumulativeGeo);
break;
case CHISQUARE:
ret = new AlgoChiSquaredDF(cons, param1, cumulativeGeo);
break;
case F:
ret = new AlgoFDistributionDF(cons, param1, param2, cumulativeGeo);
break;
case CAUCHY:
ret = new AlgoCauchyDF(cons, param1, param2, cumulativeGeo);
break;
case EXPONENTIAL:
ret = new AlgoExponentialDF(cons, param1, cumulativeGeo);
break;
case GAMMA:
ret = new AlgoGammaDF(cons, param1, param2, cumulativeGeo);
break;
case WEIBULL:
ret = new AlgoWeibullDF(cons, param1, param2, cumulativeGeo);
break;
case LOGNORMAL:
ret = new AlgoLogNormalDF(cons, param1, param2, cumulativeGeo);
break;
case LOGISTIC:
ret = new AlgoLogisticDF(cons, param1, param2, cumulativeGeo);
break;
case BINOMIAL:
case PASCAL:
case POISSON:
case HYPERGEOMETRIC:
Log.error("Not continuous distribution");
break;
default:
Log.error("Missing case for density curve");
}
if (ret != null) {
cons.removeFromConstructionList((AlgoElement) ret);
return ret.getResult();
}
return null;
}
// ============================================================
// XML
// ============================================================
/**
* returns settings in XML format
*/
public void getXML(StringBuilder sb) {
if (selectedDist == null) {
return;
}
sb.append("<probabilityCalculator>\n");
sb.append("\t<distribution");
sb.append(" type=\"");
sb.append(selectedDist.ordinal());
sb.append("\"");
sb.append(" isCumulative=\"");
sb.append(isCumulative ? "true" : "false");
sb.append("\"");
sb.append(" parameters" + "=\"");
for (int i = 0; i < parameters.length; i++) {
sb.append(parameters[i]);
sb.append(",");
}
sb.deleteCharAt(sb.lastIndexOf(","));
sb.append("\"");
sb.append("/>\n");
sb.append("\t<interval");
sb.append(" mode=\"");
sb.append(this.probMode);
sb.append("\"");
sb.append(" low=\"");
sb.append(getLow());
sb.append("\"");
sb.append(" high=\"");
sb.append(getHigh());
sb.append("\"");
sb.append("/>\n");
sb.append("</probabilityCalculator>\n");
}
@Override
public void startBatchUpdate() {
// TODO Auto-generated method stub
}
@Override
public void endBatchUpdate() {
// TODO Auto-generated method stub
}
public String getMeanSigma() {
Double[] val = probManager.getDistributionMeasures(selectedDist,
parameters);
// mean/sigma are undefined for the Cauchy distribution
// and F-distribution with certain parameters
String mean = val[0] == null ? "?" : format(val[0]);
String sigma = val[1] == null ? "?" : format(val[1]);
String meanSigmaStr = Unicode.mu + " = " + mean + " " + Unicode.sigma
+ " = " + sigma;
return meanSigmaStr;
}
protected void setHigh(double high) {
this.high = high;
}
protected void setLow(double low) {
this.low = low;
}
public boolean isOverlayDefined() {
return !((selectedDist == DIST.CAUCHY)
|| (selectedDist == DIST.F && parameters[1] < 4));
}
protected HashMap<DIST, String> getDistributionMap() {
return distributionMap;
}
protected void setDistributionMap(HashMap<DIST, String> distributionMap) {
this.distributionMap = distributionMap;
}
protected HashMap<String, DIST> getReverseDistributionMap() {
return reverseDistributionMap;
}
protected void setReverseDistributionMap(
HashMap<String, DIST> reverseDistributionMap) {
this.reverseDistributionMap = reverseDistributionMap;
}
protected String[][] getParameterLabels() {
return parameterLabels;
}
protected void setParameterLabels(String[][] parameterLabels) {
this.parameterLabels = parameterLabels;
}
public abstract ProbabilityManager getProbManager();
public EuclidianView getPlotPanel() {
return plotPanel;
}
public void setPlotPanel(EuclidianView plotPanel) {
this.plotPanel = plotPanel;
}
protected ProbabilityTable getTable() {
return table;
}
protected void setTable(ProbabilityTable table) {
this.table = table;
}
}