/* * ARX: Powerful Data Anonymization * Copyright 2012 - 2017 Fabian Prasser, Florian Kohlmayer and contributors * * 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 org.deidentifier.arx.metric.v2; import org.deidentifier.arx.ARXConfiguration; import org.deidentifier.arx.DataDefinition; import org.deidentifier.arx.framework.check.groupify.HashGroupify; import org.deidentifier.arx.framework.check.groupify.HashGroupifyEntry; import org.deidentifier.arx.framework.data.Data; import org.deidentifier.arx.framework.data.DataManager; import org.deidentifier.arx.framework.data.GeneralizationHierarchy; import org.deidentifier.arx.framework.lattice.Transformation; import org.deidentifier.arx.metric.InformationLoss; import org.deidentifier.arx.metric.InformationLossWithBound; /** * This class provides an abstract skeleton for the implementation of metrics * that can either be precomputed or not. The decision is made at runtime depending * on data properties. * * @author Fabian Prasser * @author Florian Kohlmayer */ public abstract class AbstractMetricMultiDimensionalPotentiallyPrecomputed extends AbstractMetricMultiDimensional { /** SVUID. */ private static final long serialVersionUID = 7278544218893194559L; /** Is this instance precomputed. */ private boolean precomputed = false; /** The threshold. */ private final double threshold; /** The default metric. */ private AbstractMetricMultiDimensional defaultMetric; /** The precomputed variant. */ private AbstractMetricMultiDimensional precomputedMetric; /** * Creates a new instance. The precomputed variant will be used if * #distinctValues / #rows <= threshold for all quasi-identifiers. * @param defaultMetric * @param precomputedMetric * @param threshold */ AbstractMetricMultiDimensionalPotentiallyPrecomputed(AbstractMetricMultiDimensional defaultMetric, AbstractMetricMultiDimensional precomputedMetric, double threshold) { super(defaultMetric.isMonotonicWithGeneralization(), defaultMetric.isMonotonicWithSuppression(), false, defaultMetric.getAggregateFunction()); // Sanity checks if (defaultMetric.getAggregateFunction() != precomputedMetric.getAggregateFunction()) { throw new IllegalArgumentException("Aggregate function does not match"); } if (defaultMetric.isMonotonicWithSuppression() != precomputedMetric.isMonotonicWithSuppression()) { throw new IllegalArgumentException("Monotonicity does not match"); } if (defaultMetric.isMonotonicWithGeneralization() != precomputedMetric.isMonotonicWithGeneralization()) { throw new IllegalArgumentException("Monotonicity does not match"); } // Default is non-precomputed this.threshold = threshold; this.precomputed = false; this.defaultMetric = defaultMetric; this.precomputedMetric = precomputedMetric; } @Override public InformationLoss<?> createMaxInformationLoss() { if (precomputed) { return precomputedMetric.createMaxInformationLoss(); } else { return defaultMetric.createMaxInformationLoss(); } } @Override public InformationLoss<?> createMinInformationLoss() { if (precomputed) { return precomputedMetric.createMinInformationLoss(); } else { return defaultMetric.createMinInformationLoss(); } } @Override public AggregateFunction getAggregateFunction() { if (precomputed) { return precomputedMetric.getAggregateFunction(); } else { return defaultMetric.getAggregateFunction(); } } @Override public double getGeneralizationFactor() { return defaultMetric.getGeneralizationFactor(); } @Override public double getGeneralizationSuppressionFactor() { return defaultMetric.getGeneralizationSuppressionFactor(); } @Override public double getSuppressionFactor() { return defaultMetric.getSuppressionFactor(); } @Override public boolean isIndependent() { return precomputed ? precomputedMetric.isIndependent() : defaultMetric.isIndependent(); } @Override public boolean isPrecomputed() { return this.precomputed; } /** * Returns the default variant. * * @return */ protected AbstractMetricMultiDimensional getDefaultMetric(){ return this.defaultMetric; } @Override protected InformationLossWithBound<AbstractILMultiDimensional> getInformationLossInternal(Transformation node, HashGroupify groupify) { return precomputed ? precomputedMetric.getInformationLoss(node, groupify) : defaultMetric.getInformationLoss(node, groupify); } @Override protected InformationLossWithBound<AbstractILMultiDimensional> getInformationLossInternal(Transformation node, HashGroupifyEntry entry) { if (precomputed) { return precomputedMetric.getInformationLoss(node, entry); } else { return defaultMetric.getInformationLoss(node, entry); } } @Override protected AbstractILMultiDimensional getLowerBoundInternal(Transformation node) { return precomputed ? precomputedMetric.getLowerBound(node) : defaultMetric.getLowerBound(node); } @Override protected AbstractILMultiDimensional getLowerBoundInternal(Transformation node, HashGroupify groupify) { return precomputed ? precomputedMetric.getLowerBound(node, groupify) : defaultMetric.getLowerBound(node, groupify); } /** * Returns the precomputed variant. * * @return */ protected AbstractMetricMultiDimensional getPrecomputedMetric(){ return this.precomputedMetric; } /** * Returns the threshold. * * @return */ protected double getThreshold() { return this.threshold; } @Override protected void initializeInternal(final DataManager manager, final DataDefinition definition, final Data input, final GeneralizationHierarchy[] ahierarchies, final ARXConfiguration config) { this.precomputed = true; double rows = input.getDataLength(); for (GeneralizationHierarchy hierarchy : ahierarchies) { double share = (double)hierarchy.getDistinctValues()[0] / rows; if (share > threshold) { this.precomputed = false; break; } } if (precomputed) { precomputedMetric.initializeInternal(manager, definition, input, ahierarchies, config); } else { defaultMetric.initializeInternal(manager, definition, input, ahierarchies, config); } } }