/***************************************************************************** * Limpet - the Lightweight InforMation ProcEssing Toolkit * http://limpet.info * * (C) 2015-2016, Deep Blue C Technologies Ltd * * This library is free software; you can redistribute it and/or * modify it under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html) * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ package info.limpet.data.operations.arithmetic; import info.limpet.ICommand; import info.limpet.IContext; import info.limpet.IOperation; import info.limpet.IQuantityCollection; import info.limpet.IStore; import info.limpet.ITemporalQuantityCollection; import info.limpet.ITemporalQuantityCollection.InterpMethod; import java.util.Collection; import java.util.List; import javax.measure.Measurable; import javax.measure.quantity.Quantity; public class SubtractQuantityOperation<Q extends Quantity> extends CoreQuantityOperation<Q> implements IOperation<IQuantityCollection<Q>> { public SubtractQuantityOperation() { super(); } @Override protected boolean appliesTo(List<IQuantityCollection<Q>> selection) { if (getATests().exactNumber(selection, 2) && getATests().allCollections(selection)) { boolean allQuantity = getATests().allQuantity(selection); boolean suitableLength = getATests().allTemporal(selection) || getATests().allEqualLengthOrSingleton(selection); boolean equalDimensions = getATests().allEqualDimensions(selection); return allQuantity && suitableLength && equalDimensions; } else { return false; } } @Override protected void addInterpolatedCommands( List<IQuantityCollection<Q>> selection, IStore destination, Collection<ICommand<IQuantityCollection<Q>>> res, IContext context) { ITemporalQuantityCollection<Q> longest = getLongestTemporalCollections(selection); if (longest != null) { IQuantityCollection<Q> item1 = selection.get(0); IQuantityCollection<Q> item2 = selection.get(1); ICommand<IQuantityCollection<Q>> newC = new SubtractQuantityValues("Subtract " + item2.getName() + " from " + item1.getName() + " (interpolated)", selection, item1, item2, destination, longest, context); res.add(newC); newC = new SubtractQuantityValues("Subtract " + item1.getName() + " from " + item2.getName() + " (interpolated)", selection, item2, item1, destination, longest, context); res.add(newC); } } protected void addIndexedCommands(List<IQuantityCollection<Q>> selection, IStore destination, Collection<ICommand<IQuantityCollection<Q>>> res, IContext context) { IQuantityCollection<Q> item1 = selection.get(0); IQuantityCollection<Q> item2 = selection.get(1); ICommand<IQuantityCollection<Q>> newC = new SubtractQuantityValues("Subtract " + item2.getName() + " from " + item1.getName() + " (indexed)", selection, item1, item2, destination, context); res.add(newC); newC = new SubtractQuantityValues("Subtract " + item1.getName() + " from " + item2.getName() + " (indexed)", selection, item2, item1, destination, context); res.add(newC); } public class SubtractQuantityValues extends CoreQuantityCommand { private final IQuantityCollection<Q> _item1; private final IQuantityCollection<Q> _item2; public SubtractQuantityValues(String title, List<IQuantityCollection<Q>> selection, IQuantityCollection<Q> item1, IQuantityCollection<Q> item2, IStore store, IContext context) { this(title, selection, item1, item2, store, null, context); } public SubtractQuantityValues(String title, List<IQuantityCollection<Q>> selection, IQuantityCollection<Q> item1, IQuantityCollection<Q> item2, IStore store, ITemporalQuantityCollection<Q> timeProvider, IContext context) { super(title, "Subtract provided series", store, false, false, selection, timeProvider, context); _item1 = item1; _item2 = item2; } @Override protected String getOutputName() { return getContext().getInput("Subtract dataset", NEW_DATASET_MESSAGE, _item2.getName() + " from " + _item1.getName()); } @Override protected Double calcThisElement(int elementCount) { final Measurable<Q> thisValue = _item1.getValuesCount() == 1 ? _item1.getValues().get(0) : _item1.getValues() .get(elementCount); final Measurable<Q> otherValue = _item2.getValuesCount() == 1 ? _item2.getValues().get(0) : _item2.getValues() .get(elementCount); double runningTotal = thisValue.doubleValue(_item1.getUnits()) - otherValue.doubleValue(_item2.getUnits()); return runningTotal; } @Override protected Double calcThisInterpolatedElement(long time) { final Measurable<Q> thisValue; final Measurable<Q> otherValue; if (_item1.isTemporal()) { ITemporalQuantityCollection<Q> tqc1 = (ITemporalQuantityCollection<Q>) _item1; thisValue = (Measurable<Q>) tqc1.interpolateValue(time, InterpMethod.Linear); } else { if (!_item1.isTemporal() && _item1.getValuesCount() == 1) { thisValue = _item1.getValues().get(0); } else { throw new RuntimeException( "Can't use interpolation for non-singleton non-temporal"); } } if (_item2.isTemporal()) { ITemporalQuantityCollection<Q> tqc2 = (ITemporalQuantityCollection<Q>) _item2; otherValue = (Measurable<Q>) tqc2.interpolateValue(time, InterpMethod.Linear); } else { if (!_item2.isTemporal() && _item2.getValuesCount() == 1) { otherValue = _item2.getValues().get(0); } else { throw new RuntimeException( "Can't use interpolation for non-singleton non-temporal"); } } double thisD = 0; if (thisValue != null) { thisD = thisValue.doubleValue(_item1.getUnits()); } double otherD = 0; if (otherValue != null) { otherD = otherValue.doubleValue(_item2.getUnits()); } return thisD - otherD; } } }