/* * Copyright (C) 2015 SoftIndex LLC. * * 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 io.datakernel.cube; import io.datakernel.aggregation.measure.Measure; import io.datakernel.codegen.Expression; import io.datakernel.codegen.Expressions; import io.datakernel.codegen.utils.Primitives; import java.util.*; import static com.google.common.collect.Lists.newArrayList; import static io.datakernel.codegen.Expressions.*; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; public final class ComputedMeasures { private ComputedMeasures() { } public static abstract class AbstractComputedMeasure implements ComputedMeasure { protected Set<ComputedMeasure> dependencies; public AbstractComputedMeasure(ComputedMeasure... dependencies) { this.dependencies = new LinkedHashSet<>(Arrays.asList(dependencies)); } @Override public Class<?> getType(Map<String, Measure> storedMeasures) { return null; } @Override public final Set<String> getMeasureDependencies() { Set<String> result = new LinkedHashSet<>(); for (ComputedMeasure dependency : dependencies) { result.addAll(dependency.getMeasureDependencies()); } return result; } } private static abstract class AbstractArithmeticMeasure extends AbstractComputedMeasure { public AbstractArithmeticMeasure(ComputedMeasure... dependencies) { super(dependencies); } @Override public final Class<?> getType(Map<String, Measure> storedMeasures) { List<Class<?>> types = newArrayList(); for (ComputedMeasure dependency : dependencies) { types.add(dependency.getType(storedMeasures)); } return Expressions.unifyArithmeticTypes(types); } } public static ComputedMeasure value(final Object value) { return new ComputedMeasure() { @Override public Class<?> getType(Map<String, Measure> storedMeasures) { return Primitives.unwrap(value.getClass()); } @Override public Expression getExpression(Expression record, Map<String, Measure> storedMeasures) { return Expressions.value(value); } @Override public Set<String> getMeasureDependencies() { return emptySet(); } }; } public static ComputedMeasure measure(final String measureId) { return new ComputedMeasure() { @Override public Class<?> getType(Map<String, Measure> storedMeasures) { return (Class<?>) storedMeasures.get(measureId).getFieldType().getDataType(); } @Override public Expression getExpression(Expression record, Map<String, Measure> storedMeasures) { return storedMeasures.get(measureId).valueOfAccumulator(field(record, measureId)); } @Override public Set<String> getMeasureDependencies() { return singleton(measureId); } }; } public static ComputedMeasure add(final ComputedMeasure measure1, final ComputedMeasure measure2) { return new AbstractArithmeticMeasure(measure1, measure2) { @Override public Expression getExpression(Expression record, Map<String, Measure> storedMeasures) { return Expressions.add(measure1.getExpression(record, storedMeasures), measure2.getExpression(record, storedMeasures)); } }; } public static ComputedMeasure sub(final ComputedMeasure measure1, final ComputedMeasure measure2) { return new AbstractArithmeticMeasure(measure1, measure2) { @Override public Expression getExpression(Expression record, Map<String, Measure> storedMeasures) { return Expressions.sub(measure1.getExpression(record, storedMeasures), measure2.getExpression(record, storedMeasures)); } }; } public static ComputedMeasure div(final ComputedMeasure measure1, final ComputedMeasure measure2) { return new AbstractComputedMeasure(measure1, measure2) { @Override public Class<?> getType(Map<String, Measure> storedMeasures) { return double.class; } @Override public Expression getExpression(Expression record, Map<String, Measure> storedMeasures) { Expression value2 = cast(measure2.getExpression(record, storedMeasures), double.class); return Expressions.ifThenElse(Expressions.cmpNe(value2, Expressions.value(0.0)), Expressions.div(measure1.getExpression(record, storedMeasures), value2), Expressions.value(0.0)); } }; } public static ComputedMeasure mul(final ComputedMeasure measure1, final ComputedMeasure measure2) { return new AbstractArithmeticMeasure(measure1, measure2) { @Override public Expression getExpression(Expression record, Map<String, Measure> storedMeasures) { return Expressions.mul(measure1.getExpression(record, storedMeasures), measure2.getExpression(record, storedMeasures)); } }; } public static ComputedMeasure sqrt(final ComputedMeasure measure) { return new AbstractComputedMeasure(measure) { @Override public Class<?> getType(Map<String, Measure> storedMeasures) { return double.class; } @Override public Expression getExpression(Expression record, Map<String, Measure> storedMeasures) { Expression value = let(cast(measure.getExpression(record, storedMeasures), double.class)); return ifThenElse(cmpLe(value, Expressions.value(0.0d)), Expressions.value(0.0d), callStatic(Math.class, "sqrt", value)); } }; } public static ComputedMeasure sqr(final ComputedMeasure measure) { return new AbstractComputedMeasure(measure) { @Override public Class<?> getType(Map<String, Measure> storedMeasures) { return double.class; } @Override public Expression getExpression(Expression record, Map<String, Measure> storedMeasures) { Expression value = let(cast(measure.getExpression(record, storedMeasures), double.class)); return Expressions.mul(value, value); } }; } public static ComputedMeasure stddev(ComputedMeasure sum, ComputedMeasure sumOfSquares, ComputedMeasure count) { return sqrt(variance(sum, sumOfSquares, count)); } public static ComputedMeasure variance(ComputedMeasure sum, ComputedMeasure sumOfSquares, ComputedMeasure count) { return sub(div(sumOfSquares, count), sqr(div(sum, count))); } public static ComputedMeasure percent(ComputedMeasure measure) { return mul(measure, value(100)); } public static ComputedMeasure percent(ComputedMeasure numerator, ComputedMeasure denominator) { return mul(div(numerator, denominator), value(100)); } }