All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jamesframework.core.problems.SubsetProblemWithData Maven / Gradle / Ivy

Go to download

The James core module is part of the James framework for optimization using local search metaheuristics in Java. The core contains general components to model problems, objectives and constraints, as well as generic algorithms to solve the problems. Moreover, the core provides implementations of specific utilities for subset selection.

There is a newer version: 1.2
Show newest version
//  Copyright 2014 Herman De Beukelaer
//
//  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.jamesframework.core.problems;

import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import org.jamesframework.core.problems.datatypes.SubsetData;
import org.jamesframework.core.problems.objectives.Objective;
import org.jamesframework.core.problems.solutions.SubsetSolution;
import org.jamesframework.core.util.SetUtilities;

/**
 * Represents a subset problem with data of a given data type, implementing the interface {@link SubsetData}, and with solution
 * type {@link SubsetSolution}. The minimum and maximum allowed subset size are specified in the subset problem, and subset solutions
 * with a size outside these bounds are rejected. The problem also provides methods for creating random subset solutions and copying
 * subset solutions (see {@link Problem} interface), as well as an additional method for creating empty subset solutions in which no
 * entities are selected.
 * 
 * @param  underlying data type, should implement the interface {@link SubsetData}
 * @author Herman De Beukelaer
 */
public class SubsetProblemWithData extends ProblemWithData
                                                                implements SubsetProblem {

    // minimum and maximum subset size
    private int minSubsetSize, maxSubsetSize;
    
    // indicates whether IDs in the created/copied subset solutions should be sorted
    private final boolean sortedIDs;
    
    /**
     * Creates a new subset problem with given objective, data and minimum/maximum subset size. Both objective
     * and data are not allowed to be null, an exception will be thrown if they are. Any objective
     * designed to evaluate subset solutions (or more general solutions) using the specified data type (or more general data)
     * is accepted. The minimum and maximum subset size should be contained in [0,n] where n
     * is the number of entities in the given subset data from which a subset is to be selected. Also, the minimum size
     * should be smaller than or equal to the maximum size. If sortedIDs is true, any subset
     * solution generated by this problem (random, copy, ...) will store the underlying IDs in sorted sets.
     * 
     * @param objective objective function, can not be null
     * @param data underlying subset data, can not be null
     * @param minSubsetSize minimum subset size (should be ≥ 0 and ≤ maximum subset size)
     * @param maxSubsetSize maximum subset size (should be ≥ minimum subset size and ≤ number of entities in underlying data)
     * @param sortedIDs indicates whether IDs are sorted in generated subset solutions
     * 
     * @throws NullPointerException if objective or data is null
     * @throws IllegalArgumentException if an invalid minimum or maximum subset size is specified
     */
    public SubsetProblemWithData(Objective objective,
                                DataType data, int minSubsetSize, int maxSubsetSize, boolean sortedIDs) {
        // call constructor of ProblemWithData (already checks that objective is not null)
        super(objective, data);
        // check that data is not null
        if(data == null){
            throw new NullPointerException("Error while creating subset problem: subset data is required, can not be null.");
        }
        // check constraints on minimum/maximum size
        if(minSubsetSize < 0){
            throw new IllegalArgumentException("Error while creating subset problem: minimum subset size should be >= 0.");
        }
        if(maxSubsetSize > data.getIDs().size()){
            throw new IllegalArgumentException("Error while creating subset problem: maximum subset size can not be larger "
                                                + "than number of entities in underlying subset data.");
        }
        if(minSubsetSize > maxSubsetSize){
            throw new IllegalArgumentException("Error while creating subset problem: minimum subset size should be <= maximum subset size.");
        }
        // store min/max size
        this.minSubsetSize = minSubsetSize;
        this.maxSubsetSize = maxSubsetSize;
        // store sorted
        this.sortedIDs = sortedIDs;
    }
    
    /**
     * Creates a new subset problem with given objective, data and minimum/maximum subset size. Both objective
     * and data are not allowed to be null, an exception will be thrown if they are. Any objective
     * designed to evaluate subset solutions (or more general solutions) using the specified data type (or more general data)
     * is accepted. The minimum and maximum subset size should be contained in [0,n] where n
     * is the number of entities in the given subset data from which a subset is to be selected. Also, the minimum size
     * should be smaller than or equal to the maximum size. Generated subset solutions do not guarantee any order of IDs.
     * 
     * @param objective objective function, can not be null
     * @param data underlying subset data, can not be null
     * @param minSubsetSize minimum subset size (should be ≥ 0 and ≤ maximum subset size)
     * @param maxSubsetSize maximum subset size (should be ≥ minimum subset size and ≤ number of entities in underlying data)
     * @throws NullPointerException if objective or data is null
     * @throws IllegalArgumentException if an invalid minimum or maximum subset size is specified
     */
    public SubsetProblemWithData(Objective objective,
                                DataType data, int minSubsetSize, int maxSubsetSize) {
        this(objective, data, minSubsetSize, maxSubsetSize, false);
    }
    
    /**
     * Creates a subset problem with fixed subset size. Equivalent to calling
     * SubsetProblem p = new SubsetProblem(objective, data, fixedSubsetSize, fixedSubsetSize);
* The fixed subset size should be contained in [0,n] where n * is the number of entities in the given subset data from which a subset is to be selected. * Generated subset solutions do not guarantee any order of IDs. * * @param objective objective function, can not be null * @param data underlying subset data, can not be null * @param fixedSubsetSize fixed subset size * @throws NullPointerException if objective or data is null * @throws IllegalArgumentException if an invalid fixed subset size is specified */ public SubsetProblemWithData(Objective objective, DataType data, int fixedSubsetSize) { this(objective, data, fixedSubsetSize, fixedSubsetSize); } /** * Set new subset data, verifying that the data is not null. * * @param data new subset data, can not be null * @throws NullPointerException if data is null */ @Override public void setData(DataType data) { // check not null if(data == null){ throw new NullPointerException("Error while setting data in subset problem: subset data can not be null."); } // not null: call super super.setData(data); } /** * Create a random solution within the allowed minimum and maximum subset size. The IDs of all entities are taken from the * underlying subset data, and a random subset of IDs is selected. * * @return random subset solution within minimum and maximum size */ @Override public SubsetSolution createRandomSolution() { // get thread local random generator final Random rg = ThreadLocalRandom.current(); // create new subset solution with IDs from underlying data final SubsetSolution sol = new SubsetSolution(getData().getIDs(), sortedIDs); // pick random number of initially selected IDs within bounds int size = minSubsetSize + rg.nextInt(maxSubsetSize-minSubsetSize+1); // randomly select initial IDs sol.selectAll(SetUtilities.getRandomSubset(sol.getAllIDs(), size, rg)); // return random solution return sol; } /** * Creates an empty subset solution containing the IDs of the underlying data, where none of these IDs are selected. * * @return empty subset solution with no selected IDs */ @Override public SubsetSolution createEmptySubsetSolution(){ return new SubsetSolution(getData().getIDs(), sortedIDs); } /** * Checks whether the given subset solution is rejected. A subset solution is rejected if any of the rejecting constraints is * violated (see {@link #addRejectingConstraint(Constraint)}) or if it has an invalid size (number of selected IDs). * * @param solution subset solution to verify * @return true if the solution is rejected */ @Override public boolean rejectSolution(SubsetSolution solution){ return rejectSolution(solution, true); } /** * Checks whether the given subset solution is rejected. A subset solution is rejected if any of the rejecting constraints is * violated (see {@link #addRejectingConstraint(Constraint)}). Also, if checkSubsetSize is true, * the solution is rejected if it has an invalid size. * * @param solution subset solution to verify * @param checkSubsetSize indicates whether a solution should be rejected if it has an invalid size * @return true if the solution is rejected */ @Override public boolean rejectSolution(SubsetSolution solution, boolean checkSubsetSize){ if(checkSubsetSize){ return solution.getNumSelectedIDs() < getMinSubsetSize() // too small || solution.getNumSelectedIDs() > getMaxSubsetSize() // too large || super.rejectSolution(solution); // violates rejecting constraint } else { // ignore size return super.rejectSolution(solution); } } /** * Get the minimum subset size. * * @return minimum subset size */ @Override public int getMinSubsetSize() { return minSubsetSize; } /** * Set the minimum subset size. Specified size should be ≥ 1 and ≤ the current maximum subset size. * * @param minSubsetSize new minimum subset size * @throws IllegalArgumentException if an invalid minimum size is given */ public void setMinSubsetSize(int minSubsetSize) { // check size if(minSubsetSize <= 0){ throw new IllegalArgumentException("Error while setting minimum subset size: should be > 0."); } if(minSubsetSize > maxSubsetSize){ throw new IllegalArgumentException("Error while setting minimum subset size: should be <= maximum subset size."); } this.minSubsetSize = minSubsetSize; } /** * Get the maximum subset size. * * @return maximum subset size */ @Override public int getMaxSubsetSize() { return maxSubsetSize; } /** * Set the maximum subset size. Specified size should be ≥ the current minimum subset size * and ≤ the number of entities in the underlying subset data. * * @param maxSubsetSize new maximum subset size * @throws IllegalArgumentException if an invalid maximum size is given */ public void setMaxSubsetSize(int maxSubsetSize) { // check size if(maxSubsetSize < minSubsetSize){ throw new IllegalArgumentException("Error while setting maximum subset size: should be >= minimum subset size."); } if(maxSubsetSize > getData().getIDs().size()){ throw new IllegalArgumentException("Error while setting maximum subset size: can not be larger " + "than number of entities in underlying subset data."); } this.maxSubsetSize = maxSubsetSize; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy