/*
* Copyright 2009 Peter Karich, peat_hal 'at' users 'dot' sourceforge 'dot' net.
*
* 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.
* under the License.
*/
package de.timefinder.algo.ncp;
import de.timefinder.algo.constraint.EventITCConstraintHelper;
import de.timefinder.algo.constraint.PersonITCRasterConstraint;
import de.timefinder.algo.constraint.RasterConstraint;
import de.timefinder.data.Event;
import de.timefinder.data.Person;
import de.timefinder.data.Resource;
import de.timefinder.data.algo.Assignment;
import de.timefinder.data.algo.Solution;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
/**
* @author Peter Karich, peat_hal 'at' users 'dot' sourceforge 'dot' net
*/
public class ConstraintChecker {
private final static Logger logger = Logger.getLogger(ConstraintChecker.class.getSimpleName());
private final static EventITCConstraintHelper helper = new EventITCConstraintHelper();
private final static String ORDERING_COLLISIONS = "No of ordering problems:";
private final static String EVENT_IN_PERSON_COLLISIONS = "No of person collisions:";
private final static String EVENT_IN_LOCATION_COLLISIONS = "No of location collisions:";
/**
* At the moment this method lists only the constraint violations of the
* specified solution.
* (No exception or sth. else)
*/
public static void printStatistics(Solution solution) {
printStatistics(solution, false);
}
public static void printStatistics(Solution solution, boolean throwException) {
int noOfOrderingProblems = 0;
int noOfUnplacedTIs = 0;
int distanceToFeasibility = 0;
int personConflicts = 0;
int locationConflicts = 0;
int assignedEvents = 0;
boolean moreDetails = false;
if (moreDetails) {
logger.info("----------------------------");
logger.info("Event with raster collisions:");
for (Assignment ass : solution.getAssignments()) {
int no = ass.getEvent().getConstraint(RasterConstraint.class).getViolations(ass);
if (no > 0) {
logger.info("Rasterviolations:" + ass + ":" + no);
}
}
logger.info("----------------------------");
logger.info("Unsatisfied features of following Event's:");
for (Assignment ass : solution.getAssignments()) {
int no = helper.getFeatureViolations(ass);
//featureViolations+=no;
if (no > 0) {
logger.info("feature violation:" + ass + ":" + no);
}
}
logger.info("----------------------------");
logger.info("Unsatisfied Ordering of following Event's:");
}
for (Assignment ass : solution.getAssignments()) {
if (ass.getStart() < 0) {
noOfUnplacedTIs++;
distanceToFeasibility += ass.getEvent().getPersonsMap().size();
} else {
assignedEvents++;
if (ass.getLocation() == null)
throw new NullPointerException("location of " + ass + " is null!");
int no = helper.getOrderViolations(ass.getEvent(), solution);
if (no > 0) {
noOfOrderingProblems++;
}
}
}
if (moreDetails) {
logger.info("----------------------------");
logger.info("Following Person's have >3 Event's in one day:");
}
int moreThan2 = 0;
Collection<Person> allPersons = solution.generateAllInvolvedPersons();
for (Person p : allPersons) {
if (p.getConstraint(PersonITCRasterConstraint.class) == null)
continue;
int counter = p.getConstraint(PersonITCRasterConstraint.class).getSuccessiveViolation();
if (counter > 0) {
if (moreDetails) {
logger.info(p + " has successive violation: " + counter);
}
moreThan2 += counter;
}
}
if (moreDetails) {
logger.info("----------------------------");
logger.info("Following Person's have a single Event in one day:");
}
int onlyOne = 0;
for (Person p : allPersons) {
if (p.getConstraint(PersonITCRasterConstraint.class) == null)
continue;
int counter = p.getConstraint(PersonITCRasterConstraint.class).getSingleViolation();
if (counter > 0) {
if (moreDetails) {
logger.info(p + " has only a single event: " + counter);
}
onlyOne += counter;
}
}
if (moreDetails) {
logger.info("----------------------------");
logger.info("Following Person's have Event at the end of a day:");
}
int atTheEnd = 0;
for (Person p : allPersons) {
if (p.getConstraint(PersonITCRasterConstraint.class) == null)
continue;
int counter = p.getConstraint(PersonITCRasterConstraint.class).getEndViolation();
if (counter > 0) {
if (moreDetails) {
logger.info(p + " has an event at the end: " + counter);
}
atTheEnd += counter;
}
}
personConflicts = countConflictsForResources(solution, allPersons, false);
locationConflicts = countConflictsForResources(solution, solution.generateAllInvolvedLocations(), throwException);
if (!throwException) {
logger.info(ORDERING_COLLISIONS + noOfOrderingProblems);
logger.info(EVENT_IN_PERSON_COLLISIONS + personConflicts);
logger.info(EVENT_IN_LOCATION_COLLISIONS + locationConflicts);
logger.info("assigned events:" + assignedEvents);
logger.info("### No of unplaced events:" + noOfUnplacedTIs +
" out of:" + solution.getAssignments().size() + " => " +
(float) 100 * noOfUnplacedTIs / solution.getAssignments().size() +
" % are unplaced ###");
logger.info("Distance to a feasibility solution:" + distanceToFeasibility);
logger.info("Penalty for students having three or more events in a row:" + moreThan2);
logger.info("Penalty for students having single events on a day:" + onlyOne);
logger.info("Penalty for students having end of day events:" + atTheEnd);
logger.info("Total soft constraint penalty:" + (onlyOne + atTheEnd + moreThan2));
}
}
private static int countConflictsForResources(Solution sol,
Collection<? extends Resource> resources, boolean throwExc) {
int counter = 0;
for (Resource res : resources) {
List<Event> events = new ArrayList(res.getEvents());
for (int i = 0; i < events.size(); i++) {
Event ev1 = events.get(i);
if (sol.isEventAssigned(ev1))
for (int j = i + 1; j < events.size(); j++) {
Event ev2 = events.get(j);
if (sol.isEventAssigned(ev2) && ev1.overlapps(ev2))
if (throwExc)
throw new IllegalStateException("conflicting events in resource " +
res + " ev1:" + ev1 + " " + ev1.getLocation() + " ev2:" + ev2 + " " + ev2.getLocation());
else
counter++;
}
}
}
return counter;
}
}