| /******************************************************************************* |
| * Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Pierre Allard, |
| * Regent L'Archeveque, |
| * Sebastien Gemme - initial API and implementation |
| * |
| * SPDX-License-Identifier: EPL-1.0 |
| * |
| *******************************************************************************/ |
| package org.eclipse.apogy.common.math.statistics.impl; |
| |
| import java.util.Collections; |
| |
| import org.eclipse.apogy.common.math.statistics.ApogyCommonMathStatisticsPackage; |
| import org.eclipse.apogy.common.math.statistics.Population; |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.Notifier; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.util.EDataTypeEList; |
| |
| public class PopulationCustomImpl extends PopulationImpl { |
| |
| private boolean averageDirty = true; |
| private boolean sumDirty = true; |
| private boolean medianDirty = true; |
| private boolean sumSquaredDirty = true; |
| private boolean stdDirty = true; |
| private boolean isDirty = true; |
| // private boolean isMinMaxDirty = true; |
| |
| private Adapter populationListener; |
| |
| protected PopulationCustomImpl() { |
| super(); |
| this.eAdapters().add(getPopulationListener()); |
| } |
| |
| @Override |
| @SuppressWarnings("serial") |
| public EList<Double> getData() { |
| if (this.data == null) { |
| this.data = new EDataTypeEList<Double>(Double.class, this, |
| ApogyCommonMathStatisticsPackage.POPULATION__DATA) { |
| @Override |
| protected boolean isUnique() { |
| return false; |
| } |
| }; |
| } |
| |
| return this.data; |
| } |
| |
| @Override |
| public double getStandardDeviation() { |
| |
| if (this.stdDirty) { |
| if (getData().isEmpty()) { |
| this.standardDeviation = 0.0; |
| } else { |
| double averageEltSquared = getSumSquared() / getData().size(); |
| double averageSquared = getAverage() * getAverage(); |
| |
| this.standardDeviation = Math.sqrt(averageEltSquared - averageSquared); |
| } |
| this.stdDirty = false; |
| } |
| |
| return this.standardDeviation; |
| } |
| |
| @Override |
| public double getAverage() { |
| |
| if (this.averageDirty) { |
| // If population is empty, average is 0.0. |
| if (getData().isEmpty()) { |
| this.average = 0.0; |
| } else { |
| this.average = getSum() / getData().size(); |
| } |
| this.averageDirty = false; |
| } |
| |
| return this.average; |
| } |
| |
| @Override |
| public double getSum() { |
| if (this.sumDirty) { |
| this.sum = 0.0; |
| |
| for (Double element : getData()) { |
| this.sum += element.doubleValue(); |
| } |
| |
| this.sumDirty = false; |
| } |
| return this.sum; |
| } |
| |
| @Override |
| public double getMedian() { |
| |
| sort(); |
| |
| if (this.medianDirty) { |
| |
| int middle = getData().size() / 2; |
| |
| this.median = getData().get(middle).doubleValue(); |
| |
| this.medianDirty = false; |
| } |
| |
| return this.median; |
| } |
| |
| @Override |
| public double getSumSquared() { |
| |
| if (this.sumSquaredDirty) { |
| |
| this.sumSquared = 0.0; |
| |
| for (Double element : getData()) { |
| double eltSquared = element.doubleValue() * element.doubleValue(); |
| |
| this.sumSquared += eltSquared; |
| } |
| |
| this.sumSquaredDirty = false; |
| } |
| |
| return this.sumSquared; |
| } |
| |
| @Override |
| public double getVariance() { |
| |
| this.variance = getStandardDeviation() * getStandardDeviation(); |
| |
| return this.variance; |
| } |
| |
| @Override |
| public double getMin() { |
| |
| sort(); |
| |
| if (getData().size() == 0) { |
| return Double.MAX_VALUE; |
| } else { |
| return getData().get(0).doubleValue(); |
| } |
| } |
| |
| @Override |
| public double getMax() { |
| |
| sort(); |
| |
| if (getData().size() == 0) { |
| return Double.MIN_VALUE; |
| } else { |
| int size = getData().size(); |
| return getData().get(size - 1).doubleValue(); |
| } |
| } |
| |
| private Adapter getPopulationListener() { |
| if (this.populationListener == null) { |
| this.populationListener = new Adapter() { |
| |
| @Override |
| public Notifier getTarget() { |
| return null; |
| } |
| |
| @Override |
| public boolean isAdapterForType(Object type) { |
| return false; |
| } |
| |
| @Override |
| public void notifyChanged(Notification notification) { |
| |
| if (notification.getNotifier() instanceof Population) { |
| |
| int featureID = notification.getFeatureID(Population.class); |
| |
| if (featureID == ApogyCommonMathStatisticsPackage.POPULATION__DATA) { |
| if (!notification.isTouch()) { |
| PopulationCustomImpl.this.averageDirty = true; |
| PopulationCustomImpl.this.sumDirty = true; |
| PopulationCustomImpl.this.medianDirty = true; |
| PopulationCustomImpl.this.sumSquaredDirty = true; |
| PopulationCustomImpl.this.stdDirty = true; |
| PopulationCustomImpl.this.isDirty = true; |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void setTarget(Notifier newTarget) { |
| |
| } |
| |
| }; |
| } |
| return this.populationListener; |
| } |
| |
| @Override |
| protected void finalize() throws Throwable { |
| super.finalize(); |
| |
| this.eAdapters().remove(getPopulationListener()); |
| } |
| |
| private void sort() { |
| if (this.isDirty) { |
| Collections.sort(getData()); |
| this.isDirty = false; |
| } |
| } |
| |
| } // PopulationImpl |