Package de.timefinder.algo.constraint

Source Code of de.timefinder.algo.constraint.PersonITCRasterConstraint

/*
*  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.constraint;

import de.timefinder.data.algo.DataPoolSettings;
import de.timefinder.data.Event;
import de.timefinder.data.Person;
import de.timefinder.data.algo.Constraint;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

/**
* Very specific constraint taken from the requirements in the internat. timetabling comp.
*
* @author Peter Karich, peat_hal ‘at’ users ‘dot’ sourceforge ‘dot’ net
*/
public class PersonITCRasterConstraint extends Constraint {

    private static final long serialVersionUID = -3663434621373045628L;
    private Person person;
    private int dayDuration;
    private int weekLength;

    private PersonITCRasterConstraint() {
    }

    public PersonITCRasterConstraint(Person person, DataPoolSettings settings) {       
        this.person = person;
        dayDuration = settings.getTimeslotsPerDay();
        weekLength = settings.getTimeslotsPerWeek();
    }

    public int getDayDuration() {
        return dayDuration;
    }

    public void setDayDuration(int dayDuration) {
        this.dayDuration = dayDuration;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public int getWeekLength() {
        return weekLength;
    }

    public void setWeekLength(int weekLength) {
        this.weekLength = weekLength;
    }

    @Override
    public int getViolations(Object raster) {
        TreeMap<Integer, Event> map = (TreeMap<Integer, Event>) raster;
        return getSoftConstraintViolations(map, null);
    }

    public int getSoftConstraintViolations() {
        return getSoftConstraintViolations(createIndexRasterFromStartTimes(), null);
    }

    public int getSoftConstraintViolations(TreeMap<Integer, Event> treeMapRaster,
            Map<Event, Integer> problemMap) {

        return getSuccessiveViolation(treeMapRaster, problemMap)
                + getSingleViolation(treeMapRaster, problemMap)
                + getEndViolation(treeMapRaster, problemMap);
    }

    public int getSingleViolation() {
        return getSingleViolation(createIndexRasterFromStartTimes(), null);
    }

    /**
     * This method calculates one of the soft constraints specified in the ITC Track2.
     * A single Event on a day counts as a violation.
     */
    public int getSingleViolation(TreeMap<Integer, Event> treeMapRaster,
            Map<Event, Integer> problemMap) {
        int counter = 0;
        int currentDay;
        Integer newTime;
        Entry entry = treeMapRaster.ceilingEntry(0);

        while (entry != null) {
            int time = (Integer) entry.getKey();
            currentDay = time / dayDuration;
            newTime = treeMapRaster.higherKey(time);
            if (newTime == null) {
                counter++;
                increaseProblemCounter(problemMap, (Event) entry.getValue());
                break;
            } else if (newTime / dayDuration > currentDay) {

                counter++;
                increaseProblemCounter(problemMap, (Event) entry.getValue());
                //we want that time = newTime for the next iteration
                newTime--;
            } else {
                //there couldn't be a violation on currentDay (at least two ti's found)
                newTime = dayDuration * (currentDay + 1) - 1;
            }
            entry = treeMapRaster.higherEntry(newTime);
        }

        return counter;
    }

    public int getEndViolation() {
        return getEndViolation(createIndexRasterFromStartTimes(), null);
    }

    /**
     * This method calculates one of the soft constraints specified in the ITC Track2.
     * A Event at the end of a day counts as a violation.
     */
    public int getEndViolation(TreeMap raster, Map<Event, Integer> problemMap) {

        int counter = 0;
        int end = weekLength;
        Event ti;
        for (int i = dayDuration - 1; i < end; i += dayDuration) {
            ti = (Event) raster.get(i);
            if (ti != null) {
                counter++;
                increaseProblemCounter(problemMap, ti);
            }
        }
        return counter;
    }

    public int getSuccessiveViolation() {
        return getSuccessiveViolation(createIndexRasterFromStartTimes(), null);
    }

    /**
     * This method calculates one of the soft constraints specified in the ITC Track2.
     * So n Event's (where n = 2 or more) which follows each other
     * directly and are on the same day will be violations. They call them
     * 'successive'.
     */
    public int getSuccessiveViolation(TreeMap raster, Map<Event, Integer> problemMap) {
        int counter = 0;
        int lastTime = 0;
        List<Event> allTIs = new ArrayList<Event>(5);
        for (Object o : raster.entrySet()) {
            Entry entry = (Entry) o;
            int time = (Integer) entry.getKey();
            if (time / dayDuration == lastTime / dayDuration
                    && time - lastTime < 2) {
                // Event with 'time' could be involved in a violation
                lastTime = time;
                allTIs.add((Event) entry.getValue());
                continue;
            }

            // Next day or 'time' is not a consecutive to 'lastTime'
            if (allTIs.size() > 2) {
                counter += allTIs.size() - 2;
                increaseProblemCounter(problemMap, allTIs);
            }

            // Now Event with 'time' could be involved in a violation, too!
            lastTime = time;
            allTIs.clear();
            allTIs.add((Event) entry.getValue());
        }

        if (allTIs.size() > 2) {
            counter += allTIs.size() - 2;
            increaseProblemCounter(problemMap, allTIs);
        }

        return counter;
    }

    private void increaseProblemCounter(Map<Event, Integer> problemMap, List<Event> allEvs) {
        if (problemMap != null) {
            for (Event ti : allEvs) {
                Integer i = problemMap.get(ti);
                assert i != null : allEvs + " map:" + problemMap;
                problemMap.put(ti, i + 1);
            }
        }
    }

    private void increaseProblemCounter(Map<Event, Integer> problemMap, Event event) {
        if (problemMap != null) {
            Integer i = problemMap.get(event);
            assert i != null : event + " map:" + problemMap;
            problemMap.put(event, i + 1);
        }
    }

    private TreeMap<Integer, Event> createIndexRasterFromStartTimes() {
        TreeMap<Integer, Event> indexRaster = new TreeMap<Integer, Event>();
        for (Event ev : person.getEvents()) {
            if (ev.getStart() >= 0)
                indexRaster.put(ev.getStart(), ev);
        }
        return indexRaster;
    }
}
TOP

Related Classes of de.timefinder.algo.constraint.PersonITCRasterConstraint

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.