/*
* 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.algorithm;
import org.deidentifier.arx.ARXListener;
import org.deidentifier.arx.ARXConfiguration.Monotonicity;
import org.deidentifier.arx.framework.check.NodeChecker;
import org.deidentifier.arx.framework.check.groupify.HashGroupify;
import org.deidentifier.arx.framework.lattice.SolutionSpace;
import org.deidentifier.arx.framework.lattice.Transformation;
import org.deidentifier.arx.metric.InformationLoss;
import org.deidentifier.arx.metric.InformationLossWithBound;
/**
* Abstract class for an algorithm, which provides some generic methods.
*
* @author Fabian Prasser
* @author Florian Kohlmayer
*/
public abstract class AbstractAlgorithm {
/** The optimal transformation. */
private Transformation globalOptimum = null;
/** The optimal information loss. */
private InformationLoss<?> optimalInformationLoss = null;
/** The listener */
private ARXListener listener = null;
/** A node checker. */
protected NodeChecker checker = null;
/** The lattice. */
protected SolutionSpace solutionSpace = null;
/**
* Walks the lattice.
*
* @param solutionSpace The solution space
* @param checker The checker
*/
protected AbstractAlgorithm(final SolutionSpace solutionSpace,
final NodeChecker checker) {
this.checker = checker;
this.solutionSpace = solutionSpace;
}
/**
* Returns the global optimum.
*
* @return
*/
public Transformation getGlobalOptimum() {
return globalOptimum;
}
/**
* Sets a listener
* @param listener
*/
public void setListener(ARXListener listener) {
this.listener = listener;
}
/**
* Implement this method in order to provide a new algorithm.
*/
public abstract void traverse();
/**
* Determine information loss of the given node if it can be
* used for estimating minimum and maximum information
* loss for tagged nodes.
*
* @param transformation
*/
protected void computeUtilityForMonotonicMetrics(Transformation transformation) {
if (checker.getConfiguration().getMonotonicityOfUtility() == Monotonicity.FULL &&
transformation.getInformationLoss() == null) {
// Independent evaluation or check
if (checker.getMetric().isIndependent()) {
InformationLossWithBound<?> loss = checker.getMetric().getInformationLoss(transformation, (HashGroupify)null);
transformation.setInformationLoss(loss.getInformationLoss());
transformation.setLowerBound(loss.getLowerBound());
} else {
transformation.setChecked(checker.check(transformation, true));
}
}
}
/**
* Propagate progress to listeners
* @param progress
*/
protected void progress(double progress) {
if (this.listener != null) {
this.listener.progress(progress);
}
}
/**
* Keeps track of the global optimum.
*
* @param transformation
*/
protected void trackOptimum(Transformation transformation) {
if (transformation.hasProperty(solutionSpace.getPropertyAnonymous()) &&
((globalOptimum == null) ||
(transformation.getInformationLoss().compareTo(optimalInformationLoss) < 0) ||
((transformation.getInformationLoss().compareTo(optimalInformationLoss) == 0) && (transformation.getLevel() < globalOptimum.getLevel())))) {
globalOptimum = transformation;
optimalInformationLoss = transformation.getInformationLoss();
}
}
}