/*******************************************************************************
* Copyright 2014 Felipe Takiyama
*
* 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 br.usp.poli.takiyama.prv;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import br.usp.poli.takiyama.common.Constraint;
/**
* Standard implementation of {@link LogicalVariable}.
*
* @author Felipe Takiyama
*
*/
public final class StdLogicalVariable implements LogicalVariable {
private final String name;
private final Population population;
/* ************************************************************************
* Constructors
* ************************************************************************/
/**
* Constructor. Creates a logical variable.
*
* @param name The name of the logical variable. The name must start with
* an upper case letter or underscore ("_").
* @param individuals The individuals that constitute the population of
* this logical variable
* @throws IllegalArgumentException If the name requirements are not met.
*/
// public StdLogicalVariable(String name, List<Constant> individuals) throws IllegalArgumentException {
// // The value of a logical variable is its name
// this.name = new String(name);
//
// // Population should be ordered.
// this.population = new Population(individuals);
//
// // Checks if the name of the variable is valid
// if (!name.startsWith("_") && !Character.isUpperCase(name.charAt(0))) {
// throw new IllegalArgumentException("Exception while creating " +
// "Logical Variable: '" + name + "' must start with " +
// "uppercase letter or underscore.");
// }
// }
/**
* Constructor. Creates a logical variable.
* @param name The name of the logical variable
* @param population The population of the logical variable. The new variable
* will have a copy of the population specified.
* @throws IllegalArgumentException If the name of the variable does not
* start with a upper case letter or underscore.
*/
private StdLogicalVariable(String name, Population population) throws IllegalArgumentException {
this.name = new String(name);
this.population = Population.getInstance(population);
if (!name.startsWith("_") && !Character.isUpperCase(name.charAt(0))) {
throw new IllegalArgumentException("Exception while creating " +
"Logical Variable: '" + name + "' must start with " +
"uppercase letter or underscore.");
}
}
/**
* Constructor. Creates a copy of the specified logical variable.
* @param lv The LogicalVariable to be copied.
*/
private StdLogicalVariable(LogicalVariable lv) {
name = lv.value();
population = lv.population();
}
/**
* Creates an empty LogicalVariable, with no name and empty population.
*/
private StdLogicalVariable() {
name = "";
population = Population.getInstance();
}
/* ************************************************************************
* Static factories
* ************************************************************************/
/**
* Returns a {@link StdLogicalVariable} with no name and
* empty population.
*
* @return An empty LogicalVariable
*/
public static LogicalVariable getInstance() {
return new StdLogicalVariable();
}
/**
* Returns a {@link StdLogicalVariable} with the same name and
* population as the specified logical variable.
*
* @param lv The logical variable to "copy"
* @return A "copy" of the specified logical variable
*/
public static LogicalVariable getInstance(LogicalVariable lv) {
return new StdLogicalVariable(lv);
}
/**
* Returns a {@link StdLogicalVariable} with the specified name and
* population.
*
* @param name The name of the logical variable
* @param pop The population associated with the logical variable
* @return A LogicalVariable with the specified attributes
*/
public static LogicalVariable getInstance(String name, Population pop) {
return new StdLogicalVariable(name, pop);
}
/**
* Returns a StdLogicalVariable with the specified name. Its population
* will have the specified size, and each individual is a {@link Constant}
* whose name is given by <code>prefix</code> + <code>index</code>.
* Index starts on 1.
*
* @param name THe name of the variable
* @param prefix Prefix of each individual in the population
* @param size The size of the population
* @return a StdLogicalVariable with the specified name and population size
*/
public static LogicalVariable getInstance(String name, String prefix,
int size) {
List<Constant> individuals = new ArrayList<Constant>(size);
for (int i = 1; i <= size; i++) {
individuals.add(Constant.getInstance(prefix + i));
}
Population population = Population.getInstance(individuals);
return new StdLogicalVariable(name, population);
}
/* ************************************************************************
* Inherited methods
* ************************************************************************/
@Override
public String value() {
return name;
}
@Override
public boolean isVariable() {
return true;
}
@Override
public boolean isConstant() {
return !isVariable();
}
@Override
public boolean isEmpty() {
return name.isEmpty() && (population.size() == 0);
}
/* ************************************************************************
* Getters
* ************************************************************************/
@Override
public Population population() {
return Population.getInstance(population);
}
@Override
public Population individualsSatisfying(Set<Constraint> constraints) {
// optimization - if there are no constraints there is no need to check
if (constraints.isEmpty()) {
return this.population;
}
Population pop = Population.getInstance(this.population);
for (Constant individual : population) {
Binding bind = Binding.getInstance(this, individual);
for (Constraint constraint : constraints) {
if (constraint.isUnary() && !constraint.isConsistentWith(bind)) {
pop.remove(individual);
break;
}
}
}
return pop;
}
@Override
public LogicalVariable rename(String newName) {
return new StdLogicalVariable(newName, this.population);
}
// public int sizeOfPopulationSatisfying(Set<Constraint> constraints) {
// HashSet<Constraint> consistentConstraints = new HashSet<Constraint> (constraints);
// for (Constraint constraint : consistentConstraints) {
// if (!constraint.contains(this)) {
// consistentConstraints.remove(constraint);
// }
// }
// return (this.population.size() - consistentConstraints.size());
// }
@Override
public Set<Term> excludedSet(Set<Constraint> constraints) {
Set<Term> excludedSet = new HashSet<Term>();
for (Constraint constraint : constraints) {
if (constraint.contains(this)) {
if (this.equals(constraint.firstTerm())) {
excludedSet.add(constraint.secondTerm());
} else {
excludedSet.add(constraint.firstTerm());
}
}
}
return excludedSet;
}
@Override
public int numberOfIndividualsSatisfying(Set<Constraint> constraints) {
int domainSize = population.size();
int excludedSetSize = excludedSet(constraints).size();
return domainSize - excludedSetSize;
}
/* ************************************************************************
* hashCode, equals and toString
* ************************************************************************/
@Override
public String toString() {
return this.name;
}
@Override
public boolean equals(Object other) {
// Tests if both refer to the same object
if (this == other)
return true;
// Tests if the Object is an instance of this class
if (!(other instanceof StdLogicalVariable))
return false;
// Tests if both have the same attributes
StdLogicalVariable targetObject = (StdLogicalVariable) other;
return this.name.equals(targetObject.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
}