/* 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.statistics; import java.util.ArrayList; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.algos.AlgoElement; 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.GeoList; import org.geogebra.common.kernel.geos.GeoNumberValue; /** * Sample from a list. Adapted from AlgoMode * * @author Michael Borcherds */ public class AlgoSample extends AlgoElement { // maximum size for a sample private static int SAMPLE_MAXSIZE = 10000; private GeoList inputList; // input private GeoBoolean replacement; private GeoNumberValue num; private GeoList outputList; // output public AlgoSample(Construction cons, String label, GeoList inputList, GeoNumberValue num, GeoBoolean replacement) { super(cons); this.inputList = inputList; this.replacement = replacement; this.num = num; outputList = new GeoList(cons); setInputOutput(); compute(); outputList.setLabel(label); } @Override public Commands getClassName() { return Commands.Sample; } @Override protected void setInputOutput() { input = new GeoElement[replacement == null ? 2 : 3]; input[0] = inputList; input[1] = num.toGeoElement(); if (replacement != null) { input[2] = replacement; } setOutputLength(1); setOutput(0, outputList); setDependencies(); // done by AlgoElement } public GeoList getResult() { return outputList; } @Override public final void compute() { int size = (int) num.getDouble(); if (!inputList.isDefined() || num.getDouble() < 1 || num.getDouble() > SAMPLE_MAXSIZE) { outputList.setUndefined(); return; } boolean withReplacement = true; if (replacement != null) { withReplacement = replacement.getBoolean(); } int inputListSize = inputList.size(); outputList.clear(); if (withReplacement) { for (int i = 0; i < size; i++) { GeoElement geo; geo = inputList.get((int) Math .floor(cons.getApplication().getRandomNumber() * inputListSize)); setListElement(i, geo); } } else { // sampling without replacement if (size > inputListSize) { outputList.setUndefined(); return; } ArrayList<GeoElement> list = new ArrayList<GeoElement>(); // copy inputList into arraylist for (int i = 0; i < inputListSize; i++) { list.add(inputList.get(i)); } // copy the geos back into a GeoList in a random order for (int i = 0; i < size; i++) { int pos = (int) Math .floor(cons.getApplication().getRandomNumber() * (inputListSize - i)); outputList.add(list.get(pos)); list.remove(pos); } } outputList.setDefined(true); } // copied from AlgoIterationList.java // TODO should it be centralised? private void setListElement(int index, GeoElement geo) { GeoElement listElement; if (index < outputList.getCacheSize()) { // use existing list element listElement = outputList.getCached(index); listElement.set(geo); } else { // create a new list element listElement = geo.copy(); listElement.setParentAlgorithm(this); listElement.setConstructionDefaults(); listElement.setUseVisualDefaults(false); } outputList.add(listElement); } }