/*******************************************************************************
* Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
* Copyright (c) 2023 The Refinery Authors
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-v20.html.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package tools.refinery.store.dse.objectives;
import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
import java.util.Comparator;
import java.util.Objects;
/**
* This abstract class implements the basic functionality of an objective ({@link Objective} namely its name,
* comparator, level and fitness hard constraint.
*
* @author Andras Szabolcs Nagy
*
*/
public abstract class BaseObjective implements Objective {
protected final String name;
protected Comparator comparator = Comparators.HIGHER_IS_BETTER;
protected double fitnessConstraint;
protected boolean isThereFitnessConstraint = false;
protected Comparator fitnessConstraintComparator;
protected BaseObjective(String name) {
Objects.requireNonNull(name, "Name of the objective cannot be null.");
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void setComparator(Comparator comparator) {
this.comparator = comparator;
}
@Override
public Comparator getComparator() {
return comparator;
}
public BaseObjective withComparator(Comparator comparator) {
setComparator(comparator);
return this;
}
/**
* Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the
* current state as a solution.
*
* @param fitnessConstraint
* Solutions should be better than this value.
* @param fitnessConstraintComparator
* {@link Comparator} to determine if the current state is better than the given value.
* @return The actual instance to enable builder pattern like usage.
*/
public BaseObjective withHardConstraintOnFitness(double fitnessConstraint,
Comparator fitnessConstraintComparator) {
this.fitnessConstraint = fitnessConstraint;
this.fitnessConstraintComparator = fitnessConstraintComparator;
this.isThereFitnessConstraint = true;
return this;
}
/**
* Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the
* current state as a solution. The provided comparator will be used.
*
* @param fitnessConstraint
* Solutions should be better than this value.
* @return The actual instance to enable builder pattern like usage.
*/
public BaseObjective withHardConstraintOnFitness(double fitnessConstraint) {
return withHardConstraintOnFitness(fitnessConstraint, null);
}
@Override
public void init(DesignSpaceExplorationAdapter context) {
if (fitnessConstraintComparator == null) {
fitnessConstraintComparator = comparator;
}
}
@Override
public boolean isHardObjective() {
return isThereFitnessConstraint;
}
@Override
public boolean satisfiesHardObjective(Double fitness) {
if (isThereFitnessConstraint) {
int compare = fitnessConstraintComparator.compare(fitness, fitnessConstraint);
if (compare < 0) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof BaseObjective baseObjective) {
return name.equals(baseObjective.getName());
}
return false;
}
@Override
public String toString() {
return name;
}
}