/*
* Copyright 2015 by Thomas Lottermann
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package notaql.evaluation;
import notaql.datamodel.AtomValue;
import notaql.datamodel.Value;
import notaql.datamodel.fixation.Fixation;
import notaql.evaluation.values.PartialAtomValue;
import notaql.evaluation.values.PartialNullValue;
import notaql.model.EvaluationException;
import notaql.model.vdata.VData;
import notaql.model.vdata.aggregation.ExtremumVData;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Executes MIN and MAX functions
*/
public class ExtremumVDataEvaluator implements Evaluator, Reducer {
private static final long serialVersionUID = -8211952015804397201L;
@Override
public List<ValueEvaluationResult> evaluate(VData vData, Fixation fixation) {
assert vData instanceof ExtremumVData;
final ExtremumVData extremumVData = (ExtremumVData) vData;
final VData path = extremumVData.getExpression();
final List<ValueEvaluationResult> results = EvaluatorService.getInstance().evaluate(path, fixation);
final List<Value> values = results.stream().map(ValueEvaluationResult::getValue).collect(Collectors.toList());
if (values
.stream()
.anyMatch(v -> !(v instanceof AtomValue) || !(((AtomValue) v).getValue() instanceof Comparable))
)
throw new EvaluationException(extremumVData.getFunction() + " aggregation function encountered values which are not comparable.");
final Stream<AtomValue> atomValueStream = values.stream().map(v -> (AtomValue) v);
final Optional<AtomValue> extremum;
switch (extremumVData.getFunction()) {
case MIN:
extremum = atomValueStream.min(new ExtremumVData.AtomValueComparator());
break;
case MAX:
extremum = atomValueStream.max(new ExtremumVData.AtomValueComparator());
break;
default:
extremum = null;
assert false: "Unknown extremum operator: " + extremumVData.getFunction().toString();
}
if (extremum.isPresent())
return Arrays.asList(new ValueEvaluationResult(new PartialAtomValue<>(extremum.get()), fixation));
return Arrays.asList(new ValueEvaluationResult(new PartialNullValue(), fixation));
}
@Override
public boolean canReduce(VData vData) {
return true;
}
@Override
public Value reduce(VData vData, Value v1, Value v2) {
assert vData instanceof ExtremumVData;
if(v1 instanceof PartialNullValue)
return v2;
if(v2 instanceof PartialNullValue)
return v1;
assert v1 instanceof PartialAtomValue && v2 instanceof PartialAtomValue;
final PartialAtomValue pv1 = (PartialAtomValue) v1;
final PartialAtomValue pv2 = (PartialAtomValue) v2;
final ExtremumVData extremumVData = (ExtremumVData) vData;
final int compare = new ExtremumVData.AtomValueComparator().compare(pv1, pv2);
switch (extremumVData.getFunction()) {
case MIN:
if(compare >= 0)
return pv2;
return pv1;
case MAX:
if(compare >= 0)
return pv1;
return pv2;
default:
throw new AssertionError("Unknown extremum operator: " + extremumVData.getFunction().toString());
}
}
@Override
public Value createIdentity(VData vData) {
return new PartialNullValue();
}
@Override
public Value finalize(VData vData, Value value) {
assert value instanceof PartialAtomValue;
return ((PartialAtomValue)value).getSource();
}
@Override
public List<Class<? extends VData>> getProcessedClasses() {
return Arrays.asList(ExtremumVData.class);
}
}